# Lambda School Data Science Module 132
## Sampling, Confidence Intervals, and Hypothesis Testing

## Prepare - examine other available hypothesis tests

If you had to pick a single hypothesis test in your toolbox, t-test would probably be the best choice - but the good news is you don't have to pick just one! Here's some of the others to be aware of:

```
import numpy as np
from scipy.stats import chisquare  # One-way chi square test

# Chi square can take any crosstab/table and test the independence of rows/cols
# The null hypothesis is that the rows/cols are independent -> low chi square
# The alternative is that there is a dependence -> high chi square
# Be aware! Chi square does *not* tell you direction/causation

ind_obs = np.array([[1, 1], [2, 2]]).T
print(ind_obs)
print(chisquare(ind_obs, axis=None))

dep_obs = np.array([[16, 18, 16, 14, 12, 12], [32, 24, 16, 28, 20, 24]]).T
print(dep_obs)
print(chisquare(dep_obs, axis=None))
```

    [[1 2]
     [1 2]]
    Power_divergenceResult(statistic=0.6666666666666666, pvalue=0.8810148425137847)
    [[16 32]
     [18 24]
     [16 16]
     [14 28]
     [12 20]
     [12 24]]
    Power_divergenceResult(statistic=23.31034482758621, pvalue=0.015975692534127565)

```
# Distribution tests:
# We often assume that something is normal, but it can be important to *check*

# For example, later on with predictive modeling, a typical assumption is that
# residuals (prediction errors) are normal - checking is a good diagnostic

from scipy.stats import normaltest
# Poisson models arrival times and is related to the binomial (coinflip)
sample = np.random.poisson(5, 1000)
print(normaltest(sample))  # Pretty clearly not normal
```

    NormaltestResult(statistic=46.24179655519528, pvalue=9.093298788095795e-11)

```
# Kruskal-Wallis H-test - compare the median rank between 2+ groups
# Can be applied to ranking decisions/outcomes/recommendations
# The underlying math comes from chi-square distribution, and is best for n>5
from scipy.stats import kruskal

x1 = [1, 3, 5, 7, 9]
y1 = [2, 4, 6, 8, 10]
print(kruskal(x1, y1))  # x1 is a little better, but not "significantly" so

x2 = [1, 1, 1]
y2 = [2, 2, 2]
z = [2, 2]  # Hey, a third group, and of different size!
print(kruskal(x2, y2, z))  # x clearly dominates
```

    KruskalResult(statistic=0.2727272727272734, pvalue=0.6015081344405895)
    KruskalResult(statistic=7.0, pvalue=0.0301973834223185)

And there's many more! `scipy.stats` is fairly comprehensive, though there are even more available if you delve into the extended world of statistics packages. As tests get increasingly obscure and specialized, the importance of knowing them by heart becomes small - but being able to look them up and figure them out when they *are* relevant is still important.

## T-test Assumptions

<https://statistics.laerd.com/statistical-guides/independent-t-test-statistical-guide.php>

- Independence of means

Are the means of our voting data independent (do not affect the outcome of one another)?

The best way to increase thel likelihood of our means being independent is to randomly sample (which we did not do).

```
from scipy.stats import ttest_ind

?ttest_ind
```

- "Homogeneity" of Variance?

Is the magnitude of the variance between the two roughly the same?

I think we're OK on this one for the voting data, although it probably could be better, one party was larger than the other.

If we suspect this to be a problem then we can use Welch's T-test

```
?ttest_ind
```

- "Dependent Variable" (sample means) are Distributed Normally

<https://stats.stackexchange.com/questions/9573/t-test-for-non-normal-when-n50>

Lots of statistical tests depend on normal distributions. We can test for normality using Scipy as was shown above.

This assumption is often assumed even if the assumption is a weak one. If you strongly suspect that things are not normally distributed, you can transform your data to get it looking more normal and then run your test. This problem typically goes away for large sample sizes (yay Central Limit Theorem) and is often why you don't hear it brought up. People declare the assumption to be satisfied either way.

## Central Limit Theorem

