Как разбить данные на обучающие / тестовые наборы, используя функцию выборки


160

Я только начал использовать R, и я не уверен, как включить мой набор данных в следующий пример кода:

sample(x, size, replace = FALSE, prob = NULL)

У меня есть набор данных, который мне нужно поместить в тренировочный (75%) и тестовый (25%) набор. Я не уверен, какую информацию я должен поместить в x и размер? Является ли x файл набора данных и размер, сколько образцов у меня есть?


1
xможет быть индексом (скажем, строки / столбцы) вашего data. sizeможет быть 0.75*nrow(data). Попробуйте sample(1:10, 4, replace = FALSE, prob = NULL)посмотреть, что он делает.
Harkmug

Ответы:


255

Существует множество подходов для достижения разделения данных. Для более полного подхода взгляните на createDataPartitionфункцию в caToolsпакете.

Вот простой пример:

data(mtcars)

## 75% of the sample size
smp_size <- floor(0.75 * nrow(mtcars))

## set the seed to make your partition reproducible
set.seed(123)
train_ind <- sample(seq_len(nrow(mtcars)), size = smp_size)

train <- mtcars[train_ind, ]
test <- mtcars[-train_ind, ]

Я немного запутался, что гарантирует, что этот код возвращает уникальный тест и обучает df? Кажется, работает, не поймите меня неправильно. Простое понимание того, как вычитать индексы, приводит к уникальным наблюдениям. Например, если у вас был df с 10 строками и одним столбцом, а один столбец содержал 1,2,3,4,5,6,7,8,9,10, и вы следовали этому коду, что мешает поезду иметь индекс 4 и тест, имеющий -6 -> 10 - 6 = 4, а?
goldisfine

1
спасибо. Я пытался, mtcars[!train_ind]и хотя это не сработало, это не сработало, как ожидалось. Как я могу использовать подмножество !?
user989762

@ user989762 !используются для логического ( TRUE/FALSE), а не для индексов. Если вы хотите использовать subset !, попробуйте что-то вроде mtcars [ !seq_len(nrow(mtcars)) %in% train_ind,] (не проверено).
Дикоа,

1
@VedaadShakib, когда вы используете "-", он опускает весь индекс в train_ind из ваших данных. Взгляните на adv-r.had.co.nz/Subsetting.html . Надеюсь, это поможет
Dickoa

1
Не createDataPartitionв caretи нет caTools?
J. Mini

93

Это может быть легко сделано:

set.seed(101) # Set Seed so that same sample can be reproduced in future also
# Now Selecting 75% of data as sample from total 'n' rows of the data  
sample <- sample.int(n = nrow(data), size = floor(.75*nrow(data)), replace = F)
train <- data[sample, ]
test  <- data[-sample, ]

Используя пакет caTools :

require(caTools)
set.seed(101) 
sample = sample.split(data$anycolumn, SplitRatio = .75)
train = subset(data, sample == TRUE)
test  = subset(data, sample == FALSE)

4
Недавно я прошел курс обучения в MIT, и они использовали подход с использованием caTools. Спасибо
Четан Шарма

1
sample = sample.split(data[,1], SplitRatio = .75)Следует убрать необходимость называть столбец.
Бенджамин Зиперт

33

Я бы использовал dplyrдля этого, делает это очень просто. Для этого требуется переменная id в вашем наборе данных, что в любом случае является хорошей идеей не только для создания наборов, но и для отслеживания в ходе вашего проекта. Добавьте его, если он еще не содержится.

mtcars$id <- 1:nrow(mtcars)
train <- mtcars %>% dplyr::sample_frac(.75)
test  <- dplyr::anti_join(mtcars, train, by = 'id')

28

Это почти тот же код, но в более приятном виде

bound <- floor((nrow(df)/4)*3)         #define % of training and test set

df <- df[sample(nrow(df)), ]           #sample rows 
df.train <- df[1:bound, ]              #get training set
df.test <- df[(bound+1):nrow(df), ]    #get test set

Ага! Хорошо выглядишь!
Минакши

23
library(caret)
intrain<-createDataPartition(y=sub_train$classe,p=0.7,list=FALSE)
training<-m_train[intrain,]
testing<-m_train[-intrain,]

