Jak podzielić dane na zbiory uczące / testowe przy użyciu funkcji przykładowej


160

Właśnie zacząłem używać języka R i nie jestem pewien, jak włączyć mój zestaw danych do następującego przykładowego kodu:

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

Mam zbiór danych, który muszę umieścić w zestawie treningowym (75%) i testowym (25%). Nie jestem pewien, jakie informacje mam umieścić w x i rozmiarze? Czy x jest plikiem zestawu danych i ile mam próbek?


1
xmoże być indeksem (wiersz / kol., powiedz) twojego data. sizemoże być 0.75*nrow(data). Spróbuj sample(1:10, 4, replace = FALSE, prob = NULL)zobaczyć, co to robi.
harkmug

Odpowiedzi:


255

Istnieje wiele podejść do partycjonowania danych. Aby uzyskać pełniejsze podejście, przyjrzyj się createDataPartitionfunkcji w caToolspakiecie.

Oto prosty przykład:

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, ]

Jestem trochę zdezorientowany, co gwarantuje, że ten kod zwraca unikalny test i trenuje df? Wydaje się, że działa, nie zrozum mnie źle. Mam problem ze zrozumieniem, w jaki sposób odejmowanie indeksów prowadzi do unikalnych obserwacji. Na przykład, jeśli masz df z 10 wierszami i jedną kolumną, a jedna kolumna zawiera 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 i postępujesz zgodnie z tym kodem, co uniemożliwia pociągowi indeks 4 i test mający również -6 -> 10 - 6 = 4?
goldisfine

1
podziękować. Próbowałem mtcars[!train_ind]i chociaż nie powiodło się, nie działało zgodnie z oczekiwaniami. Jak mogę podzbiór za pomocą !?
user989762

@ user989762 !są używane dla logicznych ( TRUE/FALSE), a nie indeksów. Jeśli chcesz !podzielić podzbiór przy użyciu , spróbuj czegoś takiego jak mtcars [ !seq_len(nrow(mtcars)) %in% train_ind,] (nie testowane).
dickoa

1
@VedaadShakib kiedy używasz "-" pomija cały indeks w train_ind z twoich danych. Spójrz na adv-r.had.co.nz/Subsetting.html . Mam nadzieję, że to pomoże
dickoa

1
Nie jest createDataPartitionw caretnie caTools?
J. Mini

93

Można to łatwo zrobić poprzez:

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, ]

Korzystając z pakietu caTools :

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

4
Niedawno odbyłem kurs z MIT i przez cały czas używali tego podejścia przy użyciu caTools. Dzięki
Chetan Sharma

1
sample = sample.split(data[,1], SplitRatio = .75)Powinno usunąć potrzebę nazwania kolumny.
Benjamin Ziepert

33

Użyłbym dplyrdo tego, czyni to bardzo prostym. Wymaga zmiennej id w zestawie danych, co i tak jest dobrym pomysłem, nie tylko do tworzenia zestawów, ale także do śledzenia podczas projektu. Dodaj, jeśli jeszcze nie zawiera.

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

28

To jest prawie ten sam kod, ale w ładniejszym wyglądzie

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

Tak! Ładny wygląd!
MeenakshiSundharam

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

3
Chociaż odpowiedzią jest tylko kod, lepiej jest podać jakieś wyjaśnienie.
C8H10N4O2

co to jest m_train? Myślę, że miałeś na myśli, pod_trenowanie oryginalnej ramki data.frame. Dlatego poprawiony kod powinien szkolić <-sub_train [intrain,] i testować <-sub_train [-intrain,]. Zastanawiam się, dlaczego w ciągu ostatnich pięciu lat nikt nie był w stanie dostrzec tego poważnego problemu z Twoją odpowiedzią!
mnm

21

Podzielę `` a '' na pociąg (70%) i przetestuję (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,]

Gotowe


4
musisz zaimportować pakiet dpyr, wymagaj (dplyr)
TheMI