```
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

sample_means = []
for x in range(0,3000):
  coinflips = np.random.binomial(n=1, p=.5, size=12)
  one_sample = coinflips
  sample_means.append(coinflips.mean())

print(len(sample_means))
print(sample_means)
```

    3000
    [0.5, 0.6666666666666666, 0.25, 0.6666666666666666, 0.3333333333333333, 0.4166666666666667, 0.5, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.16666666666666666, 0.3333333333333333, 0.4166666666666667, 0.5833333333333334, 0.5, 0.5, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.5, 0.75, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.5, 0.5, 0.75, 0.5, 0.3333333333333333, 0.5, 0.75, 0.3333333333333333, 0.75, 0.4166666666666667, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.75, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.75, 0.5833333333333334, 0.5833333333333334, 0.25, 0.5833333333333334, 0.5, 0.5833333333333334, 0.75, 0.5, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.25, 0.6666666666666666, 0.5, 0.25, 0.25, 0.4166666666666667, 0.4166666666666667, 0.8333333333333334, 0.5, 0.5, 0.5833333333333334, 0.6666666666666666, 0.3333333333333333, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.75, 0.6666666666666666, 0.4166666666666667, 0.5, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.08333333333333333, 0.5, 0.5833333333333334, 0.5, 0.75, 0.6666666666666666, 0.6666666666666666, 0.5833333333333334, 0.4166666666666667, 0.5, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.5, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.75, 0.5833333333333334, 0.16666666666666666, 0.6666666666666666, 0.5, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.5, 0.4166666666666667, 0.5, 0.5, 0.6666666666666666, 0.5, 0.5, 0.5, 0.4166666666666667, 0.6666666666666666, 0.5, 0.4166666666666667, 0.5, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.5, 0.5, 0.6666666666666666, 0.6666666666666666, 0.5833333333333334, 0.3333333333333333, 0.5, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.5, 0.5, 0.3333333333333333, 0.8333333333333334, 0.5, 0.75, 0.6666666666666666, 0.5, 0.4166666666666667, 0.75, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.25, 0.5, 0.5, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.5, 0.75, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.08333333333333333, 0.75, 0.4166666666666667, 0.25, 0.5, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.75, 0.4166666666666667, 0.5, 0.3333333333333333, 0.75, 0.8333333333333334, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.5, 0.5, 0.5, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.5, 0.4166666666666667, 0.6666666666666666, 0.6666666666666666, 0.5833333333333334, 0.4166666666666667, 0.75, 0.3333333333333333, 0.5, 0.75, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.5, 0.6666666666666666, 0.4166666666666667, 0.6666666666666666, 0.3333333333333333, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.25, 0.3333333333333333, 0.3333333333333333, 0.75, 0.6666666666666666, 0.3333333333333333, 0.75, 0.6666666666666666, 0.3333333333333333, 0.4166666666666667, 0.5, 0.4166666666666667, 0.5, 0.25, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.4166666666666667, 0.5, 0.5, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.75, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.25, 0.4166666666666667, 0.75, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.5, 0.6666666666666666, 0.5, 0.5, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.5, 0.5, 0.25, 0.25, 0.6666666666666666, 0.5, 0.5833333333333334, 0.5, 0.4166666666666667, 0.6666666666666666, 0.3333333333333333, 0.5833333333333334, 0.25, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.5, 0.6666666666666666, 0.5, 0.5833333333333334, 0.5, 0.3333333333333333, 0.75, 0.5833333333333334, 0.5, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.6666666666666666, 0.16666666666666666, 0.3333333333333333, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.5, 0.5833333333333334, 0.75, 0.5, 0.6666666666666666, 0.4166666666666667, 0.5, 0.5, 0.5833333333333334, 0.75, 0.5, 0.4166666666666667, 0.4166666666666667, 0.8333333333333334, 0.4166666666666667, 0.5, 0.5833333333333334, 0.5833333333333334, 0.75, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.6666666666666666, 0.5833333333333334, 0.3333333333333333, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.75, 0.75, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.4166666666666667, 0.08333333333333333, 0.3333333333333333, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.75, 0.3333333333333333, 0.4166666666666667, 0.5, 0.6666666666666666, 0.3333333333333333, 0.5, 0.16666666666666666, 0.4166666666666667, 0.5833333333333334, 0.5, 0.5, 0.4166666666666667, 0.4166666666666667, 0.75, 0.3333333333333333, 0.5, 0.25, 0.5833333333333334, 0.4166666666666667, 0.5, 0.8333333333333334, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.5, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.3333333333333333, 0.9166666666666666, 0.75, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.6666666666666666, 0.5, 0.75, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.5, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.3333333333333333, 0.5, 0.75, 0.5833333333333334, 0.4166666666666667, 0.5, 0.6666666666666666, 0.5833333333333334, 0.75, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.3333333333333333, 0.25, 0.25, 0.75, 0.5833333333333334, 0.3333333333333333, 0.5, 0.5, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.5, 0.5, 0.5833333333333334, 0.25, 0.25, 0.5, 0.5, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.3333333333333333, 0.5, 0.3333333333333333, 0.5833333333333334, 0.75, 0.6666666666666666, 0.75, 0.5, 0.3333333333333333, 0.25, 0.5833333333333334, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.25, 0.5, 0.5, 0.3333333333333333, 0.75, 0.5833333333333334, 0.75, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.5, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.5, 0.6666666666666666, 0.6666666666666666, 0.4166666666666667, 0.3333333333333333, 0.5, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.5, 0.75, 0.5833333333333334, 0.5, 0.6666666666666666, 0.9166666666666666, 0.6666666666666666, 0.6666666666666666, 0.3333333333333333, 0.5833333333333334, 0.5, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 0.75, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.5, 0.5, 0.3333333333333333, 0.5833333333333334, 0.5, 0.5833333333333334, 0.6666666666666666, 0.6666666666666666, 0.5, 0.5, 0.5833333333333334, 0.5833333333333334, 0.16666666666666666, 0.5833333333333334, 0.3333333333333333, 0.5, 0.6666666666666666, 0.75, 0.5, 0.5, 0.3333333333333333, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.5, 0.6666666666666666, 0.6666666666666666, 0.25, 0.6666666666666666, 0.5, 0.5833333333333334, 0.25, 0.5, 0.5833333333333334, 0.5, 0.5, 0.5, 0.5, 0.5833333333333334, 0.3333333333333333, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.5, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.25, 0.5, 0.5, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.5, 0.3333333333333333, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.6666666666666666, 0.75, 0.5833333333333334, 0.5833333333333334, 0.5, 0.5, 0.25, 0.8333333333333334, 0.5, 0.6666666666666666, 0.4166666666666667, 0.5, 0.6666666666666666, 0.6666666666666666, 0.3333333333333333, 0.5, 0.6666666666666666, 0.5833333333333334, 0.75, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5, 0.5, 0.6666666666666666, 0.25, 0.4166666666666667, 0.5833333333333334, 0.5, 0.75, 0.4166666666666667, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5, 0.5, 0.6666666666666666, 0.3333333333333333, 0.5, 0.3333333333333333, 0.6666666666666666, 0.5, 0.8333333333333334, 0.75, 0.4166666666666667, 0.75, 0.4166666666666667, 0.5833333333333334, 0.5, 0.4166666666666667, 0.25, 0.4166666666666667, 0.5833333333333334, 0.5, 0.4166666666666667, 0.6666666666666666, 0.5, 0.5, 0.5833333333333334, 0.5833333333333334, 0.5, 0.5, 0.6666666666666666, 0.5833333333333334, 0.5, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.5833333333333334, 0.5, 0.5833333333333334, 0.25, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.5, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5, 0.4166666666666667, 0.25, 0.5833333333333334, 0.3333333333333333, 0.3333333333333333, 0.3333333333333333, 0.5833333333333334, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 0.5833333333333334, 0.5, 0.5, 0.3333333333333333, 0.5, 0.25, 0.3333333333333333, 0.5833333333333334, 0.75, 0.6666666666666666, 0.3333333333333333, 0.3333333333333333, 0.5, 0.75, 0.4166666666666667, 0.5, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.6666666666666666, 0.16666666666666666, 0.25, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.5, 0.16666666666666666, 0.4166666666666667, 0.75, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.5, 0.6666666666666666, 0.6666666666666666, 0.5, 0.5, 0.6666666666666666, 0.5, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.5, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.5, 0.25, 0.5833333333333334, 0.5833333333333334, 0.5, 0.4166666666666667, 0.6666666666666666, 0.5, 0.4166666666666667, 0.5, 0.75, 0.25, 0.6666666666666666, 0.4166666666666667, 0.6666666666666666, 0.75, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.5, 0.5833333333333334, 0.25, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.08333333333333333, 0.25, 0.25, 0.4166666666666667, 0.6666666666666666, 0.6666666666666666, 0.3333333333333333, 0.5, 0.4166666666666667, 0.3333333333333333, 0.25, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.6666666666666666, 0.25, 0.5, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.25, 0.75, 0.75, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5, 0.4166666666666667, 0.5, 0.5, 0.5, 0.75, 0.5, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.6666666666666666, 0.4166666666666667, 0.16666666666666666, 0.5, 0.5, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.5, 0.4166666666666667, 0.3333333333333333, 0.6666666666666666, 0.5833333333333334, 0.08333333333333333, 0.4166666666666667, 0.5833333333333334, 0.5, 0.6666666666666666, 0.5, 0.5833333333333334, 0.3333333333333333, 0.5, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 0.4166666666666667, 0.5, 0.5, 0.5, 0.25, 0.3333333333333333, 0.75, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.8333333333333334, 0.8333333333333334, 0.4166666666666667, 0.5, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.5, 0.5, 0.4166666666666667, 0.5, 0.25, 0.5, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5, 0.75, 0.5833333333333334, 0.5, 0.3333333333333333, 0.5833333333333334, 0.25, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.5, 0.4166666666666667, 0.6666666666666666, 0.5, 0.3333333333333333, 0.5, 0.5833333333333334, 0.5, 0.5, 0.3333333333333333, 0.5833333333333334, 0.5, 0.6666666666666666, 0.5, 0.75, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.8333333333333334, 0.5, 0.4166666666666667, 0.5, 0.4166666666666667, 0.5, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.5, 0.5, 0.3333333333333333, 0.25, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.5, 0.6666666666666666, 0.5, 0.5833333333333334, 0.3333333333333333, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.5, 0.5, 0.5, 0.16666666666666666, 0.5, 0.5, 0.5, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.5, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.5, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.25, 0.5, 0.25, 0.4166666666666667, 0.75, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.25, 0.5, 0.75, 0.16666666666666666, 0.8333333333333334, 0.4166666666666667, 0.3333333333333333, 0.4166666666666667, 0.5, 0.3333333333333333, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.5, 0.3333333333333333, 0.8333333333333334, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.25, 0.5833333333333334, 0.4166666666666667, 0.5, 0.75, 0.3333333333333333, 0.5, 0.5, 0.75, 0.75, 0.4166666666666667, 0.8333333333333334, 0.6666666666666666, 0.6666666666666666, 0.25, 0.5, 0.6666666666666666, 0.5, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.75, 0.4166666666666667, 0.5, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.25, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.5, 0.75, 0.3333333333333333, 0.5, 0.6666666666666666, 0.5, 0.25, 0.6666666666666666, 0.5833333333333334, 0.5, 0.3333333333333333, 0.8333333333333334, 0.5, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.5, 0.6666666666666666, 0.3333333333333333, 0.5, 0.75, 0.6666666666666666, 0.25, 0.5, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.5, 0.5, 0.3333333333333333, 0.16666666666666666, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.6666666666666666, 0.3333333333333333, 0.8333333333333334, 0.6666666666666666, 0.5833333333333334, 0.5, 0.4166666666666667, 0.6666666666666666, 0.5, 0.4166666666666667, 0.5, 0.8333333333333334, 0.6666666666666666, 0.25, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.5, 0.5833333333333334, 0.16666666666666666, 0.75, 0.4166666666666667, 0.75, 0.25, 0.5833333333333334, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.3333333333333333, 0.5, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.5, 0.5, 0.5833333333333334, 0.6666666666666666, 0.5, 0.6666666666666666, 0.6666666666666666, 0.5, 0.5833333333333334, 0.5, 0.3333333333333333, 0.5, 0.5, 0.4166666666666667, 0.4166666666666667, 0.75, 0.4166666666666667, 0.4166666666666667, 0.25, 0.25, 0.4166666666666667, 0.75, 0.5, 0.4166666666666667, 0.25, 0.4166666666666667, 0.3333333333333333, 0.5, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.6666666666666666, 0.3333333333333333, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.75, 0.5, 0.5, 0.75, 0.6666666666666666, 0.6666666666666666, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.75, 0.75, 0.5, 0.3333333333333333, 0.75, 0.4166666666666667, 0.6666666666666666, 0.5, 0.5833333333333334, 0.5833333333333334, 0.5, 0.16666666666666666, 0.25, 0.5, 0.5, 0.4166666666666667, 0.8333333333333334, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.5, 0.5833333333333334, 0.3333333333333333, 0.5, 0.4166666666666667, 0.25, 0.5, 0.5, 0.6666666666666666, 0.5, 0.5, 0.5, 0.5, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.6666666666666666, 0.5, 0.3333333333333333, 0.16666666666666666, 0.6666666666666666, 0.5, 0.6666666666666666, 0.3333333333333333, 0.8333333333333334, 0.5, 0.5, 0.16666666666666666, 0.4166666666666667, 0.75, 0.5833333333333334, 0.4166666666666667, 0.5, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.5, 0.25, 0.5, 0.5, 0.25, 0.3333333333333333, 0.5, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.6666666666666666, 0.5833333333333334, 0.5, 0.5, 0.25, 0.4166666666666667, 0.4166666666666667, 0.25, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.5, 0.5833333333333334, 0.5, 0.5, 0.6666666666666666, 0.4166666666666667, 0.5, 0.5, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.25, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.25, 0.6666666666666666, 0.5833333333333334, 0.5, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.5, 0.25, 0.5833333333333334, 0.6666666666666666, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.5, 0.4166666666666667, 0.5, 0.25, 0.5, 0.5833333333333334, 0.5, 0.6666666666666666, 0.5, 0.5833333333333334, 0.5, 0.5, 0.5, 0.3333333333333333, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.75, 0.5833333333333334, 0.5, 0.3333333333333333, 0.5833333333333334, 0.5, 0.25, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.5, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.75, 0.75, 0.5833333333333334, 0.5, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.5, 0.5, 0.5833333333333334, 0.5, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.25, 0.6666666666666666, 0.5, 0.5833333333333334, 0.5, 0.5, 0.25, 0.5, 0.5833333333333334, 0.5, 0.5, 0.6666666666666666, 0.6666666666666666, 0.3333333333333333, 0.4166666666666667, 0.8333333333333334, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.5, 0.4166666666666667, 0.5, 0.5, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.5, 0.5833333333333334, 0.6666666666666666, 0.5, 0.4166666666666667, 0.25, 0.4166666666666667, 0.5, 0.3333333333333333, 0.5, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.25, 0.3333333333333333, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.3333333333333333, 0.4166666666666667, 0.5, 0.5, 0.3333333333333333, 0.6666666666666666, 0.5, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.75, 0.5833333333333334, 0.5, 0.75, 0.75, 0.5, 0.4166666666666667, 0.25, 0.4166666666666667, 0.25, 0.4166666666666667, 0.5, 0.4166666666666667, 0.4166666666666667, 0.5, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.6666666666666666, 0.5833333333333334, 0.3333333333333333, 0.25, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.75, 0.5, 0.5833333333333334, 0.5, 0.25, 0.5833333333333334, 0.3333333333333333, 0.5, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.75, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.75, 0.5, 0.3333333333333333, 0.5, 0.5, 0.4166666666666667, 0.5, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5, 0.4166666666666667, 0.75, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.5, 0.4166666666666667, 0.3333333333333333, 0.5, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.5, 0.5, 0.4166666666666667, 0.5, 0.5833333333333334, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 0.5833333333333334, 0.08333333333333333, 0.4166666666666667, 0.5, 0.5, 0.3333333333333333, 0.3333333333333333, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5, 0.5, 0.8333333333333334, 0.5833333333333334, 0.5, 0.4166666666666667, 0.75, 0.4166666666666667, 0.3333333333333333, 0.75, 0.3333333333333333, 0.5833333333333334, 0.3333333333333333, 0.5, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.3333333333333333, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.5, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.5, 0.5, 0.25, 0.5, 0.8333333333333334, 0.25, 0.5, 0.3333333333333333, 0.4166666666666667, 0.5, 0.6666666666666666, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.5, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.75, 0.4166666666666667, 0.5, 0.5, 0.5, 0.6666666666666666, 0.3333333333333333, 0.75, 0.5, 0.5, 0.3333333333333333, 0.5833333333333334, 0.6666666666666666, 0.25, 0.4166666666666667, 0.5833333333333334, 0.25, 0.75, 0.3333333333333333, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.5, 0.3333333333333333, 0.5, 0.6666666666666666, 0.4166666666666667, 0.6666666666666666, 0.16666666666666666, 0.6666666666666666, 0.4166666666666667, 0.75, 0.9166666666666666, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.5, 0.4166666666666667, 0.25, 0.6666666666666666, 0.5833333333333334, 0.5, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.9166666666666666, 0.25, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.5, 0.5, 0.3333333333333333, 0.16666666666666666, 0.6666666666666666, 0.5, 0.6666666666666666, 0.75, 0.5, 0.6666666666666666, 0.4166666666666667, 0.75, 0.4166666666666667, 0.5, 0.5833333333333334, 0.4166666666666667, 0.25, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.3333333333333333, 0.4166666666666667, 0.6666666666666666, 0.8333333333333334, 0.5833333333333334, 0.5, 0.75, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.25, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.5, 0.6666666666666666, 0.16666666666666666, 0.3333333333333333, 0.4166666666666667, 0.6666666666666666, 0.5, 0.4166666666666667, 0.5833333333333334, 0.5, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.25, 0.25, 0.4166666666666667, 0.5, 0.5, 0.5833333333333334, 0.5, 0.5833333333333334, 0.3333333333333333, 0.5, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.6666666666666666, 0.5833333333333334, 0.4166666666666667, 0.5, 0.3333333333333333, 0.5833333333333334, 0.3333333333333333, 0.5, 0.5833333333333334, 0.5, 0.4166666666666667, 0.5, 0.5, 0.4166666666666667, 0.4166666666666667, 0.16666666666666666, 0.3333333333333333, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5, 0.5, 0.3333333333333333, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.5, 0.5, 0.5, 0.5, 0.5, 0.3333333333333333, 0.75, 0.25, 0.6666666666666666, 0.5833333333333334, 0.3333333333333333, 0.5, 0.25, 0.5, 0.5, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.3333333333333333, 0.3333333333333333, 0.5833333333333334, 0.5, 0.3333333333333333, 0.5, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.25, 0.3333333333333333, 0.8333333333333334, 0.5, 0.3333333333333333, 0.3333333333333333, 0.6666666666666666, 0.5833333333333334, 0.16666666666666666, 0.4166666666666667, 0.5, 0.5833333333333334, 0.4166666666666667, 0.5, 0.5833333333333334, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5, 0.25, 0.5, 0.6666666666666666, 0.5, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.75, 0.75, 0.3333333333333333, 0.5833333333333334, 0.6666666666666666, 0.5, 0.5833333333333334, 0.5, 0.25, 0.5, 0.5, 0.75, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.5, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.5, 0.6666666666666666, 0.75, 0.5, 0.5, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.75, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.3333333333333333, 0.5833333333333334, 0.6666666666666666, 0.3333333333333333, 0.3333333333333333, 0.8333333333333334, 0.5, 0.3333333333333333, 0.25, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.5, 0.4166666666666667, 0.6666666666666666, 0.16666666666666666, 0.5833333333333334, 0.5833333333333334, 0.5, 0.3333333333333333, 0.5, 0.5, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.25, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 0.5, 0.3333333333333333, 0.4166666666666667, 0.3333333333333333, 0.5, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.5, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.5, 0.5, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.25, 0.5, 0.4166666666666667, 0.3333333333333333, 0.5, 0.5, 0.5, 0.5, 0.5, 0.4166666666666667, 0.5, 0.6666666666666666, 0.5, 0.5, 0.3333333333333333, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.5, 0.5833333333333334, 0.6666666666666666, 0.3333333333333333, 0.5, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.25, 0.6666666666666666, 0.75, 0.75, 0.5, 0.5833333333333334, 0.3333333333333333, 0.6666666666666666, 0.3333333333333333, 0.5, 0.5, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.6666666666666666, 0.4166666666666667, 0.3333333333333333, 0.75, 0.5833333333333334, 0.3333333333333333, 0.5, 0.3333333333333333, 0.5833333333333334, 0.5, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.75, 0.5833333333333334, 0.16666666666666666, 0.6666666666666666, 0.4166666666666667, 0.6666666666666666, 0.5, 0.5, 0.4166666666666667, 0.5, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.5, 0.5, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.75, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.08333333333333333, 0.4166666666666667, 0.4166666666666667, 0.8333333333333334, 0.5, 0.25, 0.75, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.5, 0.5, 0.75, 0.3333333333333333, 0.6666666666666666, 0.5, 0.5, 0.75, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.5, 0.5833333333333334, 0.5, 0.5, 0.5833333333333334, 0.3333333333333333, 0.5, 0.25, 0.25, 0.5, 0.4166666666666667, 0.6666666666666666, 0.5, 0.5833333333333334, 0.5, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.75, 0.5833333333333334, 0.5833333333333334, 0.5, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.8333333333333334, 0.5, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.8333333333333334, 0.5, 0.5, 0.3333333333333333, 0.75, 0.5, 0.4166666666666667, 0.16666666666666666, 0.25, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.3333333333333333, 0.6666666666666666, 0.16666666666666666, 0.6666666666666666, 0.5, 0.5833333333333334, 0.5833333333333334, 0.5, 0.5, 0.5833333333333334, 0.5, 0.5, 0.75, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.5, 0.4166666666666667, 0.5833333333333334, 0.5, 0.8333333333333334, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5, 0.75, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.25, 0.4166666666666667, 0.3333333333333333, 0.5, 0.4166666666666667, 0.25, 0.3333333333333333, 0.4166666666666667, 0.8333333333333334, 0.5833333333333334, 0.5, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.6666666666666666, 0.25, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.75, 0.4166666666666667, 0.4166666666666667, 0.25, 0.5, 0.75, 0.4166666666666667, 0.75, 0.6666666666666666, 0.3333333333333333, 0.6666666666666666, 0.5833333333333334, 0.75, 0.5833333333333334, 0.25, 0.6666666666666666, 0.3333333333333333, 0.3333333333333333, 0.5, 0.5833333333333334, 0.5, 0.5, 0.5, 0.4166666666666667, 0.5, 0.4166666666666667, 0.5, 0.4166666666666667, 0.4166666666666667, 0.5, 0.75, 0.9166666666666666, 0.4166666666666667, 0.75, 0.75, 0.3333333333333333, 0.6666666666666666, 0.25, 0.4166666666666667, 0.5, 0.5, 0.3333333333333333, 0.3333333333333333, 0.5, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.5, 0.3333333333333333, 0.3333333333333333, 0.5, 0.75, 0.75, 0.3333333333333333, 0.5, 0.75, 0.5, 0.5, 0.75, 0.25, 0.6666666666666666, 0.25, 0.6666666666666666, 0.3333333333333333, 0.5, 0.5, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.75, 0.4166666666666667, 0.75, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5, 0.5, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.5, 0.75, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.5, 0.6666666666666666, 0.5, 0.5, 0.5, 0.5833333333333334, 0.3333333333333333, 0.5, 0.25, 0.25, 0.6666666666666666, 0.5, 0.5, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.5, 0.75, 0.4166666666666667, 0.5833333333333334, 0.5, 0.75, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.3333333333333333, 0.75, 0.6666666666666666, 0.4166666666666667, 0.3333333333333333, 0.4166666666666667, 0.6666666666666666, 0.5, 0.5833333333333334, 0.3333333333333333, 0.3333333333333333, 0.5833333333333334, 0.3333333333333333, 0.3333333333333333, 0.5, 0.5, 0.5, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.5833333333333334, 0.5, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.75, 0.4166666666666667, 0.25, 0.4166666666666667, 0.5833333333333334, 0.5, 0.3333333333333333, 0.5833333333333334, 0.25, 0.5, 0.5, 0.75, 0.5, 0.5, 0.75, 0.3333333333333333, 0.4166666666666667, 0.5, 0.8333333333333334, 0.4166666666666667, 0.75, 0.5833333333333334, 0.8333333333333334, 0.25, 0.4166666666666667, 0.5, 0.6666666666666666, 0.3333333333333333, 0.25, 0.5, 0.4166666666666667, 0.5, 0.16666666666666666, 0.75, 0.4166666666666667, 0.75, 0.25, 0.4166666666666667, 0.5, 0.75, 0.75, 0.5, 0.75, 0.3333333333333333, 0.5, 0.5833333333333334, 0.4166666666666667, 0.8333333333333334, 0.5833333333333334, 0.5, 0.4166666666666667, 0.5, 0.6666666666666666, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.6666666666666666, 0.75, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.25, 0.5, 0.25, 0.4166666666666667, 0.5, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.5, 0.4166666666666667, 0.5833333333333334, 0.75, 0.5, 0.4166666666666667, 0.5, 0.5833333333333334, 0.6666666666666666, 0.75, 0.5, 0.5, 0.4166666666666667, 0.4166666666666667, 0.25, 0.4166666666666667, 0.6666666666666666, 0.3333333333333333, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.8333333333333334, 0.6666666666666666, 0.5833333333333334, 0.25, 0.75, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.5, 0.6666666666666666, 0.4166666666666667, 0.5, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.5, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.75, 0.25, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.4166666666666667, 0.5, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.5, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.5, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.5, 0.6666666666666666, 0.25, 0.25, 0.5, 0.6666666666666666, 0.5, 0.3333333333333333, 0.4166666666666667, 0.3333333333333333, 0.6666666666666666, 0.4166666666666667, 0.3333333333333333, 0.08333333333333333, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.5, 0.3333333333333333, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.5, 0.16666666666666666, 0.3333333333333333, 0.4166666666666667, 0.25, 0.3333333333333333, 0.16666666666666666, 0.4166666666666667, 0.6666666666666666, 0.5, 0.3333333333333333, 0.5, 0.4166666666666667, 0.25, 0.5, 0.4166666666666667, 0.5, 0.5, 0.4166666666666667, 0.8333333333333334, 0.5, 0.5, 0.5833333333333334, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.5, 0.6666666666666666, 0.5, 0.4166666666666667, 0.5, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.5, 0.5, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.75, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.75, 0.5, 0.4166666666666667, 0.8333333333333334, 0.4166666666666667, 0.3333333333333333, 0.6666666666666666, 0.5833333333333334, 0.5, 0.5, 0.8333333333333334, 0.4166666666666667, 0.25, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.5, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.75, 0.8333333333333334, 0.6666666666666666, 0.6666666666666666, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.25, 0.5833333333333334, 0.4166666666666667, 0.25, 0.5833333333333334, 0.5, 0.3333333333333333, 0.4166666666666667, 0.75, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.3333333333333333, 0.4166666666666667, 0.5833333333333334, 0.3333333333333333, 0.5, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.5, 0.5833333333333334, 0.4166666666666667, 0.5, 0.5833333333333334, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.5, 0.5833333333333334, 0.3333333333333333, 0.5, 0.3333333333333333, 0.3333333333333333, 0.5, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.5, 0.25, 0.5833333333333334, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.5, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5, 0.3333333333333333, 0.5833333333333334, 0.25, 0.75, 0.4166666666666667, 0.3333333333333333, 0.6666666666666666, 0.4166666666666667, 0.5, 0.3333333333333333, 0.5, 0.5, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.5, 0.5, 0.5, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.16666666666666666, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.5, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.9166666666666666, 0.3333333333333333, 0.4166666666666667, 0.5, 0.25, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.5, 0.5, 0.3333333333333333, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 0.25, 0.3333333333333333, 0.3333333333333333, 0.25, 0.3333333333333333, 0.5833333333333334, 0.5, 0.75, 0.5833333333333334, 0.5, 0.6666666666666666, 0.5833333333333334, 0.25, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.3333333333333333, 0.5, 0.3333333333333333, 0.3333333333333333, 0.4166666666666667, 0.5833333333333334, 0.75, 0.5, 0.3333333333333333, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.5, 0.5, 0.5, 0.6666666666666666, 0.5833333333333334, 0.5, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.3333333333333333, 0.5, 0.5833333333333334, 0.5, 0.25, 0.5, 0.4166666666666667, 0.16666666666666666, 0.5, 0.3333333333333333, 0.5833333333333334, 0.5, 0.16666666666666666, 0.16666666666666666, 0.3333333333333333, 0.5, 0.75, 0.5833333333333334, 0.5833333333333334, 0.75, 0.3333333333333333, 0.8333333333333334, 0.5, 0.4166666666666667, 0.3333333333333333, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.5, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.3333333333333333, 0.5, 0.5, 0.75, 0.25, 0.5, 0.5, 0.5833333333333334, 0.75, 0.5, 0.5, 0.6666666666666666, 0.75, 0.5, 0.5, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.75, 0.75, 0.5, 0.4166666666666667, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.75, 0.4166666666666667, 0.3333333333333333, 0.25, 0.75, 0.6666666666666666, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.5, 0.25, 0.5, 0.5, 0.4166666666666667, 0.5, 0.5833333333333334, 0.5, 0.5833333333333334, 0.6666666666666666, 0.5, 0.5833333333333334, 0.6666666666666666, 0.75, 0.5, 0.5, 0.3333333333333333, 0.5, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.3333333333333333, 0.5, 0.5, 0.4166666666666667, 0.6666666666666666, 0.75, 0.3333333333333333, 0.4166666666666667, 0.5, 0.4166666666666667, 0.6666666666666666, 0.3333333333333333, 0.4166666666666667, 0.25, 0.3333333333333333, 0.4166666666666667, 0.5833333333333334, 0.5, 0.5, 0.8333333333333334, 0.75, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.5, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.6666666666666666, 0.6666666666666666, 0.75, 0.25, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.5, 0.25, 0.5, 0.5833333333333334, 0.5833333333333334, 0.75, 0.5, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.6666666666666666, 0.5, 0.4166666666666667, 0.5, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.75, 0.5833333333333334, 0.6666666666666666, 0.5, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5, 0.4166666666666667, 0.4166666666666667, 0.5, 0.16666666666666666, 0.5, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.6666666666666666, 0.6666666666666666, 0.8333333333333334, 0.3333333333333333, 0.5, 0.5833333333333334, 0.6666666666666666, 0.5, 0.08333333333333333, 0.25, 0.8333333333333334, 0.5, 0.5833333333333334, 0.6666666666666666, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5, 0.4166666666666667, 0.5, 0.3333333333333333, 0.8333333333333334, 0.8333333333333334, 0.4166666666666667, 0.5, 0.4166666666666667, 0.5, 0.3333333333333333, 0.6666666666666666, 0.5, 0.5833333333333334, 0.5, 0.4166666666666667, 0.4166666666666667, 0.5, 0.5, 0.25, 0.5833333333333334, 0.3333333333333333, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.25, 0.4166666666666667, 0.6666666666666666, 0.8333333333333334, 0.5833333333333334, 0.25, 0.4166666666666667, 0.6666666666666666, 0.25, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.5, 0.25, 0.75, 0.5833333333333334, 0.5, 0.25, 0.3333333333333333, 0.4166666666666667, 0.16666666666666666, 0.5, 0.6666666666666666, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.25, 0.6666666666666666, 0.75, 0.5833333333333334, 0.5, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.5, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.25, 0.6666666666666666, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.6666666666666666, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.75, 0.5, 0.3333333333333333, 0.5833333333333334, 0.5833333333333334, 0.25, 0.6666666666666666, 0.5, 0.5833333333333334, 0.75, 0.5, 0.5833333333333334, 0.75, 0.6666666666666666, 0.75, 0.5, 0.5, 0.4166666666666667, 0.5, 0.4166666666666667, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.5, 0.5833333333333334, 0.4166666666666667, 0.5, 0.5, 0.3333333333333333, 0.5833333333333334, 0.6666666666666666, 0.5, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.6666666666666666, 0.5833333333333334, 0.5, 0.25, 0.4166666666666667, 0.4166666666666667, 0.5, 0.75, 0.3333333333333333, 0.5, 0.75, 0.5, 0.4166666666666667, 0.4166666666666667, 0.5, 0.3333333333333333, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.5833333333333334, 0.5833333333333334, 0.75, 0.3333333333333333, 0.5, 0.5833333333333334, 0.6666666666666666, 0.4166666666666667, 0.5, 0.5833333333333334, 0.5, 0.5833333333333334, 0.5833333333333334, 0.5833333333333334, 0.5, 0.5, 0.5833333333333334, 0.4166666666666667, 0.3333333333333333, 0.75, 0.5833333333333334, 0.4166666666666667, 0.5833333333333334, 0.5, 0.5833333333333334, 0.4166666666666667, 0.6666666666666666, 0.3333333333333333, 0.5833333333333334, 0.6666666666666666, 0.08333333333333333, 0.5, 0.5833333333333334, 0.5833333333333334, 0.4166666666666667, 0.5, 0.75, 0.5, 0.6666666666666666, 0.6666666666666666, 0.5, 0.5, 0.16666666666666666, 0.4166666666666667, 1.0, 0.6666666666666666, 0.5833333333333334, 0.5833333333333334, 0.3333333333333333, 0.75, 0.6666666666666666, 0.4166666666666667, 0.6666666666666666, 0.5833333333333334, 0.75, 0.5, 0.5, 0.5, 0.5833333333333334, 0.5, 0.5833333333333334, 0.25, 0.4166666666666667, 0.75, 0.4166666666666667, 0.3333333333333333, 0.5833333333333334, 0.5, 0.6666666666666666, 0.4166666666666667, 0.5, 0.75, 0.4166666666666667, 0.25, 0.25, 0.5, 0.5, 0.3333333333333333, 0.5, 0.3333333333333333, 0.16666666666666666, 0.6666666666666666, 0.4166666666666667, 0.4166666666666667, 0.4166666666666667, 0.5, 0.4166666666666667, 0.6666666666666666, 0.4166666666666667, 0.25, 0.4166666666666667, 0.3333333333333333, 0.3333333333333333, 0.3333333333333333, 0.5833333333333334, 0.5, 0.5833333333333334, 0.75, 0.5, 0.5833333333333334, 0.75, 0.6666666666666666, 0.6666666666666666, 0.5, 0.3333333333333333, 0.5833333333333334, 0.3333333333333333, 0.4166666666666667, 0.4166666666666667, 0.5, 0.75, 0.6666666666666666, 0.4166666666666667]

