Aufteilen von Daten in Trainings- / Testsätze mithilfe der Beispielfunktion


160

Ich habe gerade angefangen, R zu verwenden, und bin mir nicht sicher, wie ich meinen Datensatz mit dem folgenden Beispielcode integrieren soll:

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

Ich habe einen Datensatz, den ich in einen Trainings- (75%) und Testsatz (25%) einfügen muss. Ich bin nicht sicher, welche Informationen ich in x und Größe einfügen soll? Ist x die Dataset-Datei und wie viele Samples habe ich?


1
xkann der Index (z. B. Zeilen- / Spaltennummern) Ihres sein data. sizekann sein 0.75*nrow(data). Versuchen Sie sample(1:10, 4, replace = FALSE, prob = NULL)zu sehen, was es tut.
Harkmug

Antworten:


255

Es gibt zahlreiche Ansätze, um eine Datenpartitionierung zu erreichen. Für einen vollständigeren Ansatz werfen Sie einen Blick auf die createDataPartitionFunktion im caToolsPaket.

Hier ist ein einfaches Beispiel:

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

Ich bin ein wenig verwirrt, was garantiert, dass dieser Code einen einzigartigen Test zurückgibt und df trainiert? Es scheint zu funktionieren, versteh mich nicht falsch. Nur Probleme zu verstehen, wie das Subtrahieren der Indizes zu einzigartigen Beobachtungen führt. Wenn Sie beispielsweise eine df mit 10 Zeilen und einer Spalte hatten und die eine Spalte 1,2,3,4,5,6,7,8,9,10 enthielt und Sie diesem Code folgten, was verhindert, dass ein Zug hat Index 4 und Test mit -6 -> 10 - 6 = 4?
Goldfine

1
danken. Ich habe es versucht mtcars[!train_ind]und obwohl es nicht fehlgeschlagen ist, hat es nicht wie erwartet funktioniert. Wie könnte ich mit dem Subset !?
user989762

@ user989762 !werden für logische ( TRUE/FALSE) und nicht für Indizes verwendet. Wenn Sie eine Teilmenge mit verwenden möchten !, versuchen Sie etwas wie mtcars [ !seq_len(nrow(mtcars)) %in% train_ind,] (nicht getestet).
Dickoa

1
@VedaadShakib Wenn Sie "-" verwenden, wird der gesamte Index in train_ind aus Ihren Daten entfernt. Schauen Sie sich adv-r.had.co.nz/Subsetting.html an . Hoffe es hilft
Dickoa

1
Ist nicht createDataPartitionin caretund nicht caTools?
J. Mini

93

Es kann leicht gemacht werden durch:

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

Mit dem caTools- Paket:

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

4
Ich habe kürzlich einen Kurs mit MIT gemacht und sie haben den Ansatz durchgehend mit caTools verwendet. Vielen Dank
Chetan Sharma

1
sample = sample.split(data[,1], SplitRatio = .75)Sollte die Notwendigkeit beseitigen, eine Spalte zu benennen.
Benjamin Ziepert

33

Ich würde dafür verwenden dplyr, macht es super einfach. Es ist eine ID-Variable in Ihrem Datensatz erforderlich, was ohnehin eine gute Idee ist, nicht nur zum Erstellen von Sets, sondern auch zur Rückverfolgbarkeit während Ihres Projekts. Fügen Sie es hinzu, wenn es noch nicht enthalten ist.

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

28

Dies ist fast der gleiche Code, sieht aber schöner aus

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

Jep! Nettes Aussehen!
MeenakshiSundharam

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

3
Während eine Nur-Code-Antwort eine Antwort ist, ist es besser, eine Erklärung zu geben.
C8H10N4O2

Was ist m_train? Ich denke du meintest, sub_trainiere den ursprünglichen data.frame. Daher sollte der überarbeitete Code darin bestehen, <-sub_train [intrain,] zu trainieren und <sub_train [-intrain,] zu testen. Ich frage mich, warum in den letzten fünf Jahren niemand dieses große Problem mit Ihrer Antwort erkennen konnte!
Mnm

21

Ich werde 'a' in Zug (70%) und Test (30%) aufteilen.

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

