Выбор модели / типы для повышения надежности результатов с реализацией Python в одном представлении

Важно, чтобы модель, подготовленная с помощью машинного обучения, давала надежные результаты для внешних наборов данных, то есть обобщение. После того, как часть набора данных зарезервирована в качестве теста, а модель обучена, точность, полученная на основе тестовых данных, может быть высокой для тестовых данных, в то время как для внешних данных она будет очень низкой. Например, если в качестве случайно выбранного тестового набора данных в наборе данных с метками x, y, z выбраны только данные с меткой x, это фактически дает точность только метки x, а не модели, но этого можно не заметить. от разработчика. Это, не обобщая модель, определенно нежелательный случай. В этой статье представлены различные конфигурации, из которых можно выбрать данные обучения и данные тестирования, чтобы повысить надежность результатов модели. Эти методы необходимы для того, чтобы модель правильно реагировала на проекты с открытым миром.

Table of Contents 
1. Train Test Split
2. Cross Validation
2.1. KFold Cross Validation
2.2. Stratified KFold Cross Validation
2.3. LeaveOneOut Cross Validation
2.4. Repeated KFold Cross Validation
2.5. ShuffleSplit Cross Validation
2.6. Group KFold Cross Validation

1. Тренировка тестового сплита

В приложениях машинного обучения модель обучается с помощью набора данных. С помощью этого обучения модель изучает взаимосвязь между функциями и выходом (целью). Затем точность модели оценивается с помощью другого набора данных в том же формате. Разделение теста на поезд разделяет данные на данные поезда и тестовые данные со скоростью, выбранной пользователем.

IN[1]
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
iris = load_iris()
x_train,x_test,y_train,y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=2021)
print("shape of x_train",x_train.shape)
print("shape of x_test",x_test.shape)
OUT[1]
shape of x_train (120, 4)
shape of x_test (30, 4)

Как видно из OUT [1], набор данных разделен на 20% тестовых данных и 80% обучающих данных.

2. Перекрестная проверка

Хотя кажется очень полезным разделить модель с помощью train_test_split, уровень точности, полученный из тестового набора данных, может не отражать истину. Например, когда мы случайным образом разделяем набор данных, содержащий метки A, B и C, с помощью train_test_split, данные с метками A и B могут быть разделены как поезд, а все метки C - как тест. В этом контексте существует разница между обученными и протестированными данными, и это вводит в заблуждение относительно успешности модели. Поэтому при разделении набора данных на данные поезда и тестовые данные используются разные методы. Теперь давайте рассмотрим типы перекрестной проверки, основанные на статистике и легко реализуемые с помощью библиотеки scikit learn.

2.1. Перекрестная проверка KFold

Набор данных делится на число (k), выбранное пользователем. Модель разбивается на столько частей, сколько на части, каждая часть называется сверткой, а другая свертка используется в качестве тестового набора данных в каждом разбиении. Например, если для набора данных из 150 данных установлено значение k = 3, модель дает нам 3 значения точности, а другая часть 1/3 (0–50, 50–100, 100–150) используется в качестве теста на каждая точность. Остальные 2/3 части используются для поезда на каждой итерации.

IN[2]
heart_dataset=pd.read_csv('heart.csv')
heart_data   =heart_dataset.drop('output',axis=1)
heart_target =heart_dataset['output']
rb=RobustScaler()
heart_robust=rb.fit_transform(heart_data)
IN[3]
kf = KFold(n_splits=5)
i=1
for train_data,test_data in kf.split(X=heart_data, y=heart_target):
    print('iteration',i)
    print(train_data[:10],"length:", len(train_data))
    print(test_data[:10],"length:", len(test_data))
    print("**********************************")
    i +=1
