.. _tableaucontingencerst: ====================================================== 1A.1 - Calculer un chi 2 sur un tableau de contingence ====================================================== .. only:: html **Links:** :download:`notebook `, :downloadlink:`html `, :download:`python `, :downloadlink:`slides `, :githublink:`GitHub|_doc/notebooks/1a/tableau_contingence.ipynb|*` :math:`\chi_2` et tableau de contingence, avec *numpy*, avec *scipy* ou sans. .. code:: ipython3 from jyquickhelper import add_notebook_menu add_notebook_menu() .. contents:: :local: formule ------- Le test du :math:`\chi_2` (`wikipedia `__) sert à comparer deux distributions. Il peut être appliqué sur un `tableau de contingence `__ pour comparer la distributions observée avec la distribution qu’on observerait si les deux facteurs du tableau étaient indépendants. On note :math:`M=(m_{ij})` une matrice de dimension :math:`I \times J`. Le test du :math:`\chi_2` se calcule comme suit : - :math:`M = \sum_{ij} m_{ij}` - :math:`\forall i, \; m_{i \bullet} = \sum_j m_{ij}` - :math:`\forall j, \; m_{\bullet j} = \sum_i m_{ij}` - :math:`\forall i,j \; n_{ij} = \frac{m_{i \bullet} m_{\bullet j}}{N}` Avec ces notations : .. math:: T = \sum_{ij} \frac{ (m_{ij} - n_{ij})^2}{n_{ij}} La variable aléatoire :math:`T` suit asymptotiquement une loi du :math:`\chi_2` à :math:`(I-1)(J-1)` degrés de liberté (`table `__). Comment le calculer avec `numpy `__ ? tableau au hasard ----------------- On prend un petit tableau qu’on choisit au hasard, de préférence non carré pour détecter des erreurs de calculs. .. code:: ipython3 import numpy M = numpy.array([[4, 5, 2, 1], [6, 3, 1, 7], [10, 14, 6, 9]]) M .. parsed-literal:: array([[ 4, 5, 2, 1], [ 6, 3, 1, 7], [10, 14, 6, 9]]) calcul avec scipy ----------------- Evidemment, il existe une fonction en python qui permet de calculer la statistique :math:`T` : `chi2_contingency `__. .. code:: ipython3 from scipy.stats import chi2_contingency chi2, pvalue, degrees, expected = chi2_contingency(M) chi2, degrees, pvalue .. parsed-literal:: (6.1685985038926212, 6, 0.40457120905808314) calcul avec numpy ----------------- .. code:: ipython3 N = M.sum() ni = numpy.array( [M[i,:].sum() for i in range(M.shape[0])] ) nj = numpy.array( [M[:,j].sum() for j in range(M.shape[1])] ) ni, nj, N .. parsed-literal:: (array([12, 17, 39]), array([20, 22, 9, 17]), 68) Et comme c’est un usage courant, `numpy `__ propose une façon de faire sans écrire une boucle avec la fonction `sum `__ : .. code:: ipython3 ni = M.sum(axis=1) nj = M.sum(axis=0) ni, nj, N .. parsed-literal:: (array([12, 17, 39]), array([20, 22, 9, 17]), 68) .. code:: ipython3 nij = ni.reshape(M.shape[0], 1) * nj / N nij .. parsed-literal:: array([[ 3.52941176, 3.88235294, 1.58823529, 3. ], [ 5. , 5.5 , 2.25 , 4.25 ], [ 11.47058824, 12.61764706, 5.16176471, 9.75 ]]) .. code:: ipython3 d = (M - nij) ** 2 / nij d.sum() .. parsed-literal:: 6.1685985038926212