getan


4
Sie müssen dpyr Paket importieren, benötigen (dplyr)
TheMI

Diese Antwort hat mir geholfen, aber ich musste sie optimieren, um die erwarteten Ergebnisse zu erzielen. Wie es ist, hat der Datensatz 'Zug' Rownamen = Sid von sequentiellen ganzen Zahlen: 1,2,3,4, ... während Sie möchten, dass Sid die Rownummern aus dem ursprünglichen Datensatz 'a' sind, die, da sie zufällig ausgewählt wurden, gewonnen haben Es sind nicht die sequentiellen ganzen Zahlen. Daher muss zuerst die ID-Variable auf 'a' erstellt werden.
Scott Murff

row.names (mtcars) <- NULL; train <-dplyr :: sample_frac (mtcars, 0,5); test <-mtcars [-as.numeric (row.names (train)),] # Ich habe dies mit meinen Daten gemacht, der ursprüngliche Code funktioniert nicht, wenn Ihre Zeilennamen bereits auf Zahlen gesetzt sind
Christopher John

16

Meine Lösung ist im Grunde die gleiche wie die von Dickoa, aber etwas einfacher zu interpretieren:

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

Was ist die Variable Schweiz?
Billmccord

7

Nur eine kurze und einfache Möglichkeit, die fantastische dplyr- Bibliothek zu verwenden:

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
Wollten Sie Default[-train_index,]für die letzte Zeile verwenden.
Matt L.

5

Wenn Sie Folgendes eingeben:

?sample

Wenn wird ein Hilfemenü gestartet, um zu erklären, was die Parameter der Beispielfunktion bedeuten.

Ich bin kein Experte, aber hier ist ein Code, den ich habe:

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

Dies gibt Ihnen 75% Zug und 25% Test.


5

Nachdem ich mir die verschiedenen hier veröffentlichten Methoden angesehen hatte, sah ich niemanden, TRUE/FALSEder Daten auswählte und abwählte. Also dachte ich, ich würde eine Methode teilen, die diese Technik verwendet.

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

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

Erläuterung

Es gibt mehrere Möglichkeiten, Daten aus R auszuwählen. Am häufigsten werden positive / negative Indizes zum Auswählen bzw. Abwählen verwendet. Die gleichen Funktionen können jedoch durch Verwendung erreicht werdenTRUE/FALSE Auswählen / Abwählen erreicht werden.

Betrachten Sie das folgende Beispiel.

# 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

Meine Lösung mischt die Reihen und nimmt dann die ersten 75% der Reihen als Zug und die letzten 25% als Test. Super simples!

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

Ich kann vorschlagen, das rsample-Paket zu verwenden:

# 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 Das Paket hat dafür eine nützliche Funktion, in der Sie das Verhältnis und den Startwert angeben können

library(scorecard)

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

Die Test- und Zugdaten werden in einer Liste gespeichert und können durch Aufrufen von dt_list$trainund abgerufen werdendt_list$test


2

Unten finden Sie eine Funktion, mit listder Teilproben derselben Größe erstellt werden, die nicht genau Ihren Wünschen entsprechen, sich aber für andere als nützlich erweisen können. In meinem Fall, um mehrere Klassifizierungsbäume für kleinere Stichproben zu erstellen, um die Überanpassung zu testen:

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

Beispiel:

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

Das caTools-Paket im R-Beispielcode lautet wie folgt: -

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

2

Verwenden Sie die Basis R. Die Funktion runifgeneriert gleichmäßig verteilte Werte von 0 bis 1. Durch Variieren des Grenzwerts (train.size im folgenden Beispiel) haben Sie immer ungefähr den gleichen Prozentsatz an Zufallsdatensätzen unter dem Grenzwert.

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

Dies wäre eine viel bessere Antwort, wenn die zusätzlichen paar Zeilen für die Erstellung der Trainings- und Testsätze (mit denen Neulinge häufig zu kämpfen haben) angezeigt würden.
Gregor Thomas

2

Angenommen, df ist Ihr Datenrahmen und Sie möchten 75% Zug und 25% Test erstellen

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

Dann erstellen Sie einen Zug und testen Datenrahmen

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)