```
df = pd.DataFrame({'a': one_sample})
df.head()
```

      a

      0
      0

      1
      1

      2
      1

      3
      1

      4
      0

```
df.a.hist()
```

```
ax = plt.hist(sample_means, bins=24)
plt.title('Distribution of 3000 sample means \n (of 12 coinflips each)');
```

What does the Central Limit Theorem State? That no matter the initial distribution of the population, the distribution of sample means taken will approximate a normal distribution as $n \rightarrow \infty$.

This has very important implications for hypothesis testing and is precisely the reason why the t-distribution begins to approximate the normal distribution as our sample size increases.

## Standard Error of the Mean

What does it mean to "estimate"? the Population mean?

```

```

## Build and Interpret a Confidence Interval

```
coinflips_100 = np.random.binomial(n=1, p=.5, size=100)

sample_std = np.std(coinflips_100, ddof=1)
print("sample standard dev", sample_std)
```

    sample standard dev 0.5024183937956914

```
sample_size = len(coinflips_100)
print(sample_size)
```

    100

```
standard_error = sample_std / np.sqrt(sample_size)

print("Standard Error", standard_error)
```

    Standard Error 0.05024183937956914

```
from scipy import stats

stderr = stats.sem(coinflips_100, ddof=1)
print("Scipy standard error", stderr)
```

    Scipy standard error 0.05024183937956914

