I Would like to compare if results from two models are significantly different.
The models have been trained on the same samples in a K-fold cross validation setup, so both will spit out K performance scores, for which we can test is the mean of the performance is significantly different with a related T-test.
At first, setting the significance level alpha at 0.05, my results are not significant:
>>> from scipy.stats import ttest_rel
>>> np.random.seed(12)
>>> n_splits = 5
>>> performance_model_A = np.random.normal(0.5, 0.2, n_splits)
>>> performance_model_B = np.random.normal(0.6, 0.1, n_splits)
>>> _, pval = ttest_rel(performance_model_A, performance_model_B)
At 5-fold cross validation the p-value is 0.180
However, if you add repeats to the cross-validation set up, I end up with a p-value lower than alpha:
>>> n_repeats = 10
>>> performance_model_A = np.random.normal(0.5, 0.2, n_splits * n_repeats)
>>> performance_model_B = np.random.normal(0.6, 0.1, n_splits * n_repeats)
>>> _, pval = ttest_rel(performance_model_A, performance_model_B)
>>> print(f'At {n_splits}-fold, {n_repeats}-repeat cross validation the p-value is {pval:.3f}.')
At 5-fold, 10-repeat cross validation the p-value is 0.002.
Now, I think we should perform multiple comparison correction because I used the same sample multiple times (e.g. using Bonferroni correction for n_repeats
and n_splits
, reducing alpha to 0.01 and 0.001 respectively.
But I am reluctant, since all I am comparing is the performance of the models on a given sample of data, so all results are further evidence of differences between the models (which is what we are testing). However, this leads to the bizarre conclusion that -with sufficient repeats- any model is significantly different from another, so then I might not be performing the right test for this application.
Alternatively, I could just strike it in the middle: correct for n_repeats
and not for n_splits
, since this way I correct for time a sample is in the test data partition more than once. But would not be backed by any strong statistical insight.
I have not been able to find a definitive advice online/best practice/papers on multiple comparison testing for comparison of cross-validation results, and any help is greatly appreciated.
Thanks, @Firebug for the reference to Bouckaert and Frank's corrected repeated k-fold cv test.
I could not find a Python implementation for this method, so finally I would like to share the following Python solution if that is allowed:
def corr_rep_kfold_cv_test(a:list, b:list, n_splits:int, n_samples:int) -> tuple[float, float]:
"""
Implementation of Bouckaert and Franks (2004) corrected repeated k-fold cv test.
"""
r = len(a) // n_splits # number of r-times repeats as integer
k = n_splits # number of k-folds as integer
n1 = n_samples // n_splits * (n_splits - 1) # number of instances used for training
n2 = n_samples // n_splits # number of instances used for testing
x = np.subtract(a, b) # observed differences
m = x.mean() # mean estimate
s = np.sum((x - m) ** 2) / (k * r - 1) # variance estimate
t_stat = m / np.sqrt((1 / (k * r) + n2 / n1) * s) # corrected test statistic
p_val = stats.t.sf(np.abs(t_stat), r) * k # p-value
return t_stat, p_val
sklearn.model_selection.RepeatedKFold
: Thus,performance_model_A
is an 1D array of lengthn_splits
×n_folds
. $\endgroup$