3
Хотя ответ только на код является ответом, лучше дать некоторые пояснения.
C8H10N4O2

что такое m_train? Я думаю, что вы имели в виду, sub_train оригинальные data.frame. Следовательно, пересмотренный код должен быть обучен <-sub_train [intrain,] и тестирован <-sub_train [-intrain,]. Интересно, почему никто не смог определить эту серьезную проблему с вашим ответом за последние пять лет!
МНМ

21

Я разделю «а» на поезд (70%) и проверю (30%)

    a # original data frame
    library(dplyr)
    train<-sample_frac(a, 0.7)
    sid<-as.numeric(rownames(train)) # because rownames() returns character
    test<-a[-sid,]

сделано


4
вам нужно импортировать пакет dpyr, require (dplyr)
TheMI

Этот ответ помог мне, но мне нужно было настроить его, чтобы получить ожидаемые результаты. Таким образом, набор данных "train" имеет имена строк = sid последовательных целых чисел: 1,2,3,4, ... тогда как вы хотите, чтобы sid были числами из исходного набора данных "a", которые, поскольку они выбраны случайным образом, выиграли не быть последовательными целыми числами. Итак, сначала нужно создать переменную id для «a».
Скотт Мерф

row.names (mtcars) <- NULL; train <-dplyr :: sample_frac (mtcars, 0.5); test <-mtcars [-as.numeric (row.names (train)),] # Я сделал это с моими данными, оригинальный код не работает, если ваши имена строк уже установлены в числа
Кристофер Джон,

16

Мое решение в основном такое же, как у дикоа, но немного проще для интерпретации:

data(mtcars)
n = nrow(mtcars)
trainIndex = sample(1:n, size = round(0.7*n), replace=FALSE)
train = mtcars[trainIndex ,]
test = mtcars[-trainIndex ,]

Какая переменная швейцарская?
billmccord

7

Просто более краткий и простой способ использования удивительной библиотеки dplyr :

library(dplyr)
set.seed(275) #to get repeatable data

data.train <- sample_frac(Default, 0.7)

train_index <- as.numeric(rownames(data.train))
data.test <- Default[-train_index, ]

1
Вы хотели использовать Default[-train_index,]для последней строки.
Мэтт Л.

5

Если вы введете:

?sample

Если запустить меню справки, чтобы объяснить, что означают параметры функции образца.

Я не эксперт, но вот код, который у меня есть:

data <- data.frame(matrix(rnorm(400), nrow=100))
splitdata <- split(data[1:nrow(data),],sample(rep(1:4,as.integer(nrow(data)/4))))
test <- splitdata[[1]]
train <- rbind(splitdata[[1]],splitdata[[2]],splitdata[[3]])

Это даст вам 75% тренировку и 25% тест.


5

После просмотра всех различных методов, опубликованных здесь, я не увидел, чтобы кто-то использовал TRUE/FALSEдля выбора и отмены выбора данных. Поэтому я решил поделиться методом, использующим эту технику.

n = nrow(dataset)
split = sample(c(TRUE, FALSE), n, replace=TRUE, prob=c(0.75, 0.25))

training = dataset[split, ]
testing = dataset[!split, ]

объяснение

Есть несколько способов выбора данных из R, чаще всего люди используют положительные / отрицательные индексы для выбора / отмены выбора соответственно. Тем не менее, те же функциональные возможности могут быть достигнуты с помощьюTRUE/FALSE выбора / отмены выбора.

Рассмотрим следующий пример.

# let's explore ways to select every other element
data = c(1, 2, 3, 4, 5)


# using positive indices to select wanted elements
data[c(1, 3, 5)]
[1] 1 3 5

# using negative indices to remove unwanted elements
data[c(-2, -4)]
[1] 1 3 5

# using booleans to select wanted elements
data[c(TRUE, FALSE, TRUE, FALSE, TRUE)]
[1] 1 3 5

# R recycles the TRUE/FALSE vector if it is not the correct dimension
data[c(TRUE, FALSE)]
[1] 1 3 5

4

Мое решение перетасовывает строки, а затем принимает первые 75% рядов в качестве последовательности и последние 25% в качестве теста. Супер просто!