##Look at stats.t.ppf()

```
t=stats.t.ppf(.975, 99)
t
```

    1.9842169515086827

```
t = stats.t.ppf(.025, 99)
t
```

    -1.9842169515086832

```
(1+.99)/2
```

    0.995

```
stats.t.ppf(.995, 99)
```

    2.6264054563851857

```
def confidence_interval(data, confidence=0.95):
  """
  Calculate a confidence interval around a sample mean for given data.
  Using t-distribution and two-tailed test, default 95% confidence.

  Arguments:
    data - iterable (list or numpy array) of sample observations
    confidence - level of confidence for the interval

  Returns:
    tuple of (mean, lower bound, upper bound)
  """
  data = np.array(data)
  mean = np.mean(data)
  sample_size = len(data)
  sample_std_dev = np.std(data, ddof=1)
  stderr = stats.sem(data)
  interval = stderr * stats.t.ppf((1 + confidence) / 2.0, sample_size - 1)
  return (mean, mean - interval, mean + interval)
```

## Graphically Represent a Confidence Interval

https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.errorbar.html

https://jakevdp.github.io/PythonDataScienceHandbook/04.03-errorbars.html

https://seaborn.pydata.org/generated/seaborn.barplot.html

```
import seaborn as sns

coinflips_100 = np.random.binomial(n=1, p=.5, size=100)
sns.kdeplot(coinflips_100)
CI = confidence_interval(coinflips_100)
plt.axvline(x=CI[1], color='r')
plt.axvline(x=CI[2], color='r')
plt.axvline(x=CI[0], color='k')
```

```

```

## Relationship between Confidence Intervals and T-tests

Confidence Interval == Bounds of statistical significance for our t-test

A sample mean that falls inside of our confidence interval will "FAIL TO REJECT" our null hypothesis

A sample mean that falls outside of our confidence interval will "REJECT" our null hypothesis

```
from scipy.stats import t, ttest_1samp
```

```
import numpy as np

coinflip_means = []
for x in range(0,100):
  coinflips = np.random.binomial(n=1, p=.5, size=30)
  coinflip_means.append(coinflips.mean())

print(coinflip_means)
```

    [0.6, 0.5, 0.6333333333333333, 0.4, 0.4, 0.4666666666666667, 0.5333333333333333, 0.5333333333333333, 0.4, 0.5333333333333333, 0.3, 0.5333333333333333, 0.5333333333333333, 0.6, 0.5333333333333333, 0.6333333333333333, 0.4666666666666667, 0.5333333333333333, 0.5333333333333333, 0.43333333333333335, 0.4, 0.6, 0.36666666666666664, 0.6, 0.6, 0.5666666666666667, 0.4, 0.43333333333333335, 0.6333333333333333, 0.6333333333333333, 0.5333333333333333, 0.43333333333333335, 0.5333333333333333, 0.3333333333333333, 0.4666666666666667, 0.3333333333333333, 0.4, 0.4666666666666667, 0.6333333333333333, 0.43333333333333335, 0.36666666666666664, 0.5666666666666667, 0.5666666666666667, 0.6333333333333333, 0.4666666666666667, 0.6666666666666666, 0.36666666666666664, 0.36666666666666664, 0.36666666666666664, 0.5, 0.6666666666666666, 0.5333333333333333, 0.5, 0.43333333333333335, 0.5, 0.4666666666666667, 0.36666666666666664, 0.6333333333333333, 0.43333333333333335, 0.4666666666666667, 0.5666666666666667, 0.4666666666666667, 0.5, 0.6333333333333333, 0.43333333333333335, 0.3333333333333333, 0.43333333333333335, 0.36666666666666664, 0.4, 0.43333333333333335, 0.5666666666666667, 0.5, 0.4666666666666667, 0.3333333333333333, 0.5666666666666667, 0.43333333333333335, 0.43333333333333335, 0.43333333333333335, 0.5666666666666667, 0.5333333333333333, 0.5333333333333333, 0.7, 0.43333333333333335, 0.4, 0.5, 0.43333333333333335, 0.5, 0.5333333333333333, 0.36666666666666664, 0.6, 0.43333333333333335, 0.5, 0.5, 0.6666666666666666, 0.3, 0.5666666666666667, 0.5333333333333333, 0.5333333333333333, 0.36666666666666664, 0.5333333333333333]