OUT[3]
iteration 1
[61 62 63 64 65 66 67 68 69 70] train_length: 242
[0 1 2 3 4 5 6 7 8 9] test_length: 61
**********************************
iteration 2
[0 1 2 3 4 5 6 7 8 9] train_length: 242
[61 62 63 64 65 66 67 68 69 70] test_length: 61
**********************************
iteration 3
[0 1 2 3 4 5 6 7 8 9] train_length: 242
[122 123 124 125 126 127 128 129 130 131] test_length: 61
**********************************
iteration 4
[0 1 2 3 4 5 6 7 8 9] train_length: 243
[183 184 185 186 187 188 189 190 191 192] test_length: 60
**********************************
iteration 5
[0 1 2 3 4 5 6 7 8 9] train_length: 243
[243 244 245 246 247 248 249 250 251 252] test_length: 60
**********************************

Набор данных о сердечных заболеваниях состоит из 14 столбцов и 303 строк. Все значения функций являются числовыми, поэтому применяется RobustScaler. Выходные данные набора данных состоят из 0 и 1. OUT [3] показывает первые 10 данных тестовых и обучающих данных в каждом разбиении. Как видно, тестовые данные из первого разбиения начинаются с первых данных набора данных; тестовые данные из второго разбиения начинаются с 61. данных; тестовые данные из третьего сплита начинаются с 122. данных; тестовые данные из данных, четвертое разбиение начинается с данных 183.data, а окончательное разбиение начинается с данных 243. data

IN[4]
scores=cross_val_score(LogisticRegression(),heart_robust,heart_target,cv=5)
print(scores)
print("mean accuracy:",scores.mean())
OUT[4]
[0.83606557 0.86885246 0.83606557 0.86666667 0.76666667]
mean accuracy: 0.8348633879781422

Набор данных о сердечных заболеваниях из 303 числовых данных был разделен 5 раз с помощью логистической регрессии со значением k = 5. Точность логистической регрессии для каждого разделения составляет [0,83606557 0,86885246 0,83606557 0,86666667 0,76666667] соответственно.

Перекрестная проверка KFold с перемешиванием

При k-кратной перекрестной проверке набор данных был разделен на k значений по порядку. Если в параметре KFold установлены значения shuffle и random_state, данные выбираются случайным образом:

IN[5]
kfs = KFold(n_splits=5, shuffle=True, random_state=2021)
scores_shuffle=cross_val_score(LogisticRegression(),heart_robust,heart_target,cv=kfs)
print(scores_shuffle)
print("mean accuracy:",scores_shuffle.mean())
OUT[5]
[0.83606557 0.78688525 0.78688525 0.85       0.83333333]
mean accuracy: 0.8186338797814209

2.2. Стратифицированная перекрестная проверка KFold

Набор данных разделен на выбираемое пользователем количество (k) частей. В отличие от KFold, каждая цель также разделена и объединена k. Например, если мы рассмотрим набор данных iris (первые 50 данных iris setosa; 50–100 Iris Versicolor, 100–150 Iris Virginica) и разделим его, выбрав значение k, равное 5:

IN[6]
iris_dataset=pd.read_csv('iris.csv')
iris_data   =iris_dataset.drop('Species',axis=1)
iris_data   =iris_data.drop(['Id'],axis=1)
iris_target =iris_dataset['Species']
IN[7]
skf = StratifiedKFold(n_splits=5)
i=1
for train_data,test_data in skf.split(X=iris_data, y=iris_target):
    print('iteration',i)
    print(test_data,"length", len(test_data))
    print("**********************************")
    i +=1