row_count <- nrow(orders_pivotted)
shuffled_rows <- sample(row_count)
train <- orders_pivotted[head(shuffled_rows,floor(row_count*0.75)),]
test <- orders_pivotted[tail(shuffled_rows,floor(row_count*0.25)),]

4

Я могу предложить использовать пакет rsample:

# choosing 75% of the data to be the training data
data_split <- initial_split(data, prop = .75)
# extracting training data and test data as two seperate dataframes
data_train <- training(data_split)
data_test  <- testing(data_split)

3

scorecard Пакет имеет полезную функцию для этого, где вы можете указать соотношение и семян

library(scorecard)

dt_list <- split_df(mtcars, ratio = 0.75, seed = 66)

Данные испытаний и поезда, хранятся в виде списка и может быть доступно призванием dt_list$trainиdt_list$test


2

Ниже представлена ​​функция, которая создает listподвыборки того же размера, что не совсем то, что вы хотели, но может оказаться полезным для других. В моем случае, чтобы создать несколько деревьев классификации на небольших выборках, чтобы проверить их соответствие:

df_split <- function (df, number){
  sizedf      <- length(df[,1])
  bound       <- sizedf/number
  list        <- list() 
  for (i in 1:number){
    list[i] <- list(df[((i*bound+1)-bound):(i*bound),])
  }
  return(list)
}

Пример :

x <- matrix(c(1:10), ncol=1)
x
# [,1]
# [1,]    1
# [2,]    2
# [3,]    3
# [4,]    4
# [5,]    5
# [6,]    6
# [7,]    7
# [8,]    8
# [9,]    9
#[10,]   10

x.split <- df_split(x,5)
x.split
# [[1]]
# [1] 1 2

# [[2]]
# [1] 3 4

# [[3]]
# [1] 5 6

# [[4]]
# [1] 7 8

# [[5]]
# [1] 9 10

2

Использование пакета caTools в примере кода R будет выглядеть следующим образом:

data
split = sample.split(data$DependentcoloumnName, SplitRatio = 0.6)
training_set = subset(data, split == TRUE)
test_set = subset(data, split == FALSE)

2

Используйте основание R. Функция runifгенерирует равномерно распределенные значения от 0 до 1. При изменении значения отсечения (train.size в примере ниже) у вас всегда будет примерно одинаковый процент случайных записей ниже значения отсечения.

data(mtcars)
set.seed(123)

#desired proportion of records in training set
train.size<-.7
#true/false vector of values above/below the cutoff above
train.ind<-runif(nrow(mtcars))<train.size

#train
train.df<-mtcars[train.ind,]


#test
test.df<-mtcars[!train.ind,]

Это было бы намного лучшим ответом, если бы он показал дополнительные пары строк для фактического создания обучающих и тестовых наборов (с которыми часто борются новички).
Грегор Томас

2

Предполагая, что df - ваш фрейм данных, и что вы хотите создать 75% -й поезд и 25% -ый тест

all <- 1:nrow(df)
train_i <- sort(sample(all, round(nrow(df)*0.75,digits = 0),replace=FALSE))
test_i <- all[-train_i]

Затем создать поезд и проверить кадры данных

df_train <- df[train_i,]
df_test <- df[test_i,]

1
require(caTools)

set.seed(101)            #This is used to create same samples everytime

split1=sample.split(data$anycol,SplitRatio=2/3)

train=subset(data,split1==TRUE)

test=subset(data,split1==FALSE)

sample.split()Функция добавит один дополнительный столбец «split1» в dataframe и 2/3 строк будет иметь это значение как TRUE , и другие , как FALSE.Now строки , где split1 является TRUE , будет скопирована в поезде и другие строки будут скопированы в тесте dataframe.


1

Я столкнулся с этим, это может помочь тоже.

set.seed(12)
data = Sonar[sample(nrow(Sonar)),]#reshufles the data
bound = floor(0.7 * nrow(data))
df_train = data[1:bound,]
df_test = data[(bound+1):nrow(data),]

1

Мы можем разделить данные на определенное соотношение, здесь оно составляет 80% и 20% в тестовом наборе данных.

ind <- sample(2, nrow(dataName), replace = T, prob = c(0.8,0.2))
train <- dataName[ind==1, ]
test <- dataName[ind==2, ]