Die sample.split()Funktion fügt dem Datenrahmen eine zusätzliche Spalte 'split1' hinzu und 2/3 der Zeilen haben diesen Wert als TRUE und andere als FALSE. Jetzt werden die Zeilen, in denen split1 TRUE ist, in den Zug kopiert und andere Zeilen werden zum Testen kopiert Datenrahmen.


1

Ich bin auf diesen gestoßen, es kann auch helfen.

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

Wir können Daten in ein bestimmtes Verhältnis unterteilen, hier sind es 80% Zug und 20% in einem Testdatensatz.

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

0

Achten Sie sampleauf die Aufteilung, wenn Sie nach reproduzierbaren Ergebnissen suchen. Wenn sich Ihre Daten nur geringfügig ändern, ändert sich die Aufteilung auch bei Verwendung set.seed. Stellen Sie sich zum Beispiel vor, die sortierte Liste der IDs in Ihren Daten enthält alle Zahlen zwischen 1 und 10. Wenn Sie nur eine Beobachtung fallen lassen, z. B. 4, würde die Stichprobe nach Standort zu anderen Ergebnissen führen, da jetzt 5 bis 10 alle Orte verschoben werden.

Eine alternative Methode besteht darin, eine Hash-Funktion zu verwenden, um IDs in einige Pseudozufallszahlen abzubilden und dann den Mod dieser Zahlen abzutasten. Diese Stichprobe ist stabiler, da die Zuordnung jetzt durch den Hash jeder Beobachtung und nicht durch ihre relative Position bestimmt wird.

Beispielsweise:

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

Die Stichprobengröße beträgt nicht genau 5000, da die Zuordnung wahrscheinlich ist, aber bei großen Stichproben sollte sie aufgrund des Gesetzes der großen Zahlen kein Problem darstellen.

Siehe auch: http://blog.richardweiss.org/2016/12/25/hash-splits.html und /crypto/20742/statistical-properties-of-hash-functions-when -berechnungsmodulo


Als separate Frage hinzugefügt
dzeltzer

Ich möchte das auto.arima-Modell aus mehreren Zeitreihendaten entwickeln und 1 Jahr Daten, 3 Jahre Daten, 5, 7 ... in einem Zweijahresintervall von jeder Serie verwenden, um das Modell zu erstellen und zu testen der verbleibende Testsatz. Wie mache ich die Teilmenge, damit das angepasste Modell das hat, was ich will? Ich
freue

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

-2

Es gibt eine sehr einfache Möglichkeit, eine Anzahl von Zeilen mithilfe des R-Index für Zeilen und Spalten auszuwählen. Auf diese Weise können Sie den Datensatz bei mehreren Zeilen SAUBER aufteilen - beispielsweise bei den ersten 80% Ihrer Daten.

In R sind alle Zeilen und Spalten indiziert, sodass DataSetName [1,1] der Wert ist, der der ersten Spalte und der ersten Zeile von "DataSetName" zugewiesen ist. Ich kann Zeilen mit [x,] und Spalten mit [, x] auswählen.

Zum Beispiel: Wenn ich einen Datensatz mit dem bequemen Namen "Daten" mit 100 Zeilen habe, kann ich die ersten 80 Zeilen mit anzeigen

Ansicht (Daten [1:80,])

Auf die gleiche Weise kann ich diese Zeilen auswählen und unterteilen:

Zug = Daten [1:80,]

Test = Daten [81: 100,]

Jetzt habe ich meine Daten in zwei Teile aufgeteilt, ohne dass die Möglichkeit eines erneuten Samplings besteht. Schnell und einfach.


1
Obwohl es wahr ist, dass Daten auf diese Weise aufgeteilt werden können, wird davon abgeraten. Einige Datensätze sind nach einer Variablen geordnet, die Sie nicht kennen. Es ist also am besten zu probieren, welche Zeilen als Training betrachtet werden, anstatt die ersten n Zeilen zu nehmen.
user5029763

1
Wenn Sie die Daten mischen, bevor Sie sie in Test- und Trainingssatz trennen, funktioniert Ihr Vorschlag.
Hadij
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.