```
# Sample Size
n = len(coinflip_means)
# Degrees of Freedom
dof = n-1
# The Mean of Means:
mean = np.mean(coinflip_means)
# Sample Standard Deviation
sample_std = np.std(coinflip_means, ddof=1)
# Standard Error
std_err = sample_std/n**.5

CI = t.interval(.95, dof, loc=mean, scale=std_err)
print("95% Confidence Interval: ", CI)
```

    95% Confidence Interval:  (0.47229604845181783, 0.5097039515481822)

```
'''You can roll your own CI calculation pretty easily.
The only thing that's a little bit challenging
is understanding the t stat lookup'''

# 95% confidence interval
t_stat = t.ppf(.975, dof)
print("t Statistic:", t_stat)

CI = (mean-(t_stat*std_err), mean+(t_stat*std_err))
print("Confidence Interval", CI)
```

    t Statistic: 1.9842169515086827
    Confidence Interval (0.47229604845181783, 0.5097039515481822)

A null hypothesis that's just inside of our confidence interval == fail to reject

```
ttest_1samp(coinflip_means, .49)
```

    Ttest_1sampResult(statistic=0.10608544116451862, pvalue=0.9157292253188959)

A null hypothesis that's just outside of our confidence interval == reject

```
ttest_1samp(coinflip_means, .4818927)
```

    Ttest_1sampResult(statistic=0.966151938317618, pvalue=0.33632241031590215)

## Run a $\chi^{2}$ Test "by hand" (Using Numpy)

```
df = pd.read_csv('https://raw.githubusercontent.com/ryanleeallred/datasets/master/adult.csv', na_values=" ?")
print(df.shape)
df.head()
```

    (32561, 15)

      age
      workclass
      fnlwgt
      education
      education-num
      marital-status
      occupation
      relationship
      race
      sex
      capital-gain
      capital-loss
      hours-per-week
      country
      salary

      0
      39
      State-gov
      77516
      Bachelors
      13
      Never-married
      Adm-clerical
      Not-in-family
      White
      Male
      2174
      0
      40
      United-States
      <=50K

      1
      50
      Self-emp-not-inc
      83311
      Bachelors
      13
      Married-civ-spouse
      Exec-managerial
      Husband
      White
      Male
      0
      0
      13
      United-States
      <=50K

      2
      38
      Private
      215646
      HS-grad
      9
      Divorced
      Handlers-cleaners
      Not-in-family
      White
      Male
      0
      0
      40
      United-States
      <=50K

      3
      53
      Private
      234721
      11th
      7
      Married-civ-spouse
      Handlers-cleaners
      Husband
      Black
      Male
      0
      0
      40
      United-States
      <=50K

      4
      28
      Private
      338409
      Bachelors
      13
      Married-civ-spouse
      Prof-specialty
      Wife
      Black
      Female
      0
      0
      40
      Cuba
      <=50K

```
df.describe()
```

      age
      fnlwgt
      education-num
      capital-gain
      capital-loss
      hours-per-week

      count
      32561.000000
      3.256100e+04
      32561.000000
      32561.000000
      32561.000000
      32561.000000

      mean
      38.581647
      1.897784e+05
      10.080679
      1077.648844
      87.303830
      40.437456

      std
      13.640433
      1.055500e+05
      2.572720
      7385.292085
      402.960219
      12.347429

      min
      17.000000
      1.228500e+04
      1.000000
      0.000000
      0.000000
      1.000000

      25%
      28.000000
      1.178270e+05
      9.000000
      0.000000
      0.000000
      40.000000

      50%
      37.000000
      1.783560e+05
      10.000000
      0.000000
      0.000000
      40.000000

      75%
      48.000000
      2.370510e+05
      12.000000
      0.000000
      0.000000
      45.000000

      max
      90.000000
      1.484705e+06
      16.000000
      99999.000000
      4356.000000
      99.000000

```
df.describe(exclude='number')
```

      workclass
      education
      marital-status
      occupation
      relationship
      race
      sex
      country
      salary

      count
      30725
      32561
      32561
      30718
      32561
      32561
      32561
      31978
      32561

      unique
      8
      16
      7
      14
      6
      5
      2
      41
      2

      top
      Private
      HS-grad
      Married-civ-spouse
      Prof-specialty
      Husband
      White
      Male
      United-States
      <=50K

      freq
      22696
      10501
      14976
      4140
      13193
      27816
      21790
      29170
      24720

```
cut_points = [0,9,19,29,39,49,1000]
label_names = ['0-9', '10-19', '20-29', '30-39', '40-49', '50+']
df['hours_per_week_categories'] = pd.cut(df['hours-per-week'], cut_points, labels=label_names)

df.head()
```

      age
      workclass
      fnlwgt
      education
      education-num
      marital-status
      occupation
      relationship
      race
      sex
      capital-gain
      capital-loss
      hours-per-week
      country
      salary
      hours_per_week_categories

      0
      39
      State-gov
      77516
      Bachelors
      13
      Never-married
      Adm-clerical
      Not-in-family
      White
      Male
      2174
      0
      40
      United-States
      <=50K
      40-49

      1
      50
      Self-emp-not-inc
      83311
      Bachelors
      13
      Married-civ-spouse
      Exec-managerial
      Husband
      White
      Male
      0
      0
      13
      United-States
      <=50K
      10-19

      2
      38
      Private
      215646
      HS-grad
      9
      Divorced
      Handlers-cleaners
      Not-in-family
      White
      Male
      0
      0
      40
      United-States
      <=50K
      40-49

      3
      53
      Private
      234721
      11th
      7
      Married-civ-spouse
      Handlers-cleaners
      Husband
      Black
      Male
      0
      0
      40
      United-States
      <=50K
      40-49

      4
      28
      Private
      338409
      Bachelors
      13
      Married-civ-spouse
      Prof-specialty
      Wife
      Black
      Female
      0
      0
      40
      Cuba
      <=50K
      40-49

```
df['sex'].value_counts()
```

     Male      21790
     Female    10771
    Name: sex, dtype: int64

```
df['hours_per_week_categories'].value_counts()
```

    40-49    18336
    50+       6462
    30-39     3667
    20-29     2392
    10-19     1246
    0-9        458
    Name: hours_per_week_categories, dtype: int64

```
df = df.sort_values(by='hours_per_week_categories')

df.head()
```

      age
      workclass
      fnlwgt
      education
      education-num
      marital-status
      occupation
      relationship
      race
      sex
      capital-gain
      capital-loss
      hours-per-week
      country
      salary
      hours_per_week_categories

      31290
      55
      Self-emp-not-inc
      41938
      Bachelors
      13
      Married-civ-spouse
      Prof-specialty
      Wife
      White
      Female
      0
      0
      8
      United-States
      <=50K
      0-9

      5172
      32
      NaN
      134886
      HS-grad
      9
      Married-civ-spouse
      NaN
      Wife
      White
      Female
      0
      0
      2
      United-States
      >50K
      0-9

      22928
      17
      NaN
      332666
      10th
      6
      Never-married
      NaN
      Own-child
      White
      Female
      0
      0
      4
      United-States
      <=50K
      0-9

      7902
      35
      Private
      359131
      Bachelors
      13
      Married-civ-spouse
      Prof-specialty
      Wife
      White
      Female
      7298
      0
      8
      NaN
      >50K
      0-9

      6604
      41
      Private
      406603
      HS-grad
      9
      Never-married
      Other-service
      Not-in-family
      White
      Male
      0
      0
      6
      Iran
      <=50K
      0-9

```
contingency_table = pd.crosstab(df['sex'], df['hours_per_week_categories'], margins=True)

contingency_table
```

      hours_per_week_categories
      0-9
      10-19
      20-29
      30-39
      40-49
      50+
      All

      sex

      Female
      235
      671
      1287
      1914
      5636
      1028
      10771

      Male
      223
      575
      1105
      1753
      12700
      5434
      21790

      All
      458
      1246
      2392
      3667
      18336
      6462
      32561

```
femalecount = contingency_table.iloc[0][0:6].values
femalecount
```

    array([ 235,  671, 1287, 1914, 5636, 1028])

```
malecount = contingency_table.iloc[1][0:6].values
malecount
```

    array([  223,   575,  1105,  1753, 12700,  5434])

```
import matplotlib.pyplot as plt
import seaborn as sns

#plots the bar chart
fig = plt.figure(figsize=(10,5))
sns.set(font_scale=1.8)
categories = label_names
p1 = plt.bar(categories, malecount, .55, color='#d62728')
p2 = plt.bar(categories, femalecount, .55, bottom=malecount)
plt.legend((p2[0], p1[0]), ('Female', 'Male'))
plt.xlabel('Count')
plt.show()
```

##Expected Value Calculation

\begin{align}
expected_{i,j} =\frac{(row_{i} \text{total})(column_{j} \text{total}) }{(\text{total observations})}
\end{align}

```
#Get Row sums
row_sums = contingency_table.iloc[0:2, 6].values
col_sums = contingency_table.iloc[2, 0:6].values
print (row_sums)
print (col_sums)
```

    [10771 21790]
    [  458  1246  2392  3667 18336  6462]

```
total = contingency_table.loc['All', 'All']
total
```

    32561

```
len(df)
```

    32561

```
 df.shape[0]
```

    32561

```
expected = []
for i in range(len(row_sums)):
  expected_row = []
  for column in col_sums:
    expected_val = column*row_sums[i]/total
    expected_row.append(expected_val)
  expected.append(expected_row)

expected = np.array(expected)
print (expected.shape)
print (expected)
```

    (2, 6)
    [[  151.50388502   412.16995793   791.26046497  1213.02346365
       6065.44811277  2137.59411566]
     [  306.49611498   833.83004207  1600.73953503  2453.97653635
      12270.55188723  4324.40588434]]

```
observed = pd.crosstab(df['sex'], df['hours_per_week_categories']).values
print(observed.shape)
observed
```

    (2, 6)

    array([[  235,   671,  1287,  1914,  5636,  1028],
           [  223,   575,  1105,  1753, 12700,  5434]])

## Chi-Squared Statistic with Numpy

\begin{align}
\chi^2 = \sum \frac{(observed_{i}-expected_{i})^2}{(expected_{i})}
\end{align}

For the $observed$ values we will just use a version of our contingency table without the margins as a numpy array. In this way, if our observed values array and our expected values array are the same shape, then we can subtract them and divide them directly which makes the calculations a lot cleaner. No for loops!

```
chi_squared = ((observed - expected)**2/expected).sum()
print(f"Chi-Squared: {chi_squared}")
```

    Chi-Squared: 2287.190943926107

```
#Calculate Degrees of Freedom
dof = (len(row_sums) - 1) * (len(col_sums) - 1)
print(f"Degrees of Freedom: {dof}")
```

    Degrees of Freedom: 5

## Run a $\chi^{2}$ Test using Scipy

```
chi_squared, p_value, dof, expected = stats.chi2_contingency(observed)

print(f"Chi-Squared: {chi_squared}")
print(f"P-value: {p_value}")
print(f"Degrees of Freedom: {dof}")
print("Expected: \n", np.array(expected))
```

    Chi-Squared: 2287.190943926107
    P-value: 0.0
    Degrees of Freedom: 5
    Expected:
     [[  151.50388502   412.16995793   791.26046497  1213.02346365
       6065.44811277  2137.59411566]
     [  306.49611498   833.83004207  1600.73953503  2453.97653635
      12270.55188723  4324.40588434]]

