# Lambda School Data Science Module 142
## 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=14.975113494112255, pvalue=0.0005600095353013921)

```
# 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.

## Live Lecture - let's explore some more of scipy.stats

Candidate topics to explore:

- `scipy.stats.chi2` - the Chi-squared distribution, which we can use to reproduce the Chi-squared test
- Calculate the Chi-Squared test statistic "by hand" (with code), and feed it into `chi2`
- Build a confidence interval with `stats.t.ppf`, the t-distribution percentile point function (the inverse of the CDF) - we can write a function to return a tuple of `(mean, lower bound, upper bound)` that you can then use for the assignment (visualizing confidence intervals)

```
import pandas as pd
import numpy as np
from scipy import stats

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

    (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

      5
      37
      Private
      284582
      Masters
      14
      Married-civ-spouse
      Exec-managerial
      Wife
      White
      Female
      0
      0
      40
      United-States
      <=50K

      6
      49
      Private
      160187
      9th
      5
      Married-spouse-absent
      Other-service
      Not-in-family
      Black
      Female
      0
      0
      16
      Jamaica
      <=50K

      7
      52
      Self-emp-not-inc
      209642
      HS-grad
      9
      Married-civ-spouse
      Exec-managerial
      Husband
      White
      Male
      0
      0
      45
      United-States
      >50K

      8
      31
      Private
      45781
      Masters
      14
      Never-married
      Prof-specialty
      Not-in-family
      White
      Female
      14084
      0
      50
      United-States
      >50K

      9
      42
      Private
      159449
      Bachelors
      13
      Married-civ-spouse
      Exec-managerial
      Husband
      White
      Male
      5178
      0
      40
      United-States
      >50K

      10
      37
      Private
      280464
      Some-college
      10
      Married-civ-spouse
      Exec-managerial
      Husband
      Black
      Male
      0
      0
      80
      United-States
      >50K

      11
      30
      State-gov
      141297
      Bachelors
      13
      Married-civ-spouse
      Prof-specialty
      Husband
      Asian-Pac-Islander
      Male
      0
      0
      40
      India
      >50K

      12
      23
      Private
      122272
      Bachelors
      13
      Never-married
      Adm-clerical
      Own-child
      White
      Female
      0
      0
      30
      United-States
      <=50K

      13
      32
      Private
      205019
      Assoc-acdm
      12
      Never-married
      Sales
      Not-in-family
      Black
      Male
      0
      0
      50
      United-States
      <=50K

      14
      40
      Private
      121772
      Assoc-voc
      11
      Married-civ-spouse
      Craft-repair
      Husband
      Asian-Pac-Islander
      Male
      0
      0
      40
      NaN
      >50K

      15
      34
      Private
      245487
      7th-8th
      4
      Married-civ-spouse
      Transport-moving
      Husband
      Amer-Indian-Eskimo
      Male
      0
      0
      45
      Mexico
      <=50K

      16
      25
      Self-emp-not-inc
      176756
      HS-grad
      9
      Never-married
      Farming-fishing
      Own-child
      White
      Male
      0
      0
      35
      United-States
      <=50K

      17
      32
      Private
      186824
      HS-grad
      9
      Never-married
      Machine-op-inspct
      Unmarried
      White
      Male
      0
      0
      40
      United-States
      <=50K

      18
      38
      Private
      28887
      11th
      7
      Married-civ-spouse
      Sales
      Husband
      White
      Male
      0
      0
      50
      United-States
      <=50K

      19
      43
      Self-emp-not-inc
      292175
      Masters
      14
      Divorced
      Exec-managerial
      Unmarried
      White
      Female
      0
      0
      45
      United-States
      >50K

```
df.isnull().sum()
```

    age                  0
    workclass         1836
    fnlwgt               0
    education            0
    education-num        0
    marital-status       0
    occupation        1843
    relationship         0
    race                 0
    sex                  0
    capital-gain         0
    capital-loss         0
    hours-per-week       0
    country            583
    salary               0
    dtype: int64

```
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

```
df['hours-per-week']
```

```
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'].iloc[0]
```

    ' Male'

```
df['hours_per_week_categories'].iloc[0]
```

    '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', ascending=True)

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 = ["0-9","10-19","20-29","30-39","40-49","50+"]
p1 = plt.bar(categories, malecount, 0.55, color='#d62728')
p2 = plt.bar(categories, femalecount, 0.55, bottom=malecount)
plt.legend((p2[0], p1[0]), ('Male', 'Female'))
plt.xlabel('Hours per Week Worked')
plt.ylabel('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

```
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)

print(np.array(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]]

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

    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

```
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]]

# Confidence Interval Example

```
#confidence_interval = [lower_bound, upper_bound]

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

    [1 1 0 0 1 1 1 1 0 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0
     0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 0 0 0 1 1 0 1 0 1 0 0 0 1 0 0 0 0 0 1 1
     0 1 1 1 1 0 0 1 0 1 1 1 1 0 1 1 1 1 0 0 1 1 0 0 1 1]

```
coinflips.mean()
```

    0.52

```
stats.ttest_1samp(coinflips, .5)
```

    Ttest_1sampResult(statistic=0.39831375340784614, pvalue=0.6912566363051549)

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

print("100 Coinflips Mean:", coinflips_100.mean())
print("1000 Coinflips Mean:", coinflips_1000.mean())

print("100 Coinflips Standard Deviation:", np.std(coinflips_100))
print("1000 Coinflips Standard Deviation:", np.std(coinflips_1000))
```

    100 Coinflips Mean: 0.57
    1000 Coinflips Mean: 0.488
    100 Coinflips Standard Deviation: 0.4950757517794625
    1000 Coinflips Standard Deviation: 0.49985597925802594

```
print("100 Coinflips Standard Error:", stats.sem(coinflips_100))
print("1000 Coinflips Standard :", stats.sem(coinflips_1000))
```

    100 Coinflips Standard Error: 0.0497569851956243
    1000 Coinflips Standard : 0.01581474331458169

```
0.4950757517794625/np.sqrt(100-1)
```

    0.0497569851956243

```
0.49985597925802594/np.sqrt(1000-1)
```

    0.015814743314581686

## Confidence Interval Equation

```
# Confidence intervals!
# Similar to hypothesis testing, but centered at sample mean
# Generally better than reporting the "point estimate" (sample mean)
# Why? Because point estimates aren't always perfect

import numpy as np
from scipy import stats

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)
  n = len(data)
  stderr = stats.sem(data)
  interval = stderr * stats.t.ppf((1 + confidence) / 2.0, n - 1)
  return (mean, mean - interval, mean + interval)

def report_confidence_interval(confidence_interval):
  """
  Return a string with a pretty report of a confidence interval.

  Arguments:
    confidence_interval - tuple of (mean, lower bound, upper bound)

  Returns:
    None, but prints to screen the report
  """
  #print('Mean: {}'.format(confidence_interval[0]))
  #print('Lower bound: {}'.format(confidence_interval[1]))
  #print('Upper bound: {}'.format(confidence_interval[2]))
  s = "our mean lies in the interval [{:.5}, {:.5}]".format(
      confidence_interval[1], confidence_interval[2])
  return s
```

```
report_confidence_interval(confidence_interval(coinflips_100))
```

    'our mean lies in the interval [0.47, 0.67]'

```
report_confidence_interval(confidence_interval(coinflips_1000))
```

    'our mean lies in the interval [0.46, 0.52]'

```
stats.t.ppf(0.05, 5) # p-value, dof
```

    -2.0150483726691575

```
coinflips_1M = np.random.binomial(n=1, p=.5, size=1000000)
report_confidence_interval(confidence_interval(coinflips_1M))
```

    'our mean lies in the interval [0.49912, 0.50108]'

## Assignment - Build a confidence interval

A confidence interval refers to a neighborhood around some point estimate, the size of which is determined by the desired p-value. For instance, we might say that 52% of Americans prefer tacos to burritos, with a 95% confidence interval of +/- 5%.

52% (0.52) is the point estimate, and +/- 5% (the interval $[0.47, 0.57]$) is the confidence interval. "95% confidence" means a p-value $\leq 1 - 0.95 = 0.05$.

In this case, the confidence interval includes $0.5$ - which is the natural null hypothesis (that half of Americans prefer tacos and half burritos, thus there is no clear favorite). So in this case, we could use the confidence interval to report that we've failed to reject the null hypothesis.

But providing the full analysis with a confidence interval, including a graphical representation of it, can be a helpful and powerful way to tell your story. Done well, it is also more intuitive to a layperson than simply saying "fail to reject the null hypothesis" - it shows that in fact the data does *not* give a single clear result (the point estimate) but a whole range of possibilities.

How is a confidence interval built, and how should it be interpreted? It does *not* mean that 95% of the data lies in that interval - instead, the frequentist interpretation is "if we were to repeat this experiment 100 times, we would expect the average result to lie in this interval ~95 times."

For a 95% confidence interval and a normal(-ish) distribution, you can simply remember that +/-2 standard deviations contains 95% of the probability mass, and so the 95% confidence interval based on a given sample is centered at the mean (point estimate) and has a range of +/- 2 (or technically 1.96) standard deviations.

Different distributions/assumptions (90% confidence, 99% confidence) will require different math, but the overall process and interpretation (with a frequentist approach) will be the same.

Your assignment - using the data from the prior module ([congressional voting records](https://archive.ics.uci.edu/ml/datasets/Congressional+Voting+Records)):

1. Generate and numerically represent a confidence interval
2. Graphically (with a plot) represent the confidence interval
3. Interpret the confidence interval - what does it tell you about the data and its distribution?

Stretch goals:

1. Write a summary of your findings, mixing prose and math/code/results. *Note* - yes, this is by definition a political topic. It is challenging but important to keep your writing voice *neutral* and stick to the facts of the data. Data science often involves considering controversial issues, so it's important to be sensitive about them (especially if you want to publish).
2. Apply the techniques you learned today to your project data or other data of your choice, and write/discuss your findings here.
3. Refactor your code so it is elegant, readable, and can be easily run for all issues.

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

```
congress_data = 'https://archive.ics.uci.edu/ml/machine-learning-databases/voting-records/house-votes-84.data'
congress = pd.read_csv(congress_data, names=columns)