Ta odpowiedź pomogła mi, ale musiałem ją poprawić, aby uzyskać oczekiwane rezultaty. W obecnej sytuacji zbiór danych „pociąg” ma rownames = sid sekwencyjnych liczb całkowitych: 1, 2, 3, 4, ... podczas gdy chcesz, aby sid były numerami wierszowymi z oryginalnego zbioru danych „a”, które wygrywają, ponieważ są losowo wybrane nie mogą być sekwencyjnymi liczbami całkowitymi. Dlatego konieczne jest najpierw utworzenie zmiennej id na „a”.
Scott Murff

row.names (mtcars) <- NULL; pociąg <-dplyr :: sample_frac (mtcars, 0.5); test <-mtcars [-as.numeric (row.names (pociąg)),] # Zrobiłem to z moimi danymi, oryginalny kod nie działa, jeśli nazwy wierszy są już ustawione na liczby
Christopher John

16

Moje rozwiązanie jest w zasadzie takie samo jak dickoa, ale trochę łatwiejsze do zinterpretowania:

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

Jaka jest zmienna szwajcarski?
billmccord

7

Po prostu bardziej zwięzły i prosty sposób przy użyciu niesamowitej biblioteki 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
Czy chodziło Ci o użycie Default[-train_index,]w ostatniej linii.
Matt L.

5

Jeśli wpiszesz:

?sample

Jeśli uruchomi menu pomocy, aby wyjaśnić, co oznaczają parametry przykładowej funkcji.

Nie jestem ekspertem, ale mam kod:

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]])

To da ci 75% pociąg i 25% test.


5

Po przejrzeniu wszystkich zamieszczonych tutaj metod, nie widziałem nikogo używającego TRUE/FALSEdo wybierania i odznaczania danych. Pomyślałem więc, że podzielę się metodą wykorzystującą tę technikę.

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

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

Wyjaśnienie

Istnieje wiele sposobów wybierania danych z R, najczęściej ludzie używają indeksów dodatnich / ujemnych, aby odpowiednio zaznaczyć / odznaczyć. Jednak te same funkcje można osiągnąć za pomocąTRUE/FALSE do zaznaczania / odznaczania.

Rozważmy następujący przykład.

# 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

Moje rozwiązanie tasuje rzędy, następnie traktuję pierwsze 75% rzędów jako pociąg, a ostatnie 25% jako test. Super proste!

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

Mogę zasugerować użycie pakietu 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 pakiet ma do tego przydatną funkcję, w której możesz określić współczynnik i ziarno

library(scorecard)

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

Dane dotyczące testu i pociągu są przechowywane na liście i można uzyskać do nich dostęp, dzwoniąc dt_list$trainidt_list$test


2

Poniżej funkcja, która tworzy listpodpróbki o tym samym rozmiarze, co nie jest dokładnie tym, czego chciałeś, ale może okazać się przydatne dla innych. W moim przypadku, aby utworzyć wiele drzew klasyfikacyjnych na mniejszych próbach, aby przetestować nadmierne dopasowanie:

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)
}

Przykład:

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

Użyj pakietu caTools w przykładowym kodzie R będzie wyglądać następująco: -

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

2

Użyj podstawy R. Funkcja runifgeneruje równomiernie rozłożone wartości od 0 do 1, zmieniając wartość odcięcia (rozmiar pociągu w przykładzie poniżej), zawsze będziesz mieć mniej więcej taki sam procent losowych rekordów poniżej wartości odcięcia.

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,]

Byłaby to znacznie lepsza odpowiedź, gdyby pokazywała dodatkowe kilka linii, które faktycznie tworzą zestawy treningowe i testowe (z którymi początkujący często mają problemy).
Gregor Thomas,

2

Zakładając, że df jest twoją ramką danych i chcesz ją utworzyć 75% pociąg i 25% test

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