### Conclusion
Based on a chi-squared statistic of 2287 and a p-value of 0. I reject the null hypothesis that hours_worked_per_week, and sex are independent, and suggest the alternative that there is an association between hours_worked_per_week and sex.


## You don't know what to choose between Matlab and Python :

# Try

# Play with the slides

https://mybinder.org/v2/gh/raphbacher/julia-intro/master?filepath=presentation_julia.ipynb

Sources:

https://github.com/raphbacher/julia-intro

# Outline

- State of the art : the two language problem
- What is Julia
- Why Julia is fast
- Julia Ecosystem & interop

## Matlab

Pros :
- Polished product with support
- Simulink
- High level syntax

Cons :
- Closed : not everyone has access to it, impossible to put a demonstrator online.
- Slow loops (better since 2015) : not everything is pretty once vectorized
- Not fast per se (Fortran bindings), memory management is difficult
- Not a generalist language (cumbersome to put a demo on the web e.g.)
- €€ each year for a lab

## Python

Pros :
- Free and open-source, generalist, widly used outside scientific community
- Lot of scientific communities are embracing it
- Lots of efforts to make it fast (numba, ...)

Cons :
- Scientific computing is not native :
    - all fallback to C/Fortran black-boxes -> limit flexibility
- Object Oriented paradigm can be cumbersome for scientific code

## Science and the two languages problem

Scientists need to easily explore new ideas :

- Need for mathematical abstractions
- Need for customizations (avoid black boxes, try variations)

- But also need for performance (intrinsic goal or to allow re-use)

What is done now (when you need to go further than using existing packages, for e.g. data analysis)

1) Prototyping in R/Python/Matlab

2) Rewriting whole or parts (if money/man power) to a performant low-level language as C/Fortran

# Yet another language

# Here comes Julia :

* innovative open-source generalist programming language with scientific computing at its core
* **easy as Matlab, fast as Fortran, flexible as Python, deep as LISP**
* leverages (for now...) major C/Fortran science packages, e.g. LAPACK, MPI, FFTW...
* 5th language to run at 1 petaflops (Celeste project), after assembly, Fortran, C, C++
* State of the art packages in Optimization (JUMP), Differential Equations (DifEq), ... Well positioned for ML (Flux, Knet, autodiff...)
* solves the "two-languages problem"

# Background

* origins at MIT, UCSB applied math & computer science, 2010
* founders Viral Shah, Jeff Bezanson, Stefan Karpinsky (now at Julia Computing LLC), Alan Edelman (MIT)
* ~10-person core language team, ~870 contributors, ~2500 registered packages
* support from Intel, Microsoft, Wall St., Moore Foundation, NumFocus
* julia-0.1 released in 2012, julia-1.0 in August 2018, now julia-1.2

**Its goal : Solve the two-languages problem by having a dynamic, high level language with good mathematical expressivity able to be as fast as C/Fortran.**

# Disclaimer

- I am not a Julia expert : I've been following the language for ~ two years and I am currently porting python research codes to Julia.
- Julia (like Python...) is not a drop-in replacement for Matlab, it is an alternative.
- Don't fix that ain't broken :
    - if Matlab/R/Python/C is good for you, no need to change
    - but if you are sometimes faced with some limitations of these languages, give Julia a try

# Julia: expressive as Matlab

Julia can as expressive as Matlab for interactive calculations with built-in numerical libraries and plotting. A few examples...

### Arrays

```julia
A = randn(4,4)       # 4 x 4 matrix of normally distributed random numbers
```

    4×4 Array{Float64,2}:
     -1.7897    -1.27394   -0.796802   -1.12804
     -0.843538  -0.607065   0.187264    0.0447423
     -0.83152   -0.483635   0.0594034  -0.607388
      0.194026   1.4971     0.533445   -0.379708

```julia
A[:,1]                # familiar colon syntax --extract first column of A
```

    4-element Array{Float64,1}:
     -1.7896952667660175
     -0.843538211646361
     -0.8315200775522081
      0.19402554880895634

## Linear Algebra

```julia
using LinearAlgebra
b = randn(4)
x = A\b               # solve Ax=b for x using backslash operator
norm(A*x-b)
```

    5.551115123125783e-16

```julia
U, σ, V = svd(A);     # singular value decomposition --note unicode variable name σ
```

```julia
Σ = diagm(0 => σ)
norm(A - U*Σ*V')      # compute error of SVD factorization A = U Σ V'
```

    8.164634113057559e-16

# Fast as Fortran

```julia
function loop()
    a=0
    for i in 1:1_000_000
        a+=1;
    end
end
@time loop() # compile time
@time loop() # now fast
```

      0.004979 seconds (20.83 k allocations: 1.173 MiB)
      0.000001 seconds (4 allocations: 160 bytes)

## Compare with Matlab (R2018)

*I know this is not Matlab-friendly, that's the point !*

    function [] = loop()
        a=0;
        for i=1:1000000
            a=i+1;
        end
    end

    f = @() loop();

    timeit(f) => 0.0018s

**1000x slower !**

### Benchmarks on common code pattterns

Takeaway: Julia timings are clustered around C timing, Matlab/Python/R orders of magnitude slower.

### KS-CNAB2 benchmark: CPU time versus lines of code

Takeaway: The Julia PDE code is almost as compact as Matlab/Python, almost as fast as C/Fortran.

## Julia: easy, dynamic, and fast. How?

 * **Just-in-time compilation** (JIT)
    - user-level code is compiled to machine code on-the-fly

 * **Meticulous type system**
    - designed to maximize impact of JIT
    - type inference: compiler determines types of variables

 * **Multiple dispatch**
    - functions are compiled for each set of argument types
    - function dispatch determined at compile time when possible, run time when not

**Just-in-time ahead-of-time compilation

Functions are compiled to machine code when first run. Subsequent runs are as fast as compiled C, C++, Fortran.
Not a tracing JIT (like pypy)

# Caveats

- It's a marathon not a sprint : Julia can be slow at first
- It's an open-source language with lots of good willing contributors, it's not a product (see JuliaPro...)
- If you directly translate from Matlab to Julia you will not always see an improvement, you have exploit Julia strengths (loops to avoid allocations, type stability, ...)

# A julia type

Like a C struct, or a Python object... but without methods

```julia
struct Spaceship
           speed::Float64
           Position::Array{Float64,2}
   end
```

## Multiple dispatch

```julia
collide(a::Asteroid, s::Spaceship) # a first method of the function collide
collide(s1::Spaceship, s2::Spaceship) # another method of the function collide
```

## The power of Multiple dispatch

Ref https://medium.com/@Jernfrost/defining-custom-units-in-julia-and-python-513c34a4c971

See also (very interesting!) : https://www.youtube.com/watch?v=kc9HwsxE1OY

```julia
abstract type Temperature end

struct Celsius <: Temperature
    value
end

struct Kelvin <: Temperature
   value::Float64
end

struct Fahrenheit <: Temperature
    value::Float64
end

import Base: promote_rule, convert
promote_rule(::Type{Kelvin}, ::Type{Celsius})     = Kelvin
promote_rule(::Type{Fahrenheit}, ::Type{Celsius}) = Celsius
promote_rule(::Type{Fahrenheit}, ::Type{Kelvin})  = Kelvin

convert(::Type{Kelvin},  t::Celsius)     = Kelvin(t.value + 273.15)
convert(::Type{Kelvin},  t::Fahrenheit)  = Kelvin(Celsius(t))
convert(::Type{Celsius}, t::Kelvin)      = Celsius(t.value - 273.15)
convert(::Type{Celsius}, t::Fahrenheit)  = Celsius((t.value - 32)*5/9)
convert(::Type{Fahrenheit}, t::Celsius)  = Fahrenheit(t.value*9/5 + 32)
convert(::Type{Fahrenheit}, t::Kelvin)   = Fahrenheit(Celsius(t))

import Base: +,-,*
+(x::T, y::T) where {T <: Temperature} = T(x.value + y.value)
-(x::T, y::T) where {T <: Temperature} = T(x.value - y.value)

+(x::Temperature, y::Temperature) = +(promote(x,y)...)
-(x::Temperature, y::Temperature) = -(promote(x,y)...)

*(x::Number, y::T) where {T <: Temperature} = T(x * y.value)

const °C = Celsius(1); const °F = Fahrenheit(1); const K = Kelvin(1);
```

```julia
1K+1°C
```

    Kelvin(275.15)

## Introspection
$$f(x) = 4\, x\, (1-x)$$

```julia
f(x) = 4x*(1-x)     # define logistic map
@time f(0.3);       # first run is slow
@time f(0.4);       # second run is a thousand times faster
```

      0.008778 seconds (18.00 k allocations: 1.003 MiB)
      0.000003 seconds (5 allocations: 176 bytes)

#### Observe the compilation of $f(x)$ by stages

user Julia -> generic Julia expression -> typed Julia expression -> intermediate compiler language -> machine code

```julia
include("macros.jl");
```

```julia
@code_lowered f(0.3)  # show f(x) as generic Julia expression
```

    CodeInfo(
    1 ─ %1 = 4 * x
    │   %2 = 1 - x
    │   %3 = %1 * %2
    └──      return %3
    )

```julia
@code_typed f(0.3)    # show f(x) as Julia expr with inferred types, based on the arg types
```

    CodeInfo(
    1 ─ %1 = (Base.mul_float)(4.0, x)::Float64
    │   %2 = (Base.sub_float)(1.0, x)::Float64
    │   %3 = (Base.mul_float)(%1, %2)::Float64
    └──      return %3
    ) => Float64

```julia
@code_llvm f(0.3)    # show f(x) in intermediate compiler language (LLVM)
```

    ;  @ In[9]:1 within `f'
    define double @julia_f_12939(double) {
    top:
    ; ┌ @ promotion.jl:314 within `*' @ float.jl:399
       %1 = fmul double %0, 4.000000e+00
    ; └
    ; ┌ @ promotion.jl:315 within `-' @ float.jl:397
       %2 = fsub double 1.000000e+00, %0
    ; └
    ; ┌ @ float.jl:399 within `*'
       %3 = fmul double %1, %2
    ; └
      ret double %3
    }

## Type inference and dispatch

We can see that if we call f on an Integer we get a code specialised for integer (i64)

```julia
@code_native f(0.3) # show f(x) in IA-64 assembly language
```

    	.text
    ; ┌ @ In[9]:1 within `f'
    	movabsq	$140409732451304, %rax  # imm = 0x7FB3B039CBE8
    ; │┌ @ promotion.jl:314 within `*' @ float.jl:399
    	vmulsd	(%rax), %xmm0, %xmm1
    	movabsq	$140409732451312, %rax  # imm = 0x7FB3B039CBF0
    ; │└
    ; │┌ @ promotion.jl:315 within `-' @ float.jl:397
    	vmovsd	(%rax), %xmm2           # xmm2 = mem[0],zero
    	vsubsd	%xmm0, %xmm2, %xmm0
    ; │└
    ; │┌ @ float.jl:399 within `*'
    	vmulsd	%xmm0, %xmm1, %xmm0
    ; │└
    	retq
    	nopw	%cs:(%rax,%rax)
    ; └