```

```
columns = ['party','handicapped-infants'
     ,'water-project-cost-sharing'
     ,'adoption-of-the-budget-resolution'
     ,'physician-fee-freeze'
     ,'el-salvador-aid'
     ,'religious-groups-in-schools'
     ,'anti-satellite-test-ban'
     ,'aid-to-nicaraguan-contras'
     ,'mx-missile'
     ,'immigration'
     ,'synfuels-corporation-cutback'
     ,'education-spending'
     ,'superfund-right-to-sue'
     ,'crime'
     ,'duty-free-exports'
     ,'export-administration-act-south-africa']
```

```
congress.head()
```

      party
      handicapped-infants
      water-project-cost-sharing
      adoption-of-the-budget-resolution
      physician-fee-freeze
      el-salvador-aid
      religious-groups-in-schools
      anti-satellite-test-ban
      aid-to-nicaraguan-contras
      mx-missile
      immigration
      synfuels-corporation-cutback
      education-spending
      superfund-right-to-sue
      crime
      duty-free-exports
      export-administration-act-south-africa

      0
      republican
      n
      y
      n
      y
      y
      y
      n
      n
      n
      y

      y
      y
      y
      n
      y

      1
      republican
      n
      y
      n
      y
      y
      y
      n
      n
      n
      n
      n
      y
      y
      y
      n

      2
      democrat

      y
      y

      y
      y
      n
      n
      n
      n
      y
      n
      y
      y
      n
      n

      3
      democrat
      n
      y
      y
      n

      y
      n
      n
      n
      n
      y
      n
      y
      n
      n
      y

      4
      democrat
      y
      y
      y
      n
      y
      y
      n
      n
      n
      n
      y

      y
      y
      y
      y

```
congress.head(2)
```

```
congress = congress.sort_values(by='', ascending=True)

congress.head()
```

```
congress[columns] = congress[columns].replace({"?": " "})
```

```
congress[columns] = congress[columns].replace({"y": 1, "n": 0})
```

```
congress.head()
```

      party
      handicapped-infants
      water-project-cost-sharing
      adoption-of-the-budget-resolution
      physician-fee-freeze
      el-salvador-aid
      religious-groups-in-schools
      anti-satellite-test-ban
      aid-to-nicaraguan-contras
      mx-missile
      immigration
      synfuels-corporation-cutback
      education-spending
      superfund-right-to-sue
      crime
      duty-free-exports
      export-administration-act-south-africa

      0
      republican
      0
      1
      0
      1
      1
      1
      0
      0
      0
      1

      1
      1
      1
      0
      1

      1
      republican
      0
      1
      0
      1
      1
      1
      0
      0
      0
      0
      0
      1
      1
      1
      0

      2
      democrat

      1
      1

      1
      1
      0
      0
      0
      0
      1
      0
      1
      1
      0
      0

      3
      democrat
      0
      1
      1
      0

      1
      0
      0
      0
      0
      1
      0
      1
      0
      0
      1

      4
      democrat
      1
      1
      1
      0
      1
      1
      0
      0
      0
      0
      1

      1
      1
      1
      1

let's see if party is important for who supports the education spending bill

```
continge_table = pd.crosstab(congress['party'], congress['education-spending'], margins=True)
```

```
contingency = (continge_table)
contingency
```

      education-spending

      n
      y
      All

      party

      democrat
      18
      213
      36
      267

      republican
      13
      20
      135
      168

      All
      31
      233
      171
      435

```
repcount = contingency.iloc[1][0:4].values
repcount
```

    array([ 13,  20, 135, 168])

```
demcount = contingency.iloc[0][0:4].values
demcount
```

    array([ 18, 213,  36, 267])

```
contingencyedit = contingency.
```

```
no = contingency['n']
no
```

    party
    democrat      213
    republican     20
    All           233
    Name: n, dtype: int64

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

fig = plt.figure(figsize=(10, 4))
sns.set(font_scale=1.8)
p1 = plt.bar(yes, demcount, 0.55, color='#d62728')
p2 = plt.bar(yes, repcount, 0.55, bottom=demcount)
plt.legend((p2[0], p1[0]), ('Democrat', 'Republican'))
plt.xlabel('Support for the Education Bill')
plt.ylabel('Count')
plt.show()
```

```
fig = plt.figure(figsize=(10, 4))
sns.set(font_scale=1.2)
contingency.plot.bar(stacked=True)
plt.legend(title='vote')

plt.show()
```

## Resources