OUT[7]
iteration 1
[  0   1   2   3   4   5   6   7   8   9  50  51  52  53  54  55  56  57 58  59 100 101 102 103 104 105 106 107 108 109] length 30
**********************************
iteration 2
[ 10  11  12  13  14  15  16  17  18  19  60  61  62  63  64  65  66  67 68  69 110 111 112 113 114 115 116 117 118 119] length 30
**********************************
iteration 3
[ 20  21  22  23  24  25  26  27  28  29  70  71  72  73  74  75  76  77 78  79 120 121 122 123 124 125 126 127 128 129] length 30
**********************************
iteration 4
[ 30  31  32  33  34  35  36  37  38  39  80  81  82  83  84  85  86  87 88  89 130 131 132 133 134 135 136 137 138 139] length 30
**********************************
iteration 5
[ 40  41  42  43  44  45  46  47  48  49  90  91  92  93  94  95  96  97 98  99 140 141 142 143 144 145 146 147 148 149] length 30
**********************************

Когда набор тестовых данных анализируется, первые 10 данных каждой цели (0–10; 50–60; 100–110) в 1-й итерации, второй 1/5 срез каждой цели во 2-й итерации (20–30; 60-70; 110-120) и так далее. Остальные данные в каждой итерации использовались для обучения, а для обучающих данных на каждой итерации используется линейная регрессия, и, естественно, получается 5 различных значений точности.

IN[8]
lr=LogisticRegression()
le=LabelEncoder()
iris_labels=le.fit_transform(iris_target)
rb=RobustScaler()
iris_robust=rb.fit_transform(iris_data)
iris_robust=pd.DataFrame(iris_robust)
IN[9]
scores_skf = []
i = 1
for train_set, test_set in skf.split(X=iris_robust, y=iris_labels):
    lr.fit(iris_robust.loc[train_set], iris_labels[train_set])
    sco = lr.score(iris_robust.loc[test_set], iris_labels[test_set])
    scores_skf.append(sco)
    i += 1
print(scores_skf)
print("mean accuracy:",sum(scores_skf) / len(scores_skf))
OUT[9]
[0.9, 0.9666666666666667, 0.9333333333333333, 0.9333333333333333, 0.9666666666666667]
mean accuracy: 0.9400000000000001

Поскольку объект «numpy.ndarray» не имеет атрибута «loc», массив NumPy iris_robust преобразуется в pandas DataFrame.

Стратифицированную перекрестную проверку KFold можно легко реализовать, как показано с помощью cross_val_score в Scikit learn.

IN[10]
score_skf=cross_val_score(lr,iris_robust,iris_labels,cv=skf)
print(score_skf)
print("mean accuracy:",score_skf.mean())
OUT[10]
[0.9        0.96666667 0.93333333 0.93333333 0.96666667]
mean accuracy: 0.9400000000000001

Оба результата одинаковы.

Поскольку целевые значения в наборе данных радужной оболочки равны (50–50–50), они размещаются одинаково от каждого. Однако, если бы метки в наборе данных были в разных пропорциях, каждая складка содержала бы данные с этой скоростью. Например, если было 100 данных для label-x и 900 данных для label-y, каждая свертка содержала бы 90% данных label-y и 10% данных label-x.

Глядя на метод разделения на веб-сайте scikit learn, видно, что значение y должно быть (n_samples,), поэтому он предназначен для работы с кодировщиком меток вместо OneHotEncoder.

2.3. Перекрестная проверка LeaveOneOut

Каждые данные рассматриваются как кратные, поэтому значение k равно количеству данных. Все данные разделяются один за другим, и модель обучается с использованием оставшихся данных. Разделенные данные проверяются на обученной модели. Если мы рассмотрим набор данных радужной оболочки глаза:

IN[11]
loo = cross_val_score(estimator=LogisticRegression(), X=iris_robust, y=iris_labels,
                               scoring='accuracy', cv=LeaveOneOut())
print(loo,"len of loo=",len(loo))
print("mean accuracy:",loo.mean())
OUT[11]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 0. 0. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] len of loo= 150
mean accuracy: 0.9466666666666667

Как видно, набор данных радужной оболочки, состоящий из 150 наборов данных, моделируется с помощью LeaveOneOut и применяется логистическая регрессия. Все данные разделены, и модель была обучена с оставшимися данными. Всего модель обучалась 150 раз, и было сделано 150 прогнозов (для каждой информации). Все они усреднены.

