Як розділити дані на навчальні / тестові набори за допомогою функції вибірки


160

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

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

У мене є набір даних, який мені потрібно вкласти в навчальний (75%) і тестовий (25%) набір. Я не впевнений, яку інформацію я повинен вкласти в розмір x і size? Чи 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]і хоча це не вийшло, не вийшло, як очікувалося. Як я можу підмножити за допомогою !?
користувач989762

@ user989762 !використовуються для логічного ( TRUE/FALSE), а не для індексів. Якщо ви хочете підмножитися за допомогою !, спробуйте щось на зразок mtcars [ !seq_len(nrow(mtcars)) %in% train_ind,] (не тестується).
dickoa

1
@VedaadShakib, коли ви використовуєте "-", він опускає весь індекс у train_ind з ваших даних. Погляньте на adv-r.had.co.nz/Subsetting.html . Сподіваюся, що це допомагає
dickoa

1
Не createDataPartitionв caretі ні caTools?
Дж. Міні

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 протягом усього часу. Спасибі
Chetan Sharma

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

Так! Гарний вигляд!
MeenakshiSundharam

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? Я думаю, ти мав на увазі, підпрограмуйте оригінальний data.frame. Отже, переглянутий код повинен бути тренінг <-sub_train [intrain,] та тестування <-sub_train [-intrain,]. Цікаво, чому ніхто не зміг помітити на цю головну проблему з вами відповідь за останні п’ять років!
mnm

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, вимагайте (dplyr)
TheMI

Ця відповідь допомогла мені, але мені потрібно було підправити її, щоб отримати очікувані результати. Так, набір даних "поїзд" має назви рядків = sid послідовних цілих чисел: 1,2,3,4, ... тоді як ви хочете, щоб sid був рядковими номерами з початкового набору даних "a", який, оскільки вони вибираються випадковим чином, виграється не будуть послідовними цілими числами. Отже, спочатку потрібно створити змінну id на "a".
Скотт Мерфф

рядок.імена (mtcars) <- NULL; поїзд <-dplyr :: sample_frac (mtcars, 0,5); test <-mtcars [-as.numeric (row.names (поїзд)),] # Я зробив це за моїми даними, оригінальний код не працює, якщо назви ваших рядків уже встановлені на цифри
Крістофер Джон

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.Будуючи різну величину відсікання (поїзд. Розмір у прикладі нижче), у вас завжди буде приблизно такий самий відсоток випадкових записів нижче значення відсікання.

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 , буде скопійована в поїзді і інші рядки будуть скопійовані в тесті фрейм даних.


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/statistic-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]

Наприклад: Якщо у мене є набір даних, зручно названий "дані", на 100 рядків, я можу переглянути перші 80 рядків за допомогою

Перегляд (дані [1:80,])

Таким же чином я можу вибрати ці рядки і підмножити їх за допомогою:

поїзд = дані [1:80,]

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

Тепер у мене дані розділені на дві частини без можливості перекомпонування. Швидко і просто.


1
Хоча це правда, що дані можна поділити таким чином, не рекомендується. Деякі набори даних упорядковуються змінною, про яку ви не знаєте. Тому найкраще відібрати, які рядки вважатимуться навчальними, а не взяти перші n рядків.
user5029763

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