Тест. Множественная проверка гипотез


In [36]:
from __future__ import division

import numpy as np
import pandas as pd

from scipy import stats
from statsmodels.sandbox.stats.multicomp import multipletests 

%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns

from itertools import combinations

from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

Классификатор C4.5 и три его модификации: с оптимизацией гиперпараметра m, гиперпараметра cf и с одновременной оптимизацией обоих гиперпараметров. Эти четыре классификатора сравнивались на 14 наборах данных. На каждом датасете был посчитан AUC каждого классификатора. Данные записаны в файле:

AUCs.txt

Используя критерий знаковых рангов, проведите попарное сравнение каждого классификатора с каждым. Выберите два классификатора, различие между которыми наиболее статистически значимо.


In [4]:
aucs = pd.read_csv('AUCs.txt', delimiter='\t')
aucs.info()


<class 'pandas.core.frame.DataFrame'>
RangeIndex: 14 entries, 0 to 13
Data columns (total 5 columns):
Unnamed: 0    14 non-null object
C4.5          14 non-null float64
C4.5+m        14 non-null float64
C4.5+cf       14 non-null float64
C4.5+m+cf     14 non-null float64
dtypes: float64(4), object(1)
memory usage: 632.0+ bytes

In [8]:
aucs.columns = [u'Dataset', u'C4.5', u'C4.5+m', u'C4.5+cf', u'C4.5+m+cf']
aucs


Out[8]:
Dataset C4.5 C4.5+m C4.5+cf C4.5+m+cf
0 adult (sample) 0.763 0.768 0.771 0.798
1 breast cancer 0.599 0.591 0.590 0.569
2 breast cancer wisconsin 0.954 0.971 0.968 0.967
3 cmc 0.628 0.661 0.654 0.657
4 ionosphere 0.882 0.888 0.886 0.898
5 iris 0.936 0.931 0.916 0.931
6 liver disorders 0.661 0.668 0.609 0.685
7 lung cancer 0.583 0.583 0.563 0.625
8 lymphography 0.775 0.838 0.866 0.875
9 mushroom 1.000 1.000 1.000 1.000
10 primary tumor 0.940 0.962 0.965 0.962
11 rheum 0.619 0.666 0.614 0.669
12 voting 0.972 0.981 0.975 0.975
13 wine 0.957 0.978 0.946 0.970

In [18]:
w_stat = pd.DataFrame(columns=['Model 1', 'Model 2', 'Wilcoxon stat', 'p-value'])
k = 0
for i, j in combinations([1, 2, 3, 4], 2):
    w_stat.loc[k, 'Model 1'], w_stat.loc[k, 'Model 2'] = aucs.columns[i], aucs.columns[j]
    w_stat.loc[k, 'Wilcoxon stat'], w_stat.loc[k, 'p-value'] = stats.wilcoxon(aucs.iloc[:, i], aucs.iloc[:, j])
    k += 1

In [19]:
w_stat


Out[19]:
Model 1 Model 2 Wilcoxon stat p-value
0 C4.5 C4.5+m 6.5 0.0107571
1 C4.5 C4.5+cf 43 0.861262
2 C4.5 C4.5+m+cf 11 0.0159064
3 C4.5+m C4.5+cf 17 0.0463327
4 C4.5+m C4.5+m+cf 22 0.327826
5 C4.5+cf C4.5+m+cf 10 0.0229091

In [32]:
top_diff_idx = w_stat.loc[:, 'p-value'].idxmin()
print('Two classifiers with the highest significance difference: %s & %s' % (w_stat.loc[top_diff_idx, 'Model 1'],
      w_stat.loc[top_diff_idx, 'Model 2']))


Two classifiers with the highest significance difference: C4.5 & C4.5+m

Сколько статистически значимых на уровне 0.05 различий мы обнаружили?


In [35]:
diff_models_cnt = w_stat.loc[w_stat.loc[:, 'p-value'] <= 0.05, :].shape[0]
print('Number of p-value <= 0.05: %d' % diff_models_cnt)


Number of p-value <= 0.05: 4

Сравнивая 4 классификатора между собой, мы проверили 6 гипотез. Давайте сделаем поправку на множественную проверку. Начнём с метода Холма. Сколько гипотез можно отвергнуть на уровне значимости 0.05 после поправки этим методом?


In [41]:
reject, p_corrected, a1, a2 = multipletests(w_stat['p-value'], alpha = 0.05, method = 'holm')

In [42]:
w_stat['p_corrected'] = p_corrected
w_stat['reject'] = reject

In [43]:
w_stat


Out[43]:
Model 1 Model 2 Wilcoxon stat p-value p_corrected reject
0 C4.5 C4.5+m 6.5 0.0107571 0.0645428 False
1 C4.5 C4.5+cf 43 0.861262 0.861262 False
2 C4.5 C4.5+m+cf 11 0.0159064 0.0795322 False
3 C4.5+m C4.5+cf 17 0.0463327 0.138998 False
4 C4.5+m C4.5+m+cf 22 0.327826 0.655651 False
5 C4.5+cf C4.5+m+cf 10 0.0229091 0.0916364 False

Сколько гипотез можно отвергнуть на уровне значимости 0.05 после поправки методом Бенджамини-Хохберга?


In [37]:
reject, p_corrected, a1, a2 = multipletests(w_stat['p-value'], alpha = 0.05, method = 'fdr_bh')

In [38]:
w_stat['p_corrected'] = p_corrected
w_stat['reject'] = reject

In [39]:
w_stat


Out[39]:
Model 1 Model 2 Wilcoxon stat p-value p_corrected reject
0 C4.5 C4.5+m 6.5 0.0107571 0.0458182 True
1 C4.5 C4.5+cf 43 0.861262 0.861262 False
2 C4.5 C4.5+m+cf 11 0.0159064 0.0458182 True
3 C4.5+m C4.5+cf 17 0.0463327 0.0694991 False
4 C4.5+m C4.5+m+cf 22 0.327826 0.393391 False
5 C4.5+cf C4.5+m+cf 10 0.0229091 0.0458182 True

In [40]:
diff_models_cnt = w_stat.loc[w_stat.loc[:, 'p_corrected'] <= 0.05, :].shape[0]
print('Number of p-value <= 0.05: %d' % diff_models_cnt)


Number of p-value <= 0.05: 3