2.4. Повторная перекрестная проверка K-сгиба

K-кратная перекрестная проверка повторяется столько раз, сколько раз выбрано значение, выбранное пользователем. Для набора данных радужной оболочки:

IN[12]
rkf = cross_val_score(estimator=LogisticRegression(), X=iris_robust, y=iris_labels, scoring='accuracy', cv=RepeatedKFold(n_splits=5, n_repeats=5))
print("accuracy:", rkf)
print("mean accuracy",rkf.mean())
OUT[12]
accuracy: 
[0.96666667 0.9       0.93333333 0.93333333 0.93333333 0.9
 0.93333333 1.         0.96666667 0.96666667 0.86666667 0.96666667
 0.96666667 0.96666667 1.         0.96666667 0.9        1.
 0.93333333 0.93333333 0.86666667 0.96666667 1.         0.9
 0.96666667]
mean accuracy 0.9453333333333331

Набор данных был разделен на 5 частей, и алгоритм был адаптирован 5 раз. В результате было получено 25 значений точности.

То же самое можно сделать и для Stratified KFold:

IN[13]
rskf = cross_val_score(estimator=LogisticRegression(), X=iris_robust, y=iris_labels, scoring='accuracy', cv=RepeatedStratifiedKFold(n_splits=5, n_repeats=5))
print("accuracy", rskf)
print("mean accuracy",rskf.mean())
OUT[13]
accuracy
[0.96666667 0.9        0.96666667 0.96666667 0.96666667 0.9
 0.96666667 0.96666667 0.9        0.96666667 0.96666667 0.96666667
 0.9        0.96666667 0.96666667 0.9        0.93333333 1.
 0.96666667 0.96666667 0.96666667 0.93333333 1.         0.9
 0.93333333]
mean accuracy 0.9493333333333333

2.5. Перекрестная проверка в случайном порядке

Количество итераций набора данных задается с помощью n_splits, а обучающие и тестовые данные выбираются случайным образом для каждого разбиения в указанных пользователем соотношениях:

IN[14]
shuffle_split = ShuffleSplit(test_size=.4, train_size=.5, n_splits=10)
scores_ss = cross_val_score(LogisticRegression(), iris_robust, iris_labels, cv=shuffle_split)
print("Accuracy",scores_ss)
print("mean accuracy:",scores_ss.mean())
OUT[14]
Accuracy
[0.9        0.93333333 0.88333333 0.9        0.95       0.95
 0.93333333 0.91666667 0.95       0.95      ]
mean accuracy: 0.9266666666666665

Та же процедура может быть проделана для Stratified Shuffle Split:

IN[15]
shuffle_sfs=StratifiedShuffleSplit(test_size=.4, train_size=.5, n_splits=10)
scores_sfs = cross_val_score(LogisticRegression(), iris_robust, iris_labels, cv=shuffle_sfs)
print("Accuracy",scores_sfs)
print("mean accuracy:",scores_sfs.mean())
OUT[15]
Accuracy
[0.88333333 0.93333333 0.93333333 0.93333333 0.91666667 0.96666667
 0.96666667 0.96666667 0.88333333 0.9       ]
mean accuracy: 0.9283333333333333

2.6. Перекрестная проверка сгиба группы K

Он используется, когда от одного и того же объекта получено несколько данных. Например, в медицинских данных лучше иметь несколько изображений одного и того же пациента в наборе обучающих данных для обобщения модели. Для этого можно использовать GroupKFold, который принимает в качестве аргумента массив групп, которые мы можем использовать, чтобы указать, какой человек находится на изображении. Массив групп здесь определяет группы в данных, которые не следует разделять при создании обучающих и тестовых наборов, и их не следует путать с меткой класса. С GroupKFold группа находится либо в обучающем наборе, либо на тестовом наборе.

Вернуться к руководству нажмите здесь.