```julia
@code_native f(3)    # show f(x) in IA-64 assembly language
```

    	.text
    ; ┌ @ In[9]:1 within `f'
    ; │┌ @ In[9]:1 within `-'
    	movl	$1, %eax
    	subq	%rdi, %rax
    ; │└
    ; │┌ @ int.jl:54 within `*'
    	imulq	%rdi, %rax
    	shlq	$2, %rax
    ; │└
    	retq
    	nopw	%cs:(%rax,%rax)
    ; └

## Genericity
(from https://www.youtube.com/watch?v=kc9HwsxE1OY)

```julia
using LinearAlgebra

# First we write a generic function (that takes an array A and a list of vectors
# and sums the inner products of A and each vector)
function inner_sum(A,vs)
    t = zero(eltype(A))
    for v in vs
        t += inner(v,A,v)
    end
    return t
end

# we define the inner product used in our inner_sum function
inner(v,A,w) = dot(v,A*w)

## Now we want a new type, the famous One Hot Vector

import Base: *

struct OneHotVector <: AbstractVector{Bool}
  idx::UInt32
  len::UInt32
end

Base.size(xs::OneHotVector) = (Int64(xs.len),)
Base.getindex(xs::OneHotVector, i::Integer) = i == xs.idx
Base.getindex(xs::OneHotVector, ::Colon) = OneHotVector(xs.idx, xs.len)
```

```julia
# It works (generic) ! but it's slow
v = [OneHotVector(i,1000) for i in rand(1:1000,100)]
A=rand(1000,1000)

inner_sum(A,v)
@time inner_sum(A,v)

# And now specify to get speed !
A::AbstractMatrix * b::OneHotVector = A[:, b.idx]
inner(v::OneHotVector,A,w::OneHotVector) = A[v.idx,w.idx] # How to do that in single dispatch ??

inner_sum(A,v)
@time inner_sum(A,v)
```

      0.037617 seconds (105 allocations: 793.922 KiB)
      0.000003 seconds (5 allocations: 176 bytes)

    51.52316795511521

## From prototype to performance

```julia
a=rand(100_000_000)

function simple_sum(a)
    res = 0
    for i in eachindex(a)
        res += a[i]
    end
    return res
end

simple_sum(a)
@time simple_sum(a) # naive implementation

function simd_sum(a)
    res = zero(eltype(a)) # note the type instability of res=0
    @simd for i in eachindex(a)
        @inbounds res += a[i]
    end
    return res
end

simd_sum(a)
@time simd_sum(a)
sum(a)
@time sum(a)

using PyCall
np = pyimport("numpy")
np.sum(a)
@time np.sum(a)

using Test
@test np.sum(a)≈simd_sum(a)
```

      0.215574 seconds (5 allocations: 176 bytes)
      0.080315 seconds (5 allocations: 176 bytes)
      0.069825 seconds (5 allocations: 176 bytes)
      0.046125 seconds (15 allocations: 688 bytes)

    Test Passed

## An ecosystem of packages

- Most of packages are available on Github (easy collaboration)
- Main fields are grouped in Github Organizations (see https://julialang.org/community/)
- Julia comes with a powerful package/environment manager

```julia
using Pkg #load the Pkg stdlib
Pkg.activate(".") #activate the local environment
```

    "/home/raphael/Projets/Perso/tests-julia/julia-intro/Project.toml"

## Solving Differential Equations

 Solve the Lorenz equations:

$$
\begin{align}
\frac{dx}{dt} &= σ(y-x) \\
\frac{dy}{dt} &= x(ρ-z) - y \\
\frac{dz}{dt} &= xy - βz \\
\end{align}
$$

Fair Warning ⚠ : the next cell is gonna take some time. Like really. You can go grab a coffee.

This compilation time only occurs the first time you load this version of this package on your machine.
If you are trying this online on Mybinder, remember that each time you connect, you are on a fresh julia install
just built for you, so this precompilation time occurs. And Plots and DifferentialEquations are pretty big libraries (DifEq regroups a lot of solvers).

```julia
#Pkg.add("DifferentialEquations") # add the Differential equation suite
using DifferentialEquations # first time is very slow (precompilation)
using Plots
gr()
```

    Plots.GRBackend()

```julia
function lorenz(du,u,p,t)
 du[1] = 10.0*(u[2]-u[1])
 du[2] = u[1]*(28.0-u[3]) - u[2]
 du[3] = u[1]*u[2] - (8/3)*u[3]
end

u0 = [1.0;0.0;0.0] ; tspan = (0.0,100.0);
prob = ODEProblem(lorenz,u0,tspan)
sol = DifferentialEquations.solve(prob)
Plots.plot(sol,vars=(1,2,3))
```

## Optimization

```julia
using JuMP, GLPK, Test

"""
Formulate and solve a simple LP:
    max 5x + 3y
     st 1x + 5y <= 3
         0 <= x <= 2
         0 <= y <= 30
"""
function example_basic()
    model = Model(with_optimizer(GLPK.Optimizer))

    @variable(model, 0 <= x <= 2)
    @variable(model, 0 <= y <= 30)

    @objective(model, Max, 5x + 3y)
    @constraint(model, 1x + 5y <= 3.0)

    println(model)
    JuMP.optimize!(model)

    obj_value = JuMP.objective_value(model)
    x_value = JuMP.value(x)
    y_value = JuMP.value(y)

    println("Objective value: ", obj_value)
    println("x = ", x_value)
    println("y = ", y_value)
    @test obj_value ≈ 10.6
    @test x_value ≈ 2
    @test y_value ≈ 0.2

end

example_basic()

```

    ┌ Info: Precompiling GLPK [60bf3e95-4087-53dc-ae20-288a0d20c6a6]
    └ @ Base loading.jl:1186

    Max 5 x + 3 y
    Subject to
     x + 5 y ≤ 3.0
     x ≥ 0.0
     y ≥ 0.0
     x ≤ 2.0
     y ≤ 30.0

    Objective value: 10.6
    x = 2.0
    y = 0.2

    Test Passed

## Composability

See https://tutorials.juliadiffeq.org/html/type_handling/02-uncertainties.html

```julia
using DifferentialEquations, Measurements, Plots

g = 9.79 ± 0.02; # Gravitational constants
L = 1.00 ± 0.01; # Length of the pendulum

#Initial Conditions
u₀ = [0 ± 0, π / 60 ± 0.01] # Initial speed and initial angle
tspan = (0.0, 6.3)

#Define the problem
function simplependulum(du,u,p,t)
    θ  = u[1]
    dθ = u[2]
    du[1] = dθ
    du[2] = -(g/L)*θ
end

#Pass to solvers
prob = ODEProblem(simplependulum, u₀, tspan)
sol = DifferentialEquations.solve(prob, Tsit5(), reltol = 1e-6)

# Analytic solution
u = u₀[2] .* cos.(sqrt(g / L) .* sol.t)

plot(sol.t, getindex.(sol.u, 2), label = "Numerical")
plot!(sol.t, u, label = "Analytic")
```

## Automatic differentiation

```julia
#Pkg.add("ForwardDiff")
using ForwardDiff

# Define a function f
f(x::Vector) = sum(sin, x) + prod(tan, x) * sum(sqrt, x);

x = rand(5) # small size for example's sake

# Get the gradient of f
g = x -> ForwardDiff.gradient(f, x); # g = ∇f

@show g(x)

# Get the Hessian
ForwardDiff.hessian(f, x)

```

    g(x) = [2.57287, 2.51714, 2.3224, 1.87393, 1.8107]

    5×5 Array{Float64,2}:
     1.39246  4.80673  4.31075  3.52545  3.74384
     4.80673  1.37213  4.18168  3.41991  3.63178
     4.31075  4.18168  1.32308  3.06703  3.25711
     3.52545  3.41991  3.06703  1.78856  2.66366
     3.74384  3.63178  3.25711  2.66366  2.8778

# Deep learning

Classic MNIST number classification with Flux.jl

```julia
using Flux, Flux.Data.MNIST, Statistics
using Flux: onehotbatch, onecold, crossentropy, throttle
using Base.Iterators: repeated
# using CuArrays

# Classify MNIST digits with a simple multi-layer-perceptron

# Load images
imgs = MNIST.images()
# Stack images into one large batch
X = hcat(float.(reshape.(imgs, :))...) |> gpu

labels = MNIST.labels()
# One-hot-encode the labels
Y = onehotbatch(labels, 0:9) |> gpu

# Define the neural network (two Dense layers)
m = Chain(
  Dense(28^2, 32, relu),
  Dense(32, 10),
  softmax) |> gpu

# define loss function and metric
loss(x, y) = crossentropy(m(x), y)
accuracy(x, y) = mean(onecold(m(x)) .== onecold(y))

# create batches of 100
dataset = repeated((X, Y), 100)
# Define callback that show the current loss
evalcb = () -> @show(loss(X, Y))

opt = ADAM()

# Train
Flux.train!(loss, params(m), dataset, opt, cb = throttle(evalcb, 10))
@show accuracy(X, Y)
# Test set accuracy
tX = hcat(float.(reshape.(MNIST.images(:test), :))...) |> gpu
tY = onehotbatch(MNIST.labels(:test), 0:9) |> gpu
@show accuracy(tX, tY)
```

    loss(X, Y) = 2.2864406f0 (tracked)
    loss(X, Y) = 1.495227f0 (tracked)
    loss(X, Y) = 1.018613f0 (tracked)
    loss(X, Y) = 0.7433482f0 (tracked)
    loss(X, Y) = 0.60261893f0 (tracked)
    loss(X, Y) = 0.51817137f0 (tracked)
    loss(X, Y) = 0.46358913f0 (tracked)
    loss(X, Y) = 0.41939938f0 (tracked)
    loss(X, Y) = 0.39135918f0 (tracked)
    accuracy(X, Y) = 0.8994333333333333
    accuracy(tX, tY) = 0.9029

    0.9029

### Prediction

Predict the number for a given image

```julia
n = rand(1:length(MNIST.images(:test)))
print("Prediction:",argmax(tY[:,n])-1)
heatmap(MNIST.images(:test)[n])

```

    Prediction:5

## Deep learning + Autodiff

=> Scientific Machine learning

http://www.stochasticlifestyle.com/the-essential-tools-of-scientific-machine-learning-scientific-ml/

https://fluxml.ai/2019/03/05/dp-vs-rl.html

https://fluxml.ai/2019/02/07/what-is-differentiable-programming.html

https://www.youtube.com/watch?v=FGfx8CQHdQA

## Ecosystem

And much more :

- JuliaRobotics (real-time !)
- Stats/Machine Learning
- Web
- GPU
- ...

# Interop

Interop possible avec Python, Matlab, R, Java, C/Fortran,...

```julia
#Pkg.add("PyCall") # add python binding package

using PyCall
@pyimport math # import python math library
@show math.sin(math.pi / 4)
@show sin(pi / 4) ; #Julia native sinus function

