31 августа 2015

Разбиение исходных данных на обучающую и контрольную выборки



Как было отмечено ранее, при построении предсказательных моделей исходные данные обычно разбиваются на обучающую ("training set") и контрольную ("test set", "validation set") выборки. Обучающая выборка используется собственно для "обучения" той или иной модели, т.е. для построения математических отношений между некоторой переменной-откликом и предикторами, тогда как контрольная (= "проверочная", "экзаменационная") выборка служит для получения оценки прогнозных свойств модели на новых данных, т.е. данных, которые не были использованы для обучения модели. Как правило, обучающая выборка составляет 75-80% от объема исходных данных, хотя каких-то строгих правил в этом отношении не существует. Рассмотрим, как можно выполнить подобное разбиение исходных данных на обучающую и контрольную выборки стандартными средствами R и при помощи пакета caret.



Используем описанный ранее набор данных GermanCredit из пакета caret:

# Загрузка данных:
library(caret)
data(GermanCredit)

Зависимой переменной (= откликом) в этом наборе данных является переменная Class с двумя значениями - Good и Bad, обозначающими кредитоспособность клиентов банка. Интерес представляет класс Bad. Доля клиентов с этим значением составляет 30%:

table(GermanCredit$Class)/sum(table(GermanCredit$Class))
 
Bad Good 
0.3  0.7 

Разбить исходный набор данных на обучающую и контрольную выборки можно при помощи базовой функции R sample(), которая выполняет (псевдо-)случайный отбор заданного пользователем числа наблюдений из некоторой совокупности. Один из возможных способов использования этой функции выглядит следующим образом:

set.seed(101) # для воспроизводимости результата
 
# создаем вектор со случайно отобранными номерами наблюдений, 
# которые войдут в обучающую выборку:
tr.index = sample(1:nrow(GermanCredit), nrow(GermanCredit)*0.8) 
 
# формируем обучающую выборку (~80% от исходного числа наблюдений):
trSet = GermanCredit[tr.index, ]
 
# формируем контрольную выборку (~20% от исходного числа наблюдений):
testSet = GermanCredit[-tr.index, ]

Легко проверить, что доля клиентов с интересующим нас значением отклика (Class == "Bad") в обучающей и контрольной выборках составляет примерно 30%, как и в исходных данных:

table(trSet$Class)/sum(table(trSet$Class))
 
   Bad   Good 
0.2975 0.7025 
 
table(testSet$Class)/sum(table(testSet$Class))
 
 Bad  Good 
0.31  0.69

В состав пакета caret входит функция createDataPartition(), специально предназначенная для разбиения исходных данных на обучающую и контрольную выборки. Основное преимущество этой функции по сравнению с рассмотренной вышей sample() заключается в том, что createDataPartition() автоматически выполняет страцифицированный отбор ("stratified sampling") наблюдений. Для качественного отклика это означает, что случайный отбор наблюдений выполняется в пределах каждого класса. В случае же количественного отклика исходные его значения разбиваются на группы по числу заданных пользователем процентилей (аргумент groups) и отбор наблюдений затем происходит в пределах каждой из этих групп. Стратифицированный отбор обеспечивает большую вероятность того, что значения отклика в обучающей и контрольной выборках будут иметь примерно то же распределение, что и в исходных данных. Это может оказаться особенно полезным при работе с данными небольшого размера.

Главными аргументами функции createDataPartition() являются вектор со значениями переменной-отклика (y) и доля, которую размер обучающей выборки должен составлять от размера исходных данных (p). По умолчанию результаты вычислений возвращаются в виде списка. Такое поведение функции можно изменить, присвоив ее аргументу list значение FALSE - в этом случае результатом будет матрица с номерами наблюдений, которые войдут в обучающую выборку:

set.seed(101)
tr.index = createDataPartition(y = GermanCredit$Class, p = 0.8, list = FALSE)
 
head(tr.index)
     Resample1
[1,]         1
[2,]         2
[3,]         3
[4,]         4
[5,]         5
[6,]         7
 
# Формируем обучающую и контрольную выборки:
trSet = GermanCredit[tr.index, ]
testSet = GermanCredit[-tr.index, ]

При необходимости процесс разбиения исходных данных на обучающую и контрольную выборки можно повторить несколько раз. Такой подход часто используется для получения оценок разброса значений показателей качества предсказательных моделей (например, RMSE). Для выполнения подобного многократного разбиения исходных данных достаточно воспользоваться аргументом times функции createDataPartition():

set.seed(101)
tr.index = createDataPartition(y = GermanCredit$Class, p = 0.8, times = 3, list = FALSE)
head(tr.index)
     Resample1 Resample2 Resample3
[1,]         1         1         1
[2,]         2         4         3
[3,]         3         5         4
[4,]         4         6         5
[5,]         5         9         7
[6,]         7        11         8

В заключение стоит отметить, что в состав пакета caret входят функции, позволяющие реализовывать также и другие распространенные способы разбиения исходных данных на подмножества - см. createResample(), createFolds(), createMultiFolds()createTimeSlices().

2 комментария :

Евгений комментирует...

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

Cute Arwen комментирует...

Спасибо большое!

Отправить комментарий