Je reprends ici en partie le calcul manuel réalisé sur ce MOOC : https://openclassrooms.com/fr/courses/4525266-decrivez-et-nettoyez-votre-jeu-de-donnees/4775616-analysez-deux-variables-qualitatives-avec-le-chi-2
Le but est de montrer, une fois le calcul manuel maîtrisé, comment obtenir une pvaleur et pouvoir réaliser un test d'indépendance entre deux variables qualitatives grâce à scipy.stats.
Le notebook est divisé en deux parties : une partie appelée "manuelle" et une partie appelée "scipy.stats".
Merci à Nicolas Rangeon pour son excellent cours sur cette partie
Mais surtout :
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import scipy.stats as st
Basé sur ce MOOC : https://openclassrooms.com/fr/courses/4525266-decrivez-et-nettoyez-votre-jeu-de-donnees/4775616-analysez-deux-variables-qualitatives-avec-le-chi-2
X = ["Chez Luc"]*10
X.extend(["Au café Dembas"]*20)
X.extend(["Au café Ducoing"]*40)
X.extend(["Chez Sarah"]*30)
Y = ["Café"]*1
Y.extend(["Thé"]*9)
Y.extend(["Autre"]*0)
Y.extend(["Café"]*9)
Y.extend(["Thé"]*6)
Y.extend(["Autre"]*5)
Y.extend(["Café"]*20)
Y.extend(["Thé"]*10)
Y.extend(["Autre"]*10)
Y.extend(["Café"]*20)
Y.extend(["Thé"]*5)
Y.extend(["Autre"]*5)
data = {
'bar':X,
'boisson':Y
}
df = pd.DataFrame(data)
df.head()
On pivote, on remplit les NaN, on calcule la ligne Total et la colonne Total.
Ce tableau nous sera également utile pour la partie 2, car c'est cela qui est attendu en entrée par la méthode de scipy.stats que l'on utilisera.
X = "bar"
Y = "boisson"
cont = df[[X, Y]].pivot_table(index=X, columns=Y, aggfunc=len).fillna(0).copy()
tx = df[X].value_counts()
ty = df[Y].value_counts()
cont = cont.astype(int)
cont
tx_df = pd.DataFrame(tx)
tx_df.columns = ["c"]
ty_df = pd.DataFrame(ty)
ty_df.columns = ["c"]
# Valeurs totaleso observées
n = len(df)
# Produit matriciel. On utilise pd.T pour pivoter une des deux séries.
indep = (tx_df.dot(ty_df.T) / n)
indep
# Matrice
freq = (cont-indep)**2/indep
freq
Somme des valeurs de la précédente matrice. Cette somme suit une loi du Chi2 à k degrés de liberté.
k = observed.size - sum(observed.shape) + observed.ndim - 1 (D'après la documentation de scipy.stats)
chi2 = freq.sum().sum()
chi2
Documentation : https://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.stats.chi2_contingency.html
st_chi2, st_p, st_dof, st_exp = st.chi2_contingency(cont)
On retrouve bien la même valeur que calculée manuellement
st_chi2
C'est ce nombre de degrés de liberté qui sera utilisé par scipy.stats pour calculer la loi suivie et donc calculer la pvaleur (en confrontant notre valeur de khi2 à la courbe de la loi obtenue).
st_dof
Cette valeur nous permet de décider si deux variables sont indépendantes ou non en se fixant un seuil de décision.
Scipy.stats calcule lui-même le nombre de degrés de liberté à partir du tableau de contingence. Cela permet ensuite de calculer la pvaleur, en "observant" la courbe de densité de la loi du khi2 à k degrés de liberté.
L'hypothèse H0 est que les variables sont indépendantes entre elles.
A noter qu'une loi du khi2 est suivie par une somme de k lois normales centrées réduites et indépendantes.
st_p
A un seuil de 0.1%, nous pouvons rejeter H0. On rejette donc l'indépendance des veux variables.
On constate alors qu'il s'agit bien de la même matrice que nous avions calculé à la main (seules la position des index et des colonnes a changé).
st_exp