Tukey's Paired Mean Test
Example: For the above example, use Tukey's method for paired comparisons to determine which pairs of the three level means are different.
import statsmodels.stats.multicomp as mc
comp = mc.MultiComparison(x_df['test1_score'], x_df['level'])
post_hoc_res = comp.tukeyhsd(alpha=0.05)
print(post_hoc_res.summary())
Show expected output
Multiple Comparison of Means - Tukey HSD, FWER=0.05
====================================================
group1 group2 meandiff p-adj lower upper reject
----------------------------------------------------
high low -10.8383 0.001 -12.5144 -9.1622 True
high medium -4.7717 0.001 -6.4478 -3.0956 True
low medium 6.0667 0.001 4.3906 7.7428 True
----------------------------------------------------Interpretation: All pairwise mean comparisons are significant. That is, the mean score1_difference between high and low, high and medium, and low and medium are significantly different.
Two-way ANOVA (Block Design)
Example: The data set below (URL) contains students test1_score, gender, level, section etc.
- Write a program to read the dataset and display the first rows.
- Write a program to find
test1_scoremeans grouped bylevelandgender. - Write a program to perform ANOVA block design to test if there is sufficient evidence to indicate a difference in the averages of test1_scores among the three levels (low, medium, high) using gender as blocks. Use 10% level of significance.
my_csv_file.csv
import pandas as pd
url='my_csv_file.csv'
x_df = pd.read_csv(url)
x_df.head() # print the first five rows
| id | gender | section | time | level | test1_score | test2_score | test3_score | |
|---|---|---|---|---|---|---|---|---|
| 0 | 1 | female | C | 17.3 | low | 65.4 | 84.3 | 51.9 |
| 1 | 2 | female | D | 5.1 | low | 72.4 | 86.1 | 52.0 |
| 2 | 3 | female | A | 2.4 | low | 73.8 | 84.2 | 53.1 |
| 3 | 4 | female | A | 8.8 | low | 70.2 | 87.9 | 52.0 |
| 4 | 5 | male | B | 15.0 | low | 60.3 | 81.4 | 55.5 |
x_df.groupby(['level','gender']).agg({'test1_score': ['mean', 'std','size']})
| test1_score | ||||
|---|---|---|---|---|
| mean | std | size | ||
| level | gender | |||
| high | female | 79.684000 | 3.637728 | 25 |
| male | 79.562857 | 3.654979 | 35 | |
| low | female | 68.469697 | 4.876377 | 33 |
| male | 69.148148 | 3.662741 | 27 | |
| medium | female | 75.729167 | 2.804884 | 24 |
| male | 74.250000 | 4.031271 | 36 |
import statsmodels.api as sm
from statsmodels.formula.api import ols
model = ols('test1_score ~ C(level) + C(gender)',data = x_df).fit()
table = sm.stats.anova_lm(model,type=2) # type 2 for non-equal sample sizes
print(table)
Show expected output
df sum_sq mean_sq F PR(>F)
C(level) 2.0 3540.854333 1770.427167 116.878417 5.044391e-33
C(gender) 1.0 3.850572 3.850572 0.254203 6.147613e-01
Residual 176.0 2665.977095 15.147597 NaN NaNInterpretation: There is significant difference of the test1_score means between the three levles afte blocking by gender. No significant difference in the average test1_scores between the two genders.
Two-Factor ANOVA (Interactions)
Example: The dataset below (URL) contains students test1_score, gender, level, section etc.
- Write a program to read the dataset and display the first 5 rows.
- Write a program to display the means grouped by
levelandinteraction - Write a program to perform a two-factor ANOVA with
levelandsection. Do the data provide sufficient evidence to indicate an interaction betweenlevelandsection? Use 10% level of significance.
my_csv_file.csv
import pandas as pd
url='my_csv_file.csv'
x_df = pd.read_csv(url)
x_df.groupby(['level','section']).agg({'test1_score': ['mean', 'std','size']})
| test1_score | ||||
|---|---|---|---|---|
| mean | std | size | ||
| level | section | |||
| high | A | 79.714286 | 4.442601 | 14 |
| B | 79.292308 | 4.325402 | 13 | |
| C | 79.426667 | 3.944339 | 15 | |
| D | 79.835294 | 2.047542 | 17 | |
| low | A | 67.346667 | 4.704840 | 15 |
| B | 67.931250 | 4.311646 | 16 | |
| C | 67.993750 | 3.560238 | 16 | |
| D | 72.423077 | 3.067614 | 13 | |
| medium | A | 74.811765 | 2.812002 | 17 |
| B | 74.721053 | 4.207081 | 19 | |
| C | 73.016667 | 2.343857 | 6 | |
| D | 75.605556 | 4.043073 | 18 |
import statsmodels.api as sm
from statsmodels.formula.api import ols
model = ols('test1_score ~ C(level)*C(section)',data = x_df).fit()
table = sm.stats.anova_lm(model,type=2) # type 2 for non-equal sample sizes
print(table)
Show expected output
df sum_sq mean_sq F PR(>F)
C(level) 2.0 3494.967554 1747.483777 121.179409 3.062871e-33
C(section) 3.0 125.235378 41.745126 2.894819 3.687668e-02
C(level):C(section) 6.0 133.100312 22.183385 1.538309 1.685520e-01
Residual 167.0 2408.245695 14.420633 NaN NaNInterpretation: There is no significant interaction effect between level and section of the average test1_score, because the p-value 1.685520e-01 is not less than the level of significance.10.
The End
Adapted from Python for Introductory Statistics, by Simon Aman (Truman College, City Colleges of Chicago), licensed under CC BY 4.0. Changes were made: reformatted as an accessible XYZ web edition with live in-browser code cells. License: CC-BY-4.0.