- [Interactive visualize the Chi-Squared test](https://homepage.divms.uiowa.edu/~mbognar/applets/chisq.html)
- [Calculation of Chi-Squared test statistic](https://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test)
- [Visualization of a confidence interval generated by R code](https://commons.wikimedia.org/wiki/File:Confidence-interval.svg)
- [Expected value of a squared standard normal](https://math.stackexchange.com/questions/264061/expected-value-calculation-for-squared-normal-distribution) (it's 1 - which is why the expected value of a Chi-Squared with $n$ degrees of freedom is $n$, as it's the sum of $n$ squared standard normals)


---
layout: page
title: Verossimilhança
nav_order: 16
---

[](https://colab.research.google.com/github/icd-ufmg/icd-ufmg.github.io/blob/master/_lessons/16-vero.ipynb)

# Verossimilhança

{: .no_toc .mb-2 }

Entendimento de relação entre dados.
{: .fs-6 .fw-300 }

{: .no_toc .text-delta }
Resultados Esperados

1. Revisitar os mínimos quadrados (ALC)
1. Entender a regressão linear do ponto de vista probabilístico
1. Entender o conceito de verossimilhança

---
**Sumário**
1. TOC
{:toc}
---

```python
# -*- coding: utf8

from scipy import stats as ss

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

```python
plt.style.use('seaborn-colorblind')
plt.rcParams['figure.figsize']  = (16, 10)
plt.rcParams['axes.labelsize']  = 20
plt.rcParams['axes.titlesize']  = 20
plt.rcParams['legend.fontsize'] = 20
plt.rcParams['xtick.labelsize'] = 20
plt.rcParams['ytick.labelsize'] = 20
plt.rcParams['lines.linewidth'] = 4
```

```python
plt.ion()
```

```python
def despine(ax=None):
    if ax is None:
        ax = plt.gca()
    # Hide the right and top spines
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)

    # Only show ticks on the left and bottom spines
    ax.yaxis.set_ticks_position('left')
    ax.xaxis.set_ticks_position('bottom')
```

## Introdução

Continuando da aula passada. Vamos ver mais uma forma de entender um modelo de regressão linear. Lembre-se até agora falamos de correlação e covariância cobrindo os seguintes tópicos:

1. Covariância
1. Coeficiente de Pearson (Covariância Normalizada)
1. Coeficiente de Pearson como sendo a fração do desvio de y capturado por x
1. Mínimos Quadrados

Todos os passos acima chegam no mesmo local de traçar a "melhor" reta no gráfico de dispersão. Melhor aqui significa a reta que que minimiza o erro abaixo:

$$\Theta = [\alpha, \beta]$$
$$L(\Theta) = \sum_i (y_i - \hat{y}_i)^2$$
$$L(\Theta) = \sum_i (y_i - \beta x_i + \alpha)^2$$

Chegamos em:

\begin{align}
 \alpha & = \bar{y} - \beta\,\bar{x}, \\[5pt]
  \beta &= \frac{ \sum_{i=1}^n (x_i - \bar{x})(y_i - \bar{y}) }{ \sum_{i=1}^n (x_i - \bar{x})^2 } \\[6pt]
            &= \frac{ \operatorname{Cov}(x, y) }{ \operatorname{Var}(x) } \\[5pt]
            &= r_{xy} \frac{s_y}{s_x}. \\[6pt]
\end{align}

## Visão probabílistica

Vamos aprender uma última forma de pensar na regressão. Em particular, vamos fazer uso de uma visão probabílistica. Para tal, exploraremos o caso dos apartamentos de BH abaixo.

Inicialmente, vamos observar os dados além do resultado da melhor regressão.

```python
df = pd.read_csv('https://raw.githubusercontent.com/icd-ufmg/material/master/aulas/17-Verossimilhanca/aptosBH.txt', index_col=0)
df['preco'] = df['preco'] / 1000
plt.scatter(df['area'], df['preco'], edgecolors='k', s=80, alpha=0.6)
plt.title('Preco de Apartamentos em BH')
plt.ylabel(r'Preço * $10^3$ (R\$)')
plt.xlabel(r'Área ($M^2$)')
despine()
```

O seaborn tem uma função regplot que plota a melhor reta além de um IC (estmado via bootstrap -- aula passada).

```python
sns.regplot(x='area', y='preco', data=df, n_boot=10000,
            line_kws={'color':'magenta', 'lw':4},
            scatter_kws={'edgecolor':'k', 's':80, 'alpha':0.8})
plt.title('Preco de Apartamentos em BH')
plt.ylabel(r'Preço * $10^3$ (R\$)')
plt.xlabel(r'Área ($M^2$)')
despine()
```

A reta pode ser recuperada usando scipy.

```python
model = ss.linregress(df['area'], df['preco'])
# beta = slope
# alpha = intercept
model
```

    LinregressResult(slope=3.5357191563336516, intercept=200.5236136898945, rvalue=0.694605637960645, pvalue=1.917920339304322e-32, stderr=0.2503210673009473)

Usando esta reta podemos prever o preço de um apartamento usando apenas a área do mesmo.

```python
beta = model.slope
alpha = model.intercept
novo_apt_area = 225
preco = beta * novo_apt_area + alpha
preco
```

    996.0604238649662

Ou seja, quando um apartamento de 225m2 entra no mercado o mesmo custa em torno de 1M de reais.

## Erros Normais

Agora, será que conseguimos chegar no mesmo pensando na regressão como um modelo probabilístico?

[Discussão nos Slides](https://docs.google.com/presentation/d/1nSmN9ch1x6ABczaAzB292XgTqbXcIo1UIX1xjCrF1d8/edit#slide=id.g5a114266c3_0_26)

```python
x = np.linspace(-5, 5, 100)
plt.plot(x, ss.distributions.norm.pdf(x, scale=1))
plt.xlabel(r'$\epsilon_i$')
plt.ylabel(r'$p(\epsilon_i \mid \mu=0, \sigma=1)$')

despine()
```

```python
beta = 1
alpha = 1

fig = plt.figure(figsize=(36, 10))

x = np.array([2, 8, 5])
y = np.array([0, 1, 3])

plt.subplot(121)
plt.scatter(x, y, edgecolors='k', s=80, alpha=0.6)
plt.title('3 Pontinhos')
plt.ylabel(r'Y')
plt.xlabel(r'X')

y_bar = x * beta + alpha
plt.plot(x, y_bar, color='magenta')

y_min = [min(y_i, y_bar_i) for y_i, y_bar_i in zip(y, y_bar)]
y_max = [max(y_i, y_bar_i) for y_i, y_bar_i in zip(y, y_bar)]
plt.vlines(x, ymin=y_min, ymax=y_max, color='magenta', lw=1)

despine()

plt.subplot(122)
plt.title('PDF da Normal')
ei_x = np.linspace(-10, 10, 100)
sigma = (y - y_bar).std(ddof=1)
plt.plot(ei_x, ss.distributions.norm.pdf(ei_x, scale=sigma))
plt.xlabel(r'$\epsilon_i$')
plt.ylabel(r'$p(\epsilon_i \mid \mu=0, \sigma={})$'.format(np.round(sigma, 2)))
despine()
```

```python
beta = 3.535719156333653
alpha = 200.52361368989432

fig = plt.figure(figsize=(36, 10))

x = df['area']
y = df['preco']

plt.subplot(121)
plt.scatter(x, y, edgecolors='k', s=80, alpha=0.6)
plt.title('Preco de Apartamentos em BH')
plt.ylabel(r'Preço * $10^3$ (R\$)')
plt.xlabel(r'Área ($M^2$)')

y_bar = x * beta + alpha
plt.plot(x, y_bar, color='magenta')

y_min = [min(y_i, y_bar_i) for y_i, y_bar_i in zip(y, y_bar)]
y_max = [max(y_i, y_bar_i) for y_i, y_bar_i in zip(y, y_bar)]
plt.vlines(x, ymin=y_min, ymax=y_max, color='magenta', lw=1)

despine()

plt.subplot(122)
plt.title('PDF da Normal')
ei_x = np.linspace(-1000, 1000, 100)
sigma = (y - y_bar).std(ddof=1)
plt.plot(ei_x, ss.distributions.norm.pdf(ei_x, scale=sigma))
plt.xlabel(r'$\epsilon_i$')
plt.ylabel(r'$p(\epsilon_i \mid \mu=0, \sigma={})$'.format(np.round(sigma, 2)))
despine()
```

```python
sns.residplot(x='area', y='preco', data=df,
              line_kws={'color':'magenta', 'lw':4},
              scatter_kws={'edgecolor':'k', 's':80, 'alpha':0.8})
plt.ylabel(r'$\epsilon_i$')
plt.xlabel(r'Área ($M^2$)')
despine()
```

```python
ss.probplot(y - y_bar, plot=plt.gca());
```

## Close Nova Dataset

Abaixo temos a dispersão dos dados

```python
df = pd.read_csv('https://media.githubusercontent.com/media/icd-ufmg/material/master/aulas/17-Verossimilhanca/close_novas.csv')
x = df.values[:, 0]
y = df.values[:, 1]

plt.scatter(x, y, alpha=0.8, edgecolors='k', s=80)
plt.xlabel(df.columns[0])
plt.ylabel(df.columns[1])
plt.xlim((0, 300))
plt.ylim((0, 0.03))
plt.title('Close Nova Dataset')
despine()
```

```python
1e6 / (ss.pearsonr(x, y)[0] * y.std(ddof=1) / x.std(ddof=1))
```

    14612822334.220728

```python
x = df['Distance (million parsecs)']
y = df['Speed (parsecs/year)']

model = ss.linregress(x, y)
beta = model.slope
alpha = model.intercept

plt.scatter(x, y, edgecolors='k', s=80, alpha=0.6)
plt.title('Closed Novas')
plt.ylabel(r'Speed (parsecs/year)')
plt.xlabel(r'Distance (million parsecs)')

y_bar = x * beta + alpha
plt.plot(x, y_bar, color='magenta')

y_min = [min(y_i, y_bar_i) for y_i, y_bar_i in zip(y, y_bar)]
y_max = [max(y_i, y_bar_i) for y_i, y_bar_i in zip(y, y_bar)]
plt.vlines(x, ymin=y_min, ymax=y_max, color='magenta', lw=1)

despine()
```

```python
sns.residplot(x='Distance (million parsecs)', y='Speed (parsecs/year)', data=df,
              line_kws={'color':'magenta', 'lw':4},
              scatter_kws={'edgecolor':'k', 's':80, 'alpha':0.8})
plt.ylabel(r'$\epsilon_i$')
despine()
```

```python
ss.probplot(y - y_bar, plot=plt);
```

```python
import statsmodels.api as sm

stocks = {'Year': [2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2016,2016,2016,2016,2016,2016,2016,2016,2016,2016,2016,2016],
          'Month': [12, 11,10,9,8,7,6,5,4,3,2,1,12,11,10,9,8,7,6,5,4,3,2,1],
          'Interest_Rate': [2.75,2.5,2.5,2.5,2.5,2.5,2.5,2.25,2.25,2.25,2,2,2,1.75,1.75,1.75,1.75,1.75,1.75,1.75,1.75,1.75,1.75,1.75],
          'Unemployment_Rate': [5.3,5.3,5.3,5.3,5.4,5.6,5.5,5.5,5.5,5.6,5.7,5.9,6,5.9,5.8,6.1,6.2,6.1,6.1,6.1,5.9,6.2,6.2,6.1],
          'Stock_Index_Price': [1464,1394,1357,1293,1256,1254,1234,1195,1159,1167,1130,1075,1047,965,943,958,971,949,884,866,876,822,704,719]
         }

df = pd.DataFrame(stocks, columns=['Year','Month', 'Interest_Rate', 'Unemployment_Rate', 'Stock_Index_Price'])
```

```python
x = df['Interest_Rate']
y = df['Stock_Index_Price']
model = ss.linregress(x, y)
beta = model.slope
alpha = model.intercept

plt.scatter(x, y, edgecolors='k', s=80, alpha=0.6)
plt.title('Stocks')
plt.ylabel(r'Stock_Index_Price')
plt.xlabel(r'Interest_Rate')

y_bar = x * beta + alpha
plt.plot(x, y_bar, color='magenta')

y_min = [min(y_i, y_bar_i) for y_i, y_bar_i in zip(y, y_bar)]
y_max = [max(y_i, y_bar_i) for y_i, y_bar_i in zip(y, y_bar)]
plt.vlines(x, ymin=y_min, ymax=y_max, color='magenta', lw=1)

despine()
```

```python
sns.residplot(x='Interest_Rate', y='Stock_Index_Price', data=df,
              line_kws={'color':'magenta', 'lw':4},
              scatter_kws={'edgecolor':'k', 's':80, 'alpha':0.8})
plt.ylabel(r'$\epsilon_i$')
despine()
```

```python
ss.probplot(y - y_bar, plot=plt);
```

```python
x = df['Unemployment_Rate']
y = df['Stock_Index_Price']
model = ss.linregress(x, y)
beta = model.slope
alpha = model.intercept

plt.scatter(x, y, edgecolors='k', s=80, alpha=0.6)
plt.title('Stocks')
plt.ylabel(r'Unemployment_Rate')
plt.xlabel(r'Stock_Index_Price')

y_bar = x * beta + alpha
plt.plot(x, y_bar, color='magenta')

y_min = [min(y_i, y_bar_i) for y_i, y_bar_i in zip(y, y_bar)]
y_max = [max(y_i, y_bar_i) for y_i, y_bar_i in zip(y, y_bar)]
plt.vlines(x, ymin=y_min, ymax=y_max, color='magenta', lw=1)

despine()
```

```python
sns.residplot(x='Unemployment_Rate', y='Stock_Index_Price', data=df,
              line_kws={'color':'magenta', 'lw':4},
              scatter_kws={'edgecolor':'k', 's':80, 'alpha':0.8})
plt.ylabel(r'$\epsilon_i$')
despine()
```

```python
ss.probplot(y - y_bar, plot=plt);
```

```python
df = pd.read_csv('http://www.statsci.org/data/oz/dugongs.txt', sep='\t')
df
```

      Age
      Length

      0
      1.0
      1.80

      1
      1.5
      1.85

      2
      1.5
      1.87

      3
      1.5
      1.77

      4
      2.5
      2.02

      5
      4.0
      2.27

      6
      5.0
      2.15

      7
      5.0
      2.26

      8
      7.0
      2.35

      9
      8.0
      2.47

      10
      8.5
      2.19

      11
      9.0
      2.26

      12
      9.5
      2.40

      13
      9.5
      2.39

      14
      10.0
      2.41

      15
      12.0
      2.50

      16
      12.0
      2.32

      17
      13.0
      2.43

      18
      13.0
      2.47

      19
      14.5
      2.56

      20
      15.5
      2.65

      21
      15.5
      2.47

      22
      16.5
      2.64

      23
      17.0
      2.56

      24
      22.5
      2.70

      25
      29.0
      2.72

      26
      31.5
      2.57

```python
x = df['Age']
y = df['Length']
model = ss.linregress(x, y)
beta = model.slope
alpha = model.intercept

plt.scatter(x, y, edgecolors='k', s=80, alpha=0.6)
plt.title('Dugongos')
plt.ylabel(r'Length')
plt.xlabel(r'Age')

y_bar = x * beta + alpha
plt.plot(x, y_bar, color='magenta')

y_min = [min(y_i, y_bar_i) for y_i, y_bar_i in zip(y, y_bar)]
y_max = [max(y_i, y_bar_i) for y_i, y_bar_i in zip(y, y_bar)]
plt.vlines(x, ymin=y_min, ymax=y_max, color='magenta', lw=1)

despine()
```

```python
sns.residplot(x='Age', y='Length', data=df,
              line_kws={'color':'magenta', 'lw':4},
              scatter_kws={'edgecolor':'k', 's':80, 'alpha':0.8})
plt.ylabel(r'$\epsilon_i$')
despine()
```

```python
df = pd.read_csv('http://www.statsci.org/data/oz/dugongs.txt', sep='\t')
y, x = df.values.T
```


Table of Contents

Imports

Material

rp numerics

freq and q arrays

q array and single freq

freq array and single q

rs numerics

freq and q arrays

q array and single freq

freq array and single q

tp numerics

freq and q arrays

q array and single freq

freq array and single q

ts numerics

freq and q arrays

q array and single freq

freq array and single q

h numerics

freq and q arrays

q array and single freq

freq array and single q

k numerics

freq and q arrays

q array and single freq

freq array and single q

# Imports

```python
# %matplotlib notebook
from NearFieldOptics.Materials import *
from NearFieldOptics.Materials.material_types import *
from NearFieldOptics.Materials.TransferMatrixMedia import *
from common.baseclasses import AWA
import sympy
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib as mpl
import scipy.special as ss
from scipy.optimize import curve_fit
import mpmath as mp
from mpmath.ctx_fp import FPContext
from sys import stdout

sympy.init_printing(use_unicode=True)
```

    <material_types.TabulatedMaterialFromFile.__init__>:
    	Loading tabulated material data from file "Bi2Se3_epsilon.pickle"...
    <material_types.TabulatedMaterialFromFile.__init__>:
    	Loading tabulated material data from file "PMMA_epsilon.pickle"...
    <material_types.TabulatedMaterialFromFile.__init__>:
    	Loading tabulated material data from file "sio2_300nm_extracted_epsilon_cone_A=2a.pickle"...
    <material_types.TabulatedMaterialFromFile.__init__>:
    	Loading tabulated material data from file "TaS2_eps_230K.csv"...
    <material_types.TabulatedMaterialFromFile.__init__>:
    	Loading tabulated material data from file "TaS2_eps_30K.csv"...
    <material_types.TabulatedMaterialFromFile.__init__>:
    	Loading tabulated material data from file "Erik_BSTS_epsilon.pickle"...
    <material_types.TabulatedMaterialFromFile.__init__>:
    	Loading tabulated material data from file "VO2_Insulating.pickle"...
    <material_types.TabulatedMaterialFromFile.__init__>:
    	Loading tabulated material data from file "VO2_Metallic.pickle"...

# Material

```python
LM = LayeredMediaTM((BN_Caldwell,30e-7),(SiO2_300nm,60e-7))
```

# rp numerics

## freq and q arrays

```python
freq = np.linspace(200,2000,500)
q = np.linspace(1,1e6,400)

rp = LM.reflection_p(freq,q)
abs(rp).plot(vmax=1)
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
```

```python
abs(rp).cslice[1e5].plot()
```

## q array and single freq

```python
q = np.linspace(1,1e6,400)
freq = 1400
rp = LM.reflection_p(freq,q)
abs(rp).plot()
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
```

## freq array and single q

```python
freq = np.linspace(200,2000,500)
q = 1/30e-7
rp = LM.reflection_p(freq,q)
abs(rp).plot()
```

# rs numerics

## freq and q arrays

```python
freq = np.linspace(200,2000,500)
# q = 1/30e-7
q = np.linspace(1,1e6,400)

rs = LM.reflection_s(freq,q)
abs(rs).plot(vmax=1)
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
```

```python
abs(rs).cslice[1e5].plot()
```

## q array and single freq

```python
q = np.linspace(1,1e6,400)
freq = 1400
rs = LM.reflection_s(freq,q)
abs(rs).plot()
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
```

## freq array and single q

```python
freq = np.linspace(200,2000,500)
q = 1/30e-7
rs = LM.reflection_s(freq,q)
abs(rs).plot()
```

# tp numerics

## freq and q arrays

```python
freq = np.linspace(200,2000,500)
# q = 1/30e-7
q = np.linspace(1,1e6,400)

tp = LM.transmission_p(freq,q)
abs(tp).plot(vmax=1)
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
```

```python
abs(tp).cslice[1e5].plot()
```

## q array and single freq

```python
q = np.linspace(1,1e6,400)
freq = 1400
tp = LM.transmission_p(freq,q)
abs(tp).plot()
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
```

## freq array and single q

```python
freq = np.linspace(200,2000,500)
q = 1/30e-7
tp = LM.transmission_p(freq,q)
abs(tp).plot()
```

# ts numerics

## freq and q arrays

```python
freq = np.linspace(200,2000,500)
# q = 1/30e-7
q = np.linspace(1,1e6,400)

ts = LM.transmission_s(freq,q)
abs(ts).plot(vmax=1)
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
```

```python
abs(ts).cslice[1e5].plot()
```

## q array and single freq

```python
q = np.linspace(1,1e6,400)
freq = 1400
ts = LM.transmission_s(freq,q)
abs(ts).plot()
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
```

## freq array and single q

```python
freq = np.linspace(200,2000,500)
q = 1/30e-7
ts = LM.transmission_s(freq,q)
abs(ts).plot()
```

# h numerics

## freq and q arrays

```python
freq = np.linspace(200,2000,500)
# q = 1/30e-7
q = np.linspace(1,1e6,400)

h = LM.h_field(freq,q,index=1)
abs(h).plot(vmax=1e-11)
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
```

```python
abs(h).cslice[1e5].plot()
```

## q array and single freq

```python
q = np.linspace(1,1e6,400)
freq = 1400
h = LM.h_field(freq,q)
abs(h).plot()
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
```

## freq array and single q

```python
freq = np.linspace(200,2000,500)
q = 1/30e-7
h = LM.h_field(freq,q)
abs(h).plot()
```

# k numerics

## freq and q arrays

```python
freq = np.linspace(200,2000,500)
# q = 1/30e-7
q = np.linspace(1,1e6,400)

k = LM.Coulomb_kernel(freq,q,index=1)
abs(k).plot(vmax=5e-5)
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
```

```python
abs(k).cslice[1e5].plot()
```

## q array and single freq

```python
q = np.linspace(1,1e6,400)
freq = 1400
k = LM.Coulomb_kernel(freq,q)
abs(k).plot()
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
```

## freq array and single q

```python
freq = np.linspace(200,2000,500)
q = 1/30e-7
k = LM.Coulomb_kernel(freq,q)
abs(k).plot()
```

```python

```

```python

```


## Configurations for Colab

```python
import sys
IN_COLAB = "google.colab" in sys.modules

if IN_COLAB:
    !apt install python-opengl
    !apt install ffmpeg
    !apt install xvfb
    !pip install PyVirtualDisplay==3.0
    !pip install gym==0.21.0
    from pyvirtualdisplay import Display

    # Start virtual display
    dis = Display(visible=0, size=(400, 400))
    dis.start()
```

# 05. Noisy Networks for Exploration

[M. Fortunato et al., "Noisy Networks for Exploration." arXiv preprint arXiv:1706.10295, 2017.](https://arxiv.org/pdf/1706.10295.pdf)

NoisyNet is an exploration method that learns perturbations of the network weights to drive exploration. The key insight is that a single change to the weight vector can induce a consistent, and potentially very complex, state-dependent change in policy over multiple time steps.

Firstly, let's take a look into a linear layer of a neural network with $p$ inputs and $q$ outputs, represented by

$$
y = wx + b,
$$

where $x \in \mathbb{R}^p$ is the layer input, $w \in \mathbb{R}^{q \times p}$, and $b \in \mathbb{R}$ the bias.

The corresponding noisy linear layer is defined as:

$$
y = (\mu^w + \sigma^w \odot \epsilon^w) x + \mu^b + \sigma^b \odot \epsilon^b,
$$

where $\mu^w + \sigma^w \odot \epsilon^w$ and $\mu^b + \sigma^b \odot \epsilon^b$ replace $w$ and $b$ in the first linear layer equation. The parameters $\mu^w \in \mathbb{R}^{q \times p}, \mu^b \in \mathbb{R}^q, \sigma^w \in \mathbb{R}^{q \times p}$ and $\sigma^b \in \mathbb{R}^q$ are learnable, whereas $\epsilon^w \in \mathbb{R}^{q \times p}$ and $\epsilon^b \in \mathbb{R}^q$ are noise random variables which can be generated by one of the following two ways:

1. **Independent Gaussian noise**: the noise applied to each weight and bias is independent, where each random noise entry is drawn from a unit Gaussian distribution. This means that for each noisy linear layer, there are $pq + q$ noise variables (for $p$ inputs to the layer and $q$ outputs).
2. **Factorised Gaussian noise:** This is a more computationally efficient way. It produces 2 random Gaussian noise vectors ($p, q$) and makes $pq + q$ noise entries by outer product as follows:

$$
\begin{align}
\epsilon_{i,j}^w &= f(\epsilon_i) f(\epsilon_j),\\
\epsilon_{j}^b &= f(\epsilon_i),\\
\text{where } f(x) &= sgn(x) \sqrt{|x|}.
\end{align}
$$

In all experiements of the paper, the authors used Factorised Gaussian noise, so we will go for it as well.

```python
import math
import os
from typing import Dict, List, Tuple

import gym
import matplotlib.pyplot as plt
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from IPython.display import clear_output
```

## Replay buffer

Please see *01.dqn.ipynb* for detailed description.

```python
class ReplayBuffer:
    """A simple numpy replay buffer."""

    def __init__(self, obs_dim: int, size: int, batch_size: int = 32):
        self.obs_buf = np.zeros([size, obs_dim], dtype=np.float32)
        self.next_obs_buf = np.zeros([size, obs_dim], dtype=np.float32)
        self.acts_buf = np.zeros([size], dtype=np.float32)
        self.rews_buf = np.zeros([size], dtype=np.float32)
        self.done_buf = np.zeros(size, dtype=np.float32)
        self.max_size, self.batch_size = size, batch_size
        self.ptr, self.size, = 0, 0

    def store(
        self,
        obs: np.ndarray,
        act: np.ndarray,
        rew: float,
        next_obs: np.ndarray,
        done: bool,
    ):
        self.obs_buf[self.ptr] = obs
        self.next_obs_buf[self.ptr] = next_obs
        self.acts_buf[self.ptr] = act
        self.rews_buf[self.ptr] = rew
        self.done_buf[self.ptr] = done
        self.ptr = (self.ptr + 1) % self.max_size
        self.size = min(self.size + 1, self.max_size)

    def sample_batch(self) -> Dict[str, np.ndarray]:
        idxs = np.random.choice(self.size, size=self.batch_size, replace=False)
        return dict(obs=self.obs_buf[idxs],
                    next_obs=self.next_obs_buf[idxs],
                    acts=self.acts_buf[idxs],
                    rews=self.rews_buf[idxs],
                    done=self.done_buf[idxs])

    def __len__(self) -> int:
        return self.size
```

## Noisy Layer

**References:**
- https://github.com/higgsfield/RL-Adventure/blob/master/5.noisy%20dqn.ipynb
- https://github.com/Kaixhin/Rainbow/blob/master/model.py

```python
class NoisyLinear(nn.Module):
    """Noisy linear module for NoisyNet.

    Attributes:
        in_features (int): input size of linear module
        out_features (int): output size of linear module
        std_init (float): initial std value
        weight_mu (nn.Parameter): mean value weight parameter
        weight_sigma (nn.Parameter): std value weight parameter
        bias_mu (nn.Parameter): mean value bias parameter
        bias_sigma (nn.Parameter): std value bias parameter

    """

    def __init__(self, in_features: int, out_features: int, std_init: float = 0.5):
        """Initialization."""
        super(NoisyLinear, self).__init__()

        self.in_features = in_features
        self.out_features = out_features
        self.std_init = std_init

        self.weight_mu = nn.Parameter(torch.Tensor(out_features, in_features))
        self.weight_sigma = nn.Parameter(
            torch.Tensor(out_features, in_features)
        )
        self.register_buffer(
            "weight_epsilon", torch.Tensor(out_features, in_features)
        )

        self.bias_mu = nn.Parameter(torch.Tensor(out_features))
        self.bias_sigma = nn.Parameter(torch.Tensor(out_features))
        self.register_buffer("bias_epsilon", torch.Tensor(out_features))

        self.reset_parameters()
        self.reset_noise()

    def reset_parameters(self):
        """Reset trainable network parameters (factorized gaussian noise)."""
        mu_range = 1 / math.sqrt(self.in_features)
        self.weight_mu.data.uniform_(-mu_range, mu_range)
        self.weight_sigma.data.fill_(
            self.std_init / math.sqrt(self.in_features)
        )
        self.bias_mu.data.uniform_(-mu_range, mu_range)
        self.bias_sigma.data.fill_(
            self.std_init / math.sqrt(self.out_features)
        )

    def reset_noise(self):
        """Make new noise."""
        epsilon_in = self.scale_noise(self.in_features)
        epsilon_out = self.scale_noise(self.out_features)

        # outer product
        self.weight_epsilon.copy_(epsilon_out.ger(epsilon_in))
        self.bias_epsilon.copy_(epsilon_out)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """Forward method implementation.

        We don't use separate statements on train / eval mode.
        It doesn't show remarkable difference of performance.
        """
        return F.linear(
            x,
            self.weight_mu + self.weight_sigma * self.weight_epsilon,
            self.bias_mu + self.bias_sigma * self.bias_epsilon,
        )

    @staticmethod
    def scale_noise(size: int) -> torch.Tensor:
        """Set scale to make noise (factorized gaussian noise)."""
        x = torch.randn(size)

        return x.sign().mul(x.abs().sqrt())
```

## Noisy Network

We use NoisyLinear for the last two FC layers, and there is a method to reset noise at every step.
These are the only differences from the example of *01.dqn.ipynb*.

```python
class Network(nn.Module):
    def __init__(self, in_dim: int, out_dim: int):
        """Initialization."""
        super(Network, self).__init__()

        self.feature = nn.Linear(in_dim, 128)
        self.noisy_layer1 = NoisyLinear(128, 128)
        self.noisy_layer2 = NoisyLinear(128, out_dim)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """Forward method implementation."""
        feature = F.relu(self.feature(x))
        hidden = F.relu(self.noisy_layer1(feature))
        out = self.noisy_layer2(hidden)

        return out

    def reset_noise(self):
        """Reset all noisy layers."""
        self.noisy_layer1.reset_noise()
        self.noisy_layer2.reset_noise()
```

## DQN + NoisyNet Agent (w/o DuelingNet)

Here is a summary of DQNAgent class.

| Method           | Note                                                 |
| ---              | ---                                                  |
|select_action     | select an action from the input state.               |
|step              | take an action and return the response of the env.   |
|compute_dqn_loss  | return dqn loss.                                     |
|update_model      | update the model by gradient descent.                |
|target_hard_update| hard update from the local model to the target model.|
|train             | train the agent during num_frames.                   |
|test              | test the agent (1 episode).                          |
|plot              | plot the training progresses.                        |

In the paper, NoisyNet is used as a component of the Dueling Network Architecture, which includes Double-DQN and Prioritized Experience Replay. However, we don't implement them to simplify the tutorial. One thing to note is that NoisyNet is an alternertive to $\epsilon$-greedy method, so all $\epsilon$ related lines are removed. Please check all comments with *NoisyNet*.

```python
class DQNAgent:
    """DQN Agent interacting with environment.

    Attribute:
        env (gym.Env): openAI Gym environment
        memory (ReplayBuffer): replay memory to store transitions
        batch_size (int): batch size for sampling
        target_update (int): period for target model's hard update
        gamma (float): discount factor
        dqn (Network): model to train and select actions
        dqn_target (Network): target model to update
        optimizer (torch.optim): optimizer for training dqn
        transition (list): transition information including
                           state, action, reward, next_state, done
    """

    def __init__(
        self,
        env: gym.Env,
        memory_size: int,
        batch_size: int,
        target_update: int,
        gamma: float = 0.99,
    ):
        """Initialization.

        Args:
            env (gym.Env): openAI Gym environment
            memory_size (int): length of memory
            batch_size (int): batch size for sampling
            target_update (int): period for target model's hard update
            gamma (float): discount factor
        """
        # NoisyNet: All attributes related to epsilon are removed
        obs_dim = env.observation_space.shape[0]
        action_dim = env.action_space.n

        self.env = env
        self.memory = ReplayBuffer(obs_dim, memory_size, batch_size)
        self.batch_size = batch_size
        self.target_update = target_update
        self.gamma = gamma

        # device: cpu / gpu
        self.device = torch.device(
            "cuda" if torch.cuda.is_available() else "cpu"
        )
        print(self.device)

        # networks: dqn, dqn_target
        self.dqn = Network(obs_dim, action_dim).to(self.device)
        self.dqn_target = Network(obs_dim, action_dim).to(self.device)
        self.dqn_target.load_state_dict(self.dqn.state_dict())
        self.dqn_target.eval()

        # optimizer
        self.optimizer = optim.Adam(self.dqn.parameters())

        # transition to store in memory
        self.transition = list()

        # mode: train / test
        self.is_test = False

    def select_action(self, state: np.ndarray) -> np.ndarray:
        """Select an action from the input state."""
        # NoisyNet: no epsilon greedy action selection
        selected_action = self.dqn(
            torch.FloatTensor(state).to(self.device)
        ).argmax()
        selected_action = selected_action.detach().cpu().numpy()

        if not self.is_test:
            self.transition = [state, selected_action]

        return selected_action

    def step(self, action: np.ndarray) -> Tuple[np.ndarray, np.float64, bool]:
        """Take an action and return the response of the env."""
        next_state, reward, done, _ = self.env.step(action)

        if not self.is_test:
            self.transition += [reward, next_state, done]
            self.memory.store(*self.transition)

        return next_state, reward, done

    def update_model(self) -> torch.Tensor:
        """Update the model by gradient descent."""
        samples = self.memory.sample_batch()

        loss = self._compute_dqn_loss(samples)

        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()

        # NoisyNet: reset noise
        self.dqn.reset_noise()
        self.dqn_target.reset_noise()

        return loss.item()

    def train(self, num_frames: int, plotting_interval: int = 200):
        """Train the agent."""
        self.is_test = False

        state = self.env.reset()
        update_cnt = 0
        losses = []
        scores = []
        score = 0

        for frame_idx in range(1, num_frames + 1):
            action = self.select_action(state)
            next_state, reward, done = self.step(action)

            state = next_state
            score += reward

            # NoisyNet: removed decrease of epsilon

            # if episode ends
            if done:
                state = self.env.reset()
                scores.append(score)
                score = 0

            # if training is ready
            if len(self.memory) >= self.batch_size:
                loss = self.update_model()
                losses.append(loss)
                update_cnt += 1

                # if hard update is needed
                if update_cnt % self.target_update == 0:
                    self._target_hard_update()

            # plotting
            if frame_idx % plotting_interval == 0:
                self._plot(frame_idx, scores, losses)

        self.env.close()

    def test(self, video_folder: str) -> None:
        """Test the agent."""
        self.is_test = True

        # for recording a video
        naive_env = self.env
        self.env = gym.wrappers.RecordVideo(self.env, video_folder=video_folder)

        state = self.env.reset()
        done = False
        score = 0

        while not done:
            action = self.select_action(state)
            next_state, reward, done = self.step(action)

            state = next_state
            score += reward

        print("score: ", score)
        self.env.close()

        # reset
        self.env = naive_env

    def _compute_dqn_loss(self, samples: Dict[str, np.ndarray]) -> torch.Tensor:
        """Return dqn loss."""
        device = self.device  # for shortening the following lines
        state = torch.FloatTensor(samples["obs"]).to(device)
        next_state = torch.FloatTensor(samples["next_obs"]).to(device)
        action = torch.LongTensor(samples["acts"].reshape(-1, 1)).to(device)
        reward = torch.FloatTensor(samples["rews"].reshape(-1, 1)).to(device)
        done = torch.FloatTensor(samples["done"].reshape(-1, 1)).to(device)

        # G_t   = r + gamma * v(s_{t+1})  if state != Terminal
        #       = r                       otherwise
        curr_q_value = self.dqn(state).gather(1, action)
        next_q_value = self.dqn_target(next_state).max(
            dim=1, keepdim=True
        )[0].detach()
        mask = 1 - done
        target = (reward + self.gamma * next_q_value * mask).to(self.device)

        # calculate dqn loss
        loss = F.smooth_l1_loss(curr_q_value, target)

        return loss

    def _target_hard_update(self):
        """Hard update: target <- local."""
        self.dqn_target.load_state_dict(self.dqn.state_dict())

    def _plot(
        self,
        frame_idx: int,
        scores: List[float],
        losses: List[float],
    ):
        """Plot the training progresses."""
        clear_output(True)
        plt.figure(figsize=(20, 5))
        plt.subplot(131)
        plt.title('frame %s. score: %s' % (frame_idx, np.mean(scores[-10:])))
        plt.plot(scores)
        plt.subplot(132)
        plt.title('loss')
        plt.plot(losses)
        plt.show()
```

## Environment

You can see the [code](https://github.com/openai/gym/blob/master/gym/envs/classic_control/cartpole.py) and [configurations](https://github.com/openai/gym/blob/master/gym/envs/__init__.py#L53) of CartPole-v0 from OpenAI's repository.

```python
# environment
env_id = "CartPole-v0"
env = gym.make(env_id)
if IN_COLAB:
    env = gym.wrappers.Monitor(env, "videos", force=True)
```

## Set random seed

```python
seed = 777

def seed_torch(seed):
    torch.manual_seed(seed)
    if torch.backends.cudnn.enabled:
        torch.backends.cudnn.benchmark = False
        torch.backends.cudnn.deterministic = True

np.random.seed(seed)
seed_torch(seed)
env.seed(seed)
```

    [777]

## Initialize

```python
# parameters
num_frames = 20000
memory_size = 10000
batch_size = 128
target_update = 150

# train
agent = DQNAgent(env, memory_size, batch_size, target_update)
```

    cpu

## Train

```python
agent.train(num_frames)
```

## Test

Run the trained agent (1 episode).

```python
video_folder="videos/noisy_net"
agent.test(video_folder=video_folder)
```

    score:  200.0

## Render

```python
import base64
import glob
import io
import os

from IPython.display import HTML, display

def ipython_show_video(path: str) -> None:
    """Show a video at `path` within IPython Notebook."""
    if not os.path.isfile(path):
        raise NameError("Cannot access: {}".format(path))

    video = io.open(path, "r+b").read()
    encoded = base64.b64encode(video)

    display(HTML(
        data="""

        """.format(encoded.decode("ascii"))
    ))

def show_latest_video(video_folder: str) -> str:
    """Show the most recently recorded video from video folder."""
    list_of_files = glob.glob(os.path.join(video_folder, "*.mp4"))
    latest_file = max(list_of_files, key=os.path.getctime)
    ipython_show_video(latest_file)
    return latest_file

latest_file = show_latest_video(video_folder=video_folder)
print("Played:", latest_file)
```

    Played: videos/noisy_net/rl-video-episode-0.mp4


# Kinematics of particle

> Marcos Duarte, Renato Naville Watanabe
> [Laboratory of Biomechanics and Motor Control](http://pesquisa.ufabc.edu.br/bmclab)
> Federal University of ABC, Brazil

## Biomechanics & Mechanics

**A good knowledge of Mechanics is a necessary condition, although not sufficient!, to master Biomechanics**

For this reason, we will review principles of Classical Mechanics in the context of Biomechanics.

The book [*Introduction to Statics and Dynamics*](http://ruina.tam.cornell.edu/Book/index.html) , written by Andy Ruina and Rudra Pratap, is an excellent reference (a rigorous and yet didactic presentation of Mechanics for undergraduate students) on Classical Mechanics and we will use this book as the main reference on Mechanics and Mathematics for this brief review. The preface and first chapter of the book are a good read on how someone should study Mechanics. You should read them!

As we argued in the notebook [Biomechanics](http://nbviewer.jupyter.org/github/demotu/BMC/blob/master/notebooks/Biomechanics.ipynb), we will start with a branch of Classical Mechanics that is simpler to measure its related quantities on biological systems, the Kinematics.

There are some relevant cases in the study of human movement where modeling the human body or one of its segments as a particle might be all we need to explore the phenomenon. The concept of kinematics of a particle, for instance, can be applied to study the performance in the 100-m race; to describe spatial and temporal characteristics of a movement pattern, and to conjecture about how voluntary movements are planned (the minimum jerk hypothesis).

Now, let's review the concept of kinematics of a particle and later apply to the study of human movement.

## Kinematics

**Kinematics** is the branch of Classical Mechanics that describes the motion of objects without consideration of the causes of motion ([Wikipedia](http://en.wikipedia.org/wiki/Kinematics)).

Kinematics of a particle is the description of the motion when the object is considered a particle.

A particle as a physical object does not exist in nature; it is a simplification to understand the motion of a body or it is a conceptual definition such as the center of mass of a system of objects.

### Vectors in Kinematics

Some mechanical quantities in Kinematics (position and its derivatives) are represented as vectors and others, such as time and distance, are scalars.
A vector in Mechanics is a physical quantity with magnitude, direction, and satisfies some elementary vector arithmetic, whereas a scalar is a physical quantity that is fully expressed by a magnitude (a number) only.

For a review about scalars and vectors, see chapter 1 of [Ruina and Rudra's book](http://ruina.tam.cornell.edu/Book/index.html).

 For how to use Python to work with scalars and vectors, see the notebook [Scalar and Vector](http://nbviewer.jupyter.org/github/BMCLab/BMC/blob/master/notebooks/ScalarVector.ipynb).

## Position

Consider a point in the three-dimensional Euclidean space described in a Cartesian coordinate system (see the notebook [Frame of reference](http://nbviewer.jupyter.org/github/demotu/BMC/blob/master/notebooks/ReferenceFrame.ipynb) for an introduction on coordinate systems in Mechanics and Biomechanics):

Figure. Representation of a point $\mathbf{P}$ and its position vector $\overrightarrow{\mathbf{r}}$ in a Cartesian coordinate system. The versors $\hat{\mathbf{i}},\, \hat{\mathbf{j}},\, \hat{\mathbf{k}}\,$  form a basis for this coordinate system and are usually represented in the color sequence RGB (red, green, blue) for easier visualization.

The position of this point in space can be represented as a triple of values each representing the coordinate at each axis of the Cartesian coordinate system following the $ \mathbf{X, Y, Z} $ convention order (which is omitted):

\begin{equation}
(x,\, y,\, z)
\label{eq_xyz}
\end{equation}

The position of a particle in space can also be represented by a vector in the Cartesian coordinate system, with the origin of the vector at the origin of the coordinate system and the tip of the vector at the point position:

\begin{equation}
\overrightarrow{\mathbf{r}}(t) = x\,\hat{\mathbf{i}} + y\,\hat{\mathbf{j}} + z\,\hat{\mathbf{k}}
\label{eq_rxyz}
\end{equation}

Where  $\hat{\mathbf{i}},\, \hat{\mathbf{j}},\, \hat{\mathbf{k}}\,$  are unit vectors in the directions of the axes $ \mathbf{X, Y, Z} $.

For a review on vectors, see the notebook [Scalar and vector](http://nbviewer.ipython.org/github/demotu/BMC/blob/master/notebooks/ScalarVector.ipynb).

With this new notation, the coordinates of a point representing the position of a particle that vary with time would be expressed by the following position vector $\overrightarrow{\mathbf{r}}(t)$:

\begin{equation}
\overrightarrow{\mathbf{r}}(t) = x(t)\,\hat{\mathbf{i}} + y(t)\,\hat{\mathbf{j}} + z(t)\,\hat{\mathbf{k}}
\label{eq_rxyzijk}
\end{equation}

A vector can also be represented in matrix form:

\begin{equation}
\overrightarrow{\mathbf{r}}(t) = \begin{bmatrix} x(t) \\y(t) \\z(t) \end{bmatrix}
\label{eq_rxyzmatrix}
\end{equation}

And the unit vectors in each Cartesian coordinate in matrix form are given by:

\begin{equation}
\hat{\mathbf{i}} = \begin{bmatrix}1\\0\\0 \end{bmatrix},\; \hat{\mathbf{j}} = \begin{bmatrix}0\\1\\0 \end{bmatrix},\; \hat{\mathbf{k}} = \begin{bmatrix} 0 \\ 0 \\ 1 \end{bmatrix}
\label{eq_ijk}
\end{equation}

## Basis

In [linear algebra](http://en.wikipedia.org/wiki/Linear_algebra), a set of unit linearly independent vectors as the three vectors above (orthogonal in the Euclidean space) that can represent any vector via [linear combination](http://en.wikipedia.org/wiki/Linear_combination) is called a basis. A basis is the foundation of creating a reference frame and we will study how to do that other time.

## Displacement

The shortest distance between two positions of a particle.

As the difference between two vectors, displacement is also a vector quantity.

\begin{equation}
\mathbf{\overrightarrow{d}} = \mathbf{\overrightarrow{r}_2} - \mathbf{\overrightarrow{r}_1}
\label{eq_distance}
\end{equation}

Figure. Representation of the displacement vector $\mathbf{\overrightarrow{d}}$ between two positions $\mathbf{\overrightarrow{r}_1}$ and $\mathbf{\overrightarrow{r}_2}$.

## Velocity

Velocity is the rate (with respect to time) of change of the position of a particle.

The average velocity between two instants is:

\begin{equation}
\overrightarrow{\mathbf{v}}(t) = \frac{\overrightarrow{\mathbf{r}}(t_2)-\overrightarrow{\mathbf{r}}(t_1)}{t_2-t_1} = \frac{\Delta \overrightarrow{\mathbf{r}}}{\Delta t}
\label{eq_velocity}
\end{equation}

The instantaneous velocity of the particle is obtained when $\Delta t$ approaches to zero, which from calculus is the first-order [derivative](http://en.wikipedia.org/wiki/Derivative) of the position vector:

\begin{equation}
\overrightarrow{\mathbf{v}}(t) = \lim_{\Delta t \to 0} \frac{\Delta \overrightarrow{\mathbf{r}}}{\Delta t} = \lim_{\Delta t \to 0} \frac{\overrightarrow{\mathbf{r}}(t+\Delta t)-\overrightarrow{\mathbf{r}}(t)}{\Delta t} = \frac{\mathrm{d}\overrightarrow{\mathbf{r}}}{dt}
\label{eq_velocityderiv}
\end{equation}

For the movement of a particle described with respect to an [inertial Frame of reference](http://nbviewer.jupyter.org/github/demotu/BMC/blob/master/notebooks/ReferenceFrame.ipynb), the derivative of a vector is obtained by differentiating each vector component of the Cartesian coordinates (since the base versors  $\hat{\mathbf{i}}, \hat{\mathbf{j}}, \hat{\mathbf{k}}$  are constant):

\begin{equation}
\overrightarrow{\mathbf{v}}(t) = \frac{\mathrm{d}\overrightarrow{\mathbf{r}}(t)}{dt} = \frac{\mathrm{d}x(t)}{\mathrm{d}t}\hat{\mathbf{i}} + \frac{\mathrm{d}y(t)}{\mathrm{d}t}\hat{\mathbf{j}} + \frac{\mathrm{d}z(t)}{\mathrm{d}t}\hat{\mathbf{k}}
\label{eq_velocityderiv2}
\end{equation}

Or in matrix form (and using the Newton's notation for differentiation):

\begin{equation}
\overrightarrow{\mathbf{v}}(t) = \begin{bmatrix}
\dot x(t) \\
\dot y(t) \\
\dot z(t)
\end{bmatrix}
\label{eq_velocityderiv3}
\end{equation}

## Acceleration

Acceleration is the rate (with respect to time) of change of the velocity of a particle, which can also be given by the second-order rate of change of the position.

The average acceleration between two instants is:

\begin{equation}
\overrightarrow{\mathbf{a}}(t) = \frac{\overrightarrow{\mathbf{v}}(t_2)-\overrightarrow{\mathbf{v}}(t_1)}{t_2-t_1} = \frac{\Delta \overrightarrow{\mathbf{v}}}{\Delta t}
\label{eq_acc}
\end{equation}

Likewise, instantaneous acceleration is the first-order derivative of the velocity or the second-order derivative of the position vector:

\begin{equation}
\overrightarrow{\mathbf{a}}(t) = \frac{\mathrm{d}\overrightarrow{\mathbf{v}}(t)}{\mathrm{d}t} = \frac{\mathrm{d}^2\overrightarrow{\mathbf{r}}(t)}{\mathrm{d}t^2} = \frac{\mathrm{d}^2x(t)}{\mathrm{d}t^2}\hat{\mathbf{i}} + \frac{\mathrm{d}^2y(t)}{\mathrm{d}t^2}\hat{\mathbf{j}} + \frac{\mathrm{d}^2z(t)}{\mathrm{d}t^2}\hat{\mathbf{k}}
\label{eq_accderiv}
\end{equation}

And in matrix form:

\begin{equation}
\mathbf{a}(t) = \begin{bmatrix}
\ddot x(t) \\
\ddot y(t) \\
\ddot z(t)
\end{bmatrix}
\label{eq_accderiv2}
\end{equation}

For curiosity, see [Notation for differentiation](https://en.wikipedia.org/wiki/Notation_for_differentiation) on the origin of the different notations for differentiation.

When the base versors change in time, for instance when the basis is attached to a rotating frame or reference, the components of the vector’s derivative is not the derivatives of its components; we will also have to consider the derivative of the basis with respect to time.

## The antiderivative

As the acceleration is the derivative of the velocity which is the derivative of position, the inverse mathematical operation is the [antiderivative](http://en.wikipedia.org/wiki/Antiderivative) (or integral):

\begin{equation}
\begin{array}{l l}
\mathbf{r}(t) = \mathbf{r}_0 + \int \mathbf{v}(t) \:\mathrm{d}t \\
\mathbf{v}(t) = \mathbf{v}_0 + \int \mathbf{a}(t) \:\mathrm{d}t
\end{array}
\label{eq_antiderivative}
\end{equation}

**This part of the kinematics is presented in chapter 12, pages 605-620, of the [Ruina and Rudra's book](http://ruina.tam.cornell.edu/Book/index.html).**

## Some cases of motion of a particle

To deduce some trivial cases of motion of a particle (at rest, at constant speed, and at constant acceleration), we can start from the equation for its position and differentiate it to obtain expressions for the velocity and acceleration or the inverse approach, start with the equation for acceleration, and then integrate it to obtain the velocity and position of the particle. Both approachs are valid in Mechanics. For the present case, it probaly makes more sense to start with the expression for acceleration.

#### Particle at rest

\begin{equation}
\begin{array}{l l}
\overrightarrow{\mathbf{a}}(t) = 0 \\
\overrightarrow{\mathbf{v}}(t) = 0 \\
\overrightarrow{\mathbf{r}}(t) = \overrightarrow{\mathbf{r}}_0
\end{array}
\label{eq_rest}
\end{equation}

#### Particle at constant speed

\begin{equation}
\begin{array}{l l}
\overrightarrow{\mathbf{a}}(t) = 0 \\
\overrightarrow{\mathbf{v}}(t) = \overrightarrow{\mathbf{v}}_0 \\
\overrightarrow{\mathbf{r}}(t) = \overrightarrow{\mathbf{r}}_0 + \overrightarrow{\mathbf{v}}_0t
\end{array}
\label{eq_constantspeed}
\end{equation}

#### Particle at constant acceleration

\begin{equation}
\begin{array}{l l}
\overrightarrow{\mathbf{a}}(t) = \overrightarrow{\mathbf{a}}_0 \\
\overrightarrow{\mathbf{v}}(t) = \overrightarrow{\mathbf{v}}_0 + \overrightarrow{\mathbf{a}}_0t \\
\overrightarrow{\mathbf{r}}(t) = \overrightarrow{\mathbf{r}}_0 + \overrightarrow{\mathbf{v}}_0t +
\frac{1}{2}\overrightarrow{\mathbf{a}}_0 t^2
\end{array}
\label{eq_constantacceleration}
\end{equation}

### Visual representation of these cases

```python
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
sns.set_context("notebook", font_scale=1.2, rc={"lines.linewidth": 2, "lines.markersize": 10})
```

```python
t = np.arange(0, 2.0, 0.02)
r0 = 1; v0 = 2; a0 = 4

plt.rc('axes',  labelsize=14,  titlesize=14)
plt.rc('xtick', labelsize=10)
plt.rc('ytick', labelsize=10)
f, axarr = plt.subplots(3, 3, sharex = True, sharey = True, figsize=(14,7))
plt.suptitle('Scalar kinematics of a particle', fontsize=20);

tones = np.ones(np.size(t))

axarr[0, 0].set_title('at rest', fontsize=14);
axarr[0, 0].plot(t, r0*tones, 'g', linewidth=4, label='$r(t)=1$')
axarr[1, 0].plot(t,  0*tones, 'b', linewidth=4, label='$v(t)=0$')
axarr[2, 0].plot(t,  0*tones, 'r', linewidth=4, label='$a(t)=0$')
axarr[0, 0].set_ylabel('r(t) [m]')
axarr[1, 0].set_ylabel('v(t) [m/s]')
axarr[2, 0].set_ylabel('a(t) [m/s$^2$]')

axarr[0, 1].set_title('at constant speed');
axarr[0, 1].plot(t, r0*tones+v0*t, 'g', linewidth=4, label='$r(t)=1+2t$')
axarr[1, 1].plot(t, v0*tones,      'b', linewidth=4, label='$v(t)=2$')
axarr[2, 1].plot(t,  0*tones,      'r', linewidth=4, label='$a(t)=0$')

axarr[0, 2].set_title('at constant acceleration');
axarr[0, 2].plot(t, r0*tones+v0*t+1/2.*a0*t**2,'g', linewidth=4,
                 label='$r(t)=1+2t+\\frac{1}{2}4t^2$')
axarr[1, 2].plot(t, v0*tones+a0*t,             'b', linewidth=4,
                 label='$v(t)=2+4t$')
axarr[2, 2].plot(t, a0*tones,                  'r', linewidth=4,
                 label='$a(t)=4$')

for i in range(3):
    axarr[2, i].set_xlabel('Time [s]');
    for j in range(3):
        axarr[i,j].set_ylim((-.2, 10))
        axarr[i,j].legend(loc = 'upper left', frameon=True, framealpha = 0.9, fontsize=16)

plt.subplots_adjust(hspace=0.09, wspace=0.07)
```

## Symbolic programming

We can use [Sympy](http://www.sympy.org/en/index.html), a Python library for symbolic mathematics, to deduce the expressions for the cases of motion of a particle we just visualized.
Let's show how to integrate with Sympy for the case of particle with constant acceleration:

```python
from sympy import Symbol, integrate, init_printing
init_printing(use_latex='mathjax')

t = Symbol('t', real=True, positive=True)
g = Symbol('g', real=True, positive=True)
v0 = Symbol('v0', real=True, positive=True, constant = True)
r0 = Symbol('r0', real=True, positive=True, constant = True)
```

```python
v = integrate(g, t) + v0  # a constant has to be added
v
```

$\displaystyle g t + v_{0}$

```python
r = integrate(v, t) + r0  # a constant has to be added
r
```

$\displaystyle \frac{g t^{2}}{2} + r_{0} + t v_{0}$

## Kinematics of human movement

### Kinematics of the 100-m race

An example where the analysis of some aspects of the human body movement can be reduced to the analysis of a particle is the study of the Biomechanics of the 100-m race.

A technical report with the kinematic data for the 100-m world record by Usain Bolt can be downloaded from the [website for Research Projects](http://www.iaaf.org/development/research) from the International Association of Athletics Federations.
[Here is a direct link for that report](http://www.iaaf.org/download/download?filename=76ade5f9-75a0-4fda-b9bf-1b30be6f60d2.pdf&urlSlug=1-biomechanics-report-wc-berlin-2009-sprint). In particular, the following table shows the data for the three medalists in that race:

Figure. Data from the three medalists of the 100-m dash in Berlin, 2009 (IAAF report).

The column **RT** in the table above refers to the reaction time of each athlete. The IAAF has a very strict rule about reaction time: any athlete with a reaction time less than 100 ms is disqualified from the competition! See the website [Reaction Times and Sprint False Starts](http://condellpark.com/kd/reactiontime.htm) for a discussion about this rule.

You can measure your own reaction time in a simple way visiting this website: [http://www.humanbenchmark.com/tests/reactiontime](http://www.humanbenchmark.com/tests/reactiontime).

The article [A Kinematics Analysis Of Three Best 100 M Performances Ever](http://www.ncbi.nlm.nih.gov/pmc/articles/PMC3661886/) by Krzysztof and Mero presents a detailed kinematic analysis of 100-m races.

### Spatial and temporal characteristics of a movement pattern

See the notebook [Spatial and temporal characteristics](http://nbviewer.jupyter.org/github/demotu/BMC/blob/master/notebooks/SpatialTemporalCharacteristcs.ipynb) about how the simple measurement of spatial and temporal kinematic variables can be very useful to describe the human gait.

### The minimum jerk hypothesis

See the notebook [The minimum jerk hypothesis](http://nbviewer.jupyter.org/github/demotu/BMC/blob/master/notebooks/MinimumJerkHypothesis.ipynb) about the conjecture that movements are performed (organized) with the smoothest trajectory possible.

## Problems

1. Read the preface and first chapter of the [Ruina and Rudra's book](http://ruina.tam.cornell.edu/Book/index.html) about how someone should study Mechanics.

2. Consider the data for the three medalists of the 100-m dash in Berlin, 2009, shown previously.
 a. Calculate the average velocity and acceleration.
 b. Plot the graphs for the displacement, velocity, and acceleration versus time.
 c. Plot the graphs velocity and acceleration versus partial distance (every 20m).
 d. Calculate the average velocity and average acceleration and the instants and values of the peak velocity and peak acceleration.

3. The article "Biomechanical Analysis of the Sprint and Hurdles Events at the 2009 IAAF World Championships in Athletics" by Graubner and Nixdorf lists the 10-m split times for the three medalists of the 100-m dash in Berlin, 2009:

 a. Repeat the same calculations performed in problem 2 and compare the results.

4. A body attached to a spring has its position (in cm) described by the equation $x(t) = 2\sin(4\pi t + \pi/4)$.
 a. Calculate the equation for the body velocity and acceleration.
 b. Plot the position, velocity, and acceleration in the interval [0, 1] s.

5. There are some nice free software that can be used for the kinematic analysis of human motion. Some of them are: [Kinovea](http://www.kinovea.org/), [Tracker](http://www.cabrillo.edu/~dbrown/tracker/), and [SkillSpector](http://video4coach.com/index.php?option=com_content&task=view&id=13&Itemid=45). Visit their websites and explore these software to understand in which biomechanical applications they could be used.

6. (Sample 12.1 of Ruina and Rudra's book) The position vector of a particle is given as a functions time: $\overrightarrow{\mathbf{r}}(t) = (C_1+C_2t+C_3t^2)\hat{\mathbf{i}}+C_4t\,\hat{\mathbf{j}}$ . Where $C_1=1m, C_2=3m/s,C_3=1m/s^2, C_4=2m/s$.
 a. Find the position, velocity, and acceleration of the particle at $t=2s$.
 b. Find the change in the position of the particle between $t=2s$ and $t=3s$.

7. From Ruina and Rudra's book, solve the problems **12.1.1** to **12.1.14**.

## References

- Graubner R, Nixdorf E (2011) [Biomechanical Analysis of the Sprint and Hurdles Events at the 2009 IAAF World Championships in Athletics ](http://www.meathathletics.ie/devathletes/pdf/Biomechanics%20of%20Sprints.pdf). [New Studies in Athletics](http://www.iaaf.org/development/new-studies-in-athletics), 1/2, 19-53.
- Krzysztof M, Antti Mero A (2013) [A Kinematics Analysis Of Three Best 100 M Performances Ever](http://www.ncbi.nlm.nih.gov/pmc/articles/PMC3661886/). Journal of Human Kinetics, 36, 149–160.
- [Research Projects](http://www.iaaf.org/development/research) from the International Association of Athletics Federations.
- Ruina A, Rudra P (2019) [Introduction to Statics and Dynamics](http://ruina.tam.cornell.edu/Book/index.html). Oxford University Press.