0

Остерегайтесь sampleрасщепления, если вы ищете воспроизводимые результаты. Если ваши данные изменятся даже незначительно, разделение будет отличаться, даже если вы используете set.seed. Например, представьте, что отсортированный список идентификаторов в ваших данных - это все числа от 1 до 10. Если вы просто отбросите одно наблюдение, скажем, 4, выборка по местоположению даст другие результаты, потому что теперь 5-10 всех перемещенных мест.

Альтернативный метод заключается в использовании хэш-функции для сопоставления идентификаторов некоторым псевдослучайным числам, а затем выборки по модулю этих чисел. Этот образец более стабилен, потому что назначение теперь определяется хешем каждого наблюдения, а не его относительным положением.

Например:

require(openssl)  # for md5
require(data.table)  # for the demo data

set.seed(1)  # this won't help `sample`

population <- as.character(1e5:(1e6-1))  # some made up ID names

N <- 1e4  # sample size

sample1 <- data.table(id = sort(sample(population, N)))  # randomly sample N ids
sample2 <- sample1[-sample(N, 1)]  # randomly drop one observation from sample1

# samples are all but identical
sample1
sample2
nrow(merge(sample1, sample2))

[1] 9999

# row splitting yields very different test sets, even though we've set the seed
test <- sample(N-1, N/2, replace = F)

test1 <- sample1[test, .(id)]
test2 <- sample2[test, .(id)]
nrow(test1)

[1] 5000

nrow(merge(test1, test2))

[1] 2653

# to fix that, we can use some hash function to sample on the last digit

md5_bit_mod <- function(x, m = 2L) {
  # Inputs: 
  #  x: a character vector of ids
  #  m: the modulo divisor (modify for split proportions other than 50:50)
  # Output: remainders from dividing the first digit of the md5 hash of x by m
  as.integer(as.hexmode(substr(openssl::md5(x), 1, 1)) %% m)
}

# hash splitting preserves the similarity, because the assignment of test/train 
# is determined by the hash of each obs., and not by its relative location in the data
# which may change 
test1a <- sample1[md5_bit_mod(id) == 0L, .(id)]
test2a <- sample2[md5_bit_mod(id) == 0L, .(id)]
nrow(merge(test1a, test2a))

[1] 5057

nrow(test1a)

[1] 5057

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

Смотрите также: http://blog.richardweiss.org/2016/12/25/hash-splits.html и /crypto/20742/statistical-properties-of-hash-functions-when вычисляют-модулю


Добавлен отдельным вопросом: stackoverflow.com/questions/52769681/…
dzeltzer

Я хочу разработать модель auto.arima из данных нескольких временных рядов и хочу использовать данные за 1 год, данные за 3 года, 5, 7 ... с интервалом в два года из каждой серии, чтобы построить модель и протестировать ее в оставшийся набор для тестирования. Как мне сделать поднабор, чтобы у подобранной модели было то, что я хочу? Я благодарен за вашу помощь
Stackuser


-2

Существует очень простой способ выбрать количество строк, используя индекс R для строк и столбцов. Это позволяет вам ЧИСТО разделить набор данных по количеству строк - скажем, первые 80% ваших данных.

В R все строки и столбцы индексируются, поэтому DataSetName [1,1] - это значение, назначенное первому столбцу и первой строке «DataSetName». Я могу выбрать строки, используя [x,] и столбцы, используя [, x]

Например: если у меня есть набор данных с удобным названием «data» с 100 строками, я могу просмотреть первые 80 строк, используя

Просмотр (данные [1:80,])

Таким же образом я могу выбрать эти строки и установить их подстановки, используя:

поезд = данные [1:80,]

тест = данные [81: 100,]

Теперь мои данные разбиты на две части без возможности повторной выборки. Быстро и просто.


1
Хотя это правда, что данные могут быть разделены таким образом, это не рекомендуется. Некоторые наборы данных упорядочены по переменной, о которой вы не знаете. Поэтому лучше всего выбирать, какие строки будут считаться тренировочными, а не брать первые n строк.
user5029763

1
Если вы перетасуете данные, прежде чем разделить их на тестовый и обучающий набор, ваше предложение сработает.
Хадидж
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.