Mood’s median test in SAEPER
For a discussion of this test, see the corresponding chapter in Summary and Analysis of Extension Program Evaluation in R (rcompanion.org/handbook/F_09.html).
Importing packages in this chapter
The following commands will import required packages used in this chapter from libraries and assign them common aliases. You may need install these libraries first.
import io
import os
import numpy as np
import scipy.stats as stats
import pandas as pd
import matplotlib.pyplot as plt
import pingouin as pg
import seaborn as sns
import math
Setting your working directory
You may wish to set your working directory for exported plots.
os.chdir("C:/Users/Sal Mangiafico/Desktop")
print(os.getcwd())
Example of Mood’s median test
Data = pd.read_table(sep="\\s+",
filepath_or_buffer=io.StringIO("""
Speaker Likert
Pooh 3
Pooh 5
Pooh 4
Pooh 4
Pooh 4
Pooh 4
Pooh 4
Pooh 4
Pooh 5
Pooh 5
Piglet 2
Piglet 4
Piglet 2
Piglet 2
Piglet 1
Piglet 2
Piglet 3
Piglet 2
Piglet 2
Piglet 3
Tigger 4
Tigger 4
Tigger 4
Tigger 4
Tigger 5
Tigger 3
Tigger 5
Tigger 4
Tigger 4
Tigger 3
"""))
Summarize data treating Likert scores as numeric
Summary = Data.groupby('Speaker')['Likert'].describe()
print(Summary)
count mean std min 25% 50% 75% max
Speaker
Piglet 10.0 2.3 0.823273 1.0 2.0 2.0 2.75 4.0
Pooh 10.0 4.2 0.632456 3.0 4.0 4.0 4.75 5.0
Tigger 10.0 4.0 0.666667 3.0 4.0 4.0 4.00 5.0
### The 50% percentile is the median for each group
Mood’s median test
Using scipy.stats
Pooh = Data['Likert'][Data['Speaker']=='Pooh']
Piglet = Data['Likert'][Data['Speaker']=='Piglet']
Tigger = Data['Likert'][Data['Speaker']=='Tigger']
stats.median_test(Piglet, Pooh, Tigger)
MedianTestResult(statistic=3.3599999999999994, pvalue=0.18637397603940997, median=4.0)
As mentioned in the SAEPER chapter, we’ll invert the scale on the Likert item responses. This is related to so many responses being equal to the global median, 4.
Data['Likert.inv'] = 6 - Data['Likert']
Pooh = Data['Likert.inv'][Data['Speaker']=='Pooh']
Piglet = Data['Likert.inv'][Data['Speaker']=='Piglet']
Tigger = Data['Likert.inv'][Data['Speaker']=='Tigger']
stats.median_test(Piglet, Pooh, Tigger)
MedianTestResult(statistic=15.833333333333334, pvalue=0.0003646156887302732, median=2.0)
### Note: This is based on the inverted responses
Effect size measurements
Appropriate effect size statistics may include those for the two-sample case, applied on each pair of groups.
Manual calculation of Mood’s median test
medianOverall = Data['Likert.inv'].median()
medianOverall
2.0
### Note: This is the median of the inverted responses
PoohHigher = sum(Data['Likert.inv'][Data['Speaker']=='Pooh'] > medianOverall)
PigletHigher = sum(Data['Likert.inv'][Data['Speaker']=='Piglet'] > medianOverall)
TiggerHigher =sum(Data['Likert.inv'][Data['Speaker']=='Tigger'] > medianOverall)
PoohLower = sum(Data['Likert.inv'][Data['Speaker']=='Pooh'] <= medianOverall)
PigletLower = sum(Data['Likert.inv'][Data['Speaker']=='Piglet'] <= medianOverall)
TiggerLower = sum(Data['Likert.inv'][Data['Speaker']=='Tigger'] <= medianOverall)
Matrix = np.array([[PoohHigher, PoohLower], [PigletHigher, PigletLower],
[TiggerHigher, TiggerLower]])
So the following the contingency table would be used by Mood’s median test.
GreaterThanEqualMu.inv LessThanMu.inv
Pooh 1 9
Piglet 9 1
Tigger 2 8
stats.chi2_contingency(Matrix)
Chi2ContingencyResult(statistic=15.833333333333334, pvalue=0.0003646156887302732, dof=2)
### Note this is the same as the output from Pingouin above