Następnie utwórz pociąg i przetestuj ramki danych

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()Funkcja dodać jedną dodatkową kolumnę „Podziel1” do dataframe i 2/3 wiersze będą miały tę wartość jako prawdziwy i innych jako FALSE.Now wiersze gdzie Podziel1 jest prawdą zostaną skopiowane do pociągu i inne wiersze zostaną skopiowane do testu ramka danych.


1

Wpadłem na ten, to też może pomóc.

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

Możemy podzielić dane na określony stosunek tutaj jest to 80% pociągu i 20% w testowym zbiorze danych.

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

0

Uważaj samplena rozdzielanie, jeśli szukasz powtarzalnych wyników. Jeśli dane zmienią się nawet nieznacznie, podział będzie różny, nawet jeśli użyjeszset.seed . Na przykład, wyobraź sobie, że posortowana lista identyfikatorów w twoich danych zawiera wszystkie liczby od 1 do 10. Jeśli po prostu upuścisz jedną obserwację, powiedzmy 4, próbkowanie według lokalizacji przyniesie inne wyniki, ponieważ teraz od 5 do 10 wszystkich przeniesionych miejsc.

Alternatywną metodą jest użycie funkcji skrótu do mapowania identyfikatorów na niektóre liczby pseudolosowe, a następnie próbkowanie na modach tych liczb. Ta próbka jest bardziej stabilna, ponieważ przypisanie jest teraz określane na podstawie skrótu każdej obserwacji, a nie przez jej względną pozycję.

Na przykład:

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

wielkość próby nie jest dokładnie 5000, ponieważ przypisanie jest probabilistyczne, ale nie powinno to stanowić problemu w przypadku dużych próbek dzięki prawu dużych liczb.

Zobacz też: http://blog.richardweiss.org/2016/12/25/hash-splits.html i /crypto/20742/statistical-properties-of-hash-functions-when -calculating-modulo



Chcę opracować model auto.arima z wielu danych szeregów czasowych i chcę użyć danych 1 rok, 3 lata danych, 5, 7 ... w dwuletnich odstępach z każdej serii do zbudowania modelu i przetestowania go w pozostały zestaw testowy. Jak zrobić podzbiór, aby dopasowany model miał to, czego chcę? Doceniam twoją pomoc
Stackuser

0
set.seed(123)
llwork<-sample(1:length(mydata),round(0.75*length(mydata),digits=0)) 
wmydata<-mydata[llwork, ]
tmydata<-mydata[-llwork, ]

-2

Istnieje bardzo prosty sposób na wybranie liczby wierszy przy użyciu indeksu R dla wierszy i kolumn. Pozwala to CZYSTO podzielić zestaw danych na liczbę wierszy - powiedzmy pierwsze 80% danych.

W R wszystkie wiersze i kolumny są indeksowane, więc DataSetName [1,1] jest wartością przypisaną do pierwszej kolumny i pierwszego wiersza „DataSetName”. Mogę wybrać wiersze za pomocą [x,] i kolumny za pomocą [, x]

Na przykład: Jeśli mam zestaw danych o wygodnej nazwie „dane” ze 100 wierszami, mogę wyświetlić pierwsze 80 wierszy za pomocą

Wyświetl (dane [1:80,])

W ten sam sposób mogę zaznaczyć te wiersze i podzielić je za pomocą:

pociąg = dane [1:80,]

test = dane [81: 100,]

Teraz mam podzielone dane na dwie części bez możliwości ponownego próbkowania. Szybko i łatwo.


1
Chociaż prawdą jest, że dane można podzielić w ten sposób, nie jest to zalecane. Niektóre zbiory danych są uporządkowane według zmiennej, której nie znasz. Dlatego najlepiej jest próbkować, które wiersze będą uważane za treningowe, zamiast pobierać pierwsze n wierszy.
user5029763,

1
Jeśli pomieszasz dane przed rozdzieleniem ich na zestaw testowy i treningowy, Twoja sugestia zadziała.
Hadij
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.