```

    math.sin(math.pi / 4) = 0.7071067811865475
    sin(pi / 4) = 0.7071067811865475

```julia
# call C
t = ccall((:clock, "libc.so.6"), Int32, ())
```

    854653866

### Macros: code that transforms code

```julia
# @time macro inserts timing and memory profiling into expression, then evaluates, and prints
@time f(2//3)
```

      0.076290 seconds (114.51 k allocations: 6.258 MiB, 24.08% gc time)

    8//9

```julia
# @which macro determines which function is called, provides link to source code on GitHub
@which exp(π)
```

exp(x::Real) in Base.Math at special/exp.jl:73

```julia
@which exp(π*im)
```

exp(z::Complex) in Base at complex.jl:604

Macros enable run-time code generation and transformation.

Applications :

  * generation and execution of boilerplate code
  * run-time generation and optimization of algorithms, e.g. FFTW, ATLAS
  * symbolic mathematics, automatic differentiation
  * *all written like high-level Python, running like compiled C !!!*

## Parallelism in Julia: just change the array type

Some very trivial examples of Julia's built-in parallelism

```julia
using Distributed
#Pkg.add("DistributedArrays")
# add 4 process
addprocs(4);
```

```julia
; cat codes/count_heads.jl
```

    function count_heads(n)
        c::Int = 0
        for i=1:n
            c += rand(Bool)
        end
        c
    end

```julia
# define function on all process
@everywhere include("codes/count_heads.jl")

# dispatch two tasks
a = @spawn count_heads(10000000)
b = @spawn count_heads(10000000)
(fetch(a)+fetch(b))/20000000 # Get proba of drawing a head
```

    0.49999545

### Parallel loops with reduction

```julia
# distribute the simulation on all process and sum results
nheads = @distributed (+) for i=1:200000000
  Int(rand(Bool))
end
nheads/200000000
```

    0.499957515

And more :
- Distributed arrays
- GPUArrays
- TPUArrays ...
- Nested Threading (PARTR)

Just changing the behavior of the underlying structure can bring new hardware support for all packages

# Helpful materials

- Main site https://julialang.org/
- Docs https://docs.julialang.org/en/v1/
- Courses : https://juliaacademy.com/
- Forum https://discourse.julialang.org/
- Book https://benlauwens.github.io/ThinkJulia.jl/latest/book.html
- Blog http://www.stochasticlifestyle.com/
- All-in-one package : https://juliacomputing.com/products/juliapro.html
- Try online  : https://juliabox.com/

# Code as a first-class citizen product of research

- The (new version) Julia package manager has reproductibility at its core (each code project is linked to a deterministic set of dependencies)
- Creating a Julia package comes with tools for documentation, unit testing, continuous integration
- New scientific collaborations can be based on software (see the Github organizations such as JuliaDiff, JuliaStats, etc...)

# Food for thoughts

- Cost and open source
    - Matlab licences cost several 10K€ each year to some labs
    - Julia (and Python and R) come for free but development is not free
    - A part of Matlab costs could go to financing open source software that is critical for science (see e.g. https://bitbucket.org/paugier/etude-asso-pynumfr/src/default/etude_asso_python_sciences_fr.rst?fileviewer=file-view-default)
- The combo C(++) low-level libraries and high level bindings (as Tensorflow, Keras...) lead to black box workflows...

# Conclusions

Julia
* **Easy as Matlab, fast as Fortran, flexible as Python, deep as Lisp**
*  Scientific computing, from interactive exploration to HPC
*  Paradigms (multiple dispatch) that enforce collaboration

Not covered
* large-scale programming, development ecosystem, environments, debuggers, etc.
* Abstract Types, compositions, ...
* rough edges: plotting, static compilation  (not quite there), package loading times, young 1.x

*Thanks* : the Julia community for most of the examples, xkcd

Julia website: http://www.julialang.org, this talk: https://github.com/raphbacher/julia-intro


# Analysis tools

Before we start, we copy the atmospheric setup case from the ["Getting Started"](getting_started.html) example:

First setting up the Radtrans object:

```python
import numpy as np
from petitRADTRANS import Radtrans

atmosphere = Radtrans(line_species = ['H2O', 'CO_all_iso', 'CH4', 'CO2', 'Na', 'K'], \
      rayleigh_species = ['H2', 'He'], \
      continuum_opacities = ['H2-H2', 'H2-He'], \
      wlen_bords_micron = [0.3, 15])

pressures = np.logspace(-6, 2, 100)
atmosphere.setup_opa_structure(pressures)
```

      Read CIA opacities for H2-H2...
      Read CIA opacities for H2-He...
     Done.

**Units in petitRADTRANS:** remember that all units in *petitRADTRANS* are in cgs, **except for pressure**, which is in bars, **and the mean molecular weight (MMW)**, which is in units of atomic mass units.

And the atmospheric parameters:

```python
from petitRADTRANS import nat_cst as nc
R_pl = 1.838*nc.r_jup_mean
gravity = 1e1**2.45
P0 = 0.01

kappa_IR = 0.01
gamma = 0.4
T_int = 200.
T_equ = 1500.
temperature = nc.guillot_global(pressures, kappa_IR, gamma, gravity, T_int, T_equ)

mass_fractions = {}
mass_fractions['H2'] = 0.74 * np.ones_like(temperature)
mass_fractions['He'] = 0.24 * np.ones_like(temperature)
mass_fractions['H2O'] = 0.001 * np.ones_like(temperature)
mass_fractions['CO_all_iso'] = 0.01 * np.ones_like(temperature)
mass_fractions['CO2'] = 0.00001 * np.ones_like(temperature)
mass_fractions['CH4'] = 0.000001 * np.ones_like(temperature)
mass_fractions['Na'] = 0.00001 * np.ones_like(temperature)
mass_fractions['K'] = 0.000001 * np.ones_like(temperature)

MMW = 2.33 * np.ones_like(temperature)
```

**Abundances in petitRADTRANS:** remember that abundances in petitCODE are in units of **mass fractions**, not number fractions (aka volume mixing ratio, VMR). You can convert between mass fractions and VMRs by using
\begin{equation}
X_i = \frac{\mu_i}{\mu}n_i,
\end{equation}
where $X_i$ is the mass fraction of species $i$, $\mu_i$ the mass of a single molecule/atom/ion/... of species $i$, $\mu$ is the atmospheric mean molecular weight, and $n_i$ is the VMR of species $i$.

## Transmission contribution functions

We calculate the transmission spectrum in the usual way, this time setting the ``contribution = True`` keyword argument, however. This will additionally measure the contribution of the different layers, by calculating as many transmission spectra as there are layers, iteratively turning off the opacity in one layer only. The difference to the nominal transmission spectrum then measures the influence of the respective layers. Note that calculating the contribution function will increase the computation time considerably. We plan to improve the calculation speed of the contribution function soon. The formal definition of the contribution function is (also see Mollière et al., in prep.):

\begin{equation}
C_{\rm tr}^{i} = \frac{R_{\rm nom}^2-R^2(\kappa_i=0)}{\sum_{j=1}^{N_{\rm L}}\left[R_{\rm nom}^2-R^2(\kappa_j=0)\right]},
\end{equation}

where $R_{\rm nom}$ is the nominal transmission radius of the planet and $R(\kappa_i=0)$ is the transmission radius obtained from setting the opacity in the $i$th layer to zero. $N_{\rm L}$ is the number of atmospheric layers.

Now, to the contribution function calculation:

```python
atmosphere.calc_transm(temperature, mass_fractions, \
                       gravity, MMW, R_pl=R_pl, P0_bar=P0, \
                       contribution = True)
```

The transmission contribution function is plotted below, one can see that pressures above 0.5 bar cannot be probed in the wavelength range studied here.

```python
import pylab as plt
plt.rcParams['figure.figsize'] = (10, 6)

wlen_mu = nc.c/atmosphere.freq/1e-4
X, Y = np.meshgrid(wlen_mu, pressures)
plt.contourf(X,Y,atmosphere.contr_tr,30,cmap=plt.cm.bone_r)

plt.yscale('log')
plt.xscale('log')
plt.ylim([1e2,1e-6])
plt.xlim([np.min(wlen_mu),np.max(wlen_mu)])

plt.xlabel('Wavelength (microns)')
plt.ylabel('P (bar)')
plt.title('Transmission contribution function')
plt.show()
plt.clf()
```

## Emission contribution functions

Below, we show the same for the emission contribution functions, which are defined in the usual way, that is measuring the fraction of flux a layer contributes to the total flux, at a given wavelength. The computational time is comparable to a normal emission spectrum.

```python
atmosphere.calc_flux(temperature, mass_fractions, \
                       gravity, MMW, \
                       contribution = True)
```

The emission contribution function is plotted below, one can see that pressures that pressures larger than 1 bar can now be probed.

```python
import pylab as plt
plt.rcParams['figure.figsize'] = (10, 6)

wlen_mu = nc.c/atmosphere.freq/1e-4
X, Y = np.meshgrid(wlen_mu, pressures)
plt.contourf(X,Y,atmosphere.contr_em,30,cmap=plt.cm.bone_r)

plt.yscale('log')
plt.xscale('log')
plt.ylim([1e2,1e-6])
plt.xlim([np.min(wlen_mu),np.max(wlen_mu)])

plt.xlabel('Wavelength (microns)')
plt.ylabel('P (bar)')
plt.title('Emission contribution function')
plt.show()
plt.clf()
```

One also sees that scattering is not included in the pRT emission spectrum here, blueward of the strong alkali lines in the optical, quite large pressures can be probed. Conversely, in the transmission contribution plot above, the Rayleigh scattering is clearly visible. Hence, we will turn on scattering in the calculation below to show its impact on the spectra.

**Scattering and petitRADTRANS:** remember that scattering is included for emission spectra in petitRADTRANS only if requested specifically when generating the Radtrans object, as it increases the runtime (see ["Scattering for Emission Spectra"](emis_scat.html) for an example how to do this).

First we reload the pRT object with scattering turned on:

```python
atmosphere = Radtrans(line_species = ['H2O', 'CO_all_iso', 'CH4', 'CO2', 'Na', 'K'], \
      rayleigh_species = ['H2', 'He'], \
      continuum_opacities = ['H2-H2', 'H2-He'], \
      wlen_bords_micron = [0.3, 15], \
      do_scat_emis = True)

pressures = np.logspace(-6, 2, 100)
atmosphere.setup_opa_structure(pressures)
```

      Read CIA opacities for H2-H2...
      Read CIA opacities for H2-He...
     Done.

Now we recalculate and plot the emission contribution function:

```python
atmosphere.calc_flux(temperature, mass_fractions, \
                       gravity, MMW, \
                       contribution = True)

import pylab as plt
plt.rcParams['figure.figsize'] = (10, 6)

wlen_mu = nc.c/atmosphere.freq/1e-4
X, Y = np.meshgrid(wlen_mu, pressures)
plt.contourf(X,Y,atmosphere.contr_em,30,cmap=plt.cm.bone_r)

plt.yscale('log')
plt.xscale('log')
plt.ylim([1e2,1e-6])
plt.xlim([np.min(wlen_mu),np.max(wlen_mu)])

plt.xlabel('Wavelength (microns)')
plt.ylabel('P (bar)')
plt.title('Emission contribution function, *with* scattering')
plt.show()
plt.clf()
```

As can be seen, the Rayleigh scattering contribution to the emitted flux leaving the atmosphere is clearly visible now.