วิธีแบ่งข้อมูลออกเป็นชุดฝึกอบรม / ทดสอบโดยใช้ฟังก์ชั่นตัวอย่าง


160

ฉันเพิ่งเริ่มใช้ R และฉันไม่แน่ใจว่าจะรวมชุดข้อมูลของฉันกับโค้ดตัวอย่างต่อไปนี้:

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

ฉันมีชุดข้อมูลที่ฉันต้องใช้ในการฝึกอบรม (75%) และชุดการทดสอบ (25%) ฉันไม่แน่ใจว่าฉันควรใส่ข้อมูลอะไรลงไปในขนาดและ x? x เป็นชุดข้อมูลและขนาดเท่าไรที่ฉันมี?


1
xสามารถเป็นดัชนี (แถว / คอลัมน์ Nos. กล่าวว่า) 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?
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 ตลอด ขอบคุณ
Chetan Sharma

1
sample = sample.split(data[,1], SplitRatio = .75)ควรลบความจำเป็นในการตั้งชื่อคอลัมน์
Benjamin Ziepert

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 คืออะไร ฉันคิดว่าคุณหมายถึง sub_train data ต้นฉบับเฟรม ดังนั้นรหัสที่ได้รับการแก้ไขควรเป็นการฝึกอบรม <-sub_train [intrain,] และการทดสอบ <-sub_train [-intrain,] ฉันสงสัยว่าทำไมไม่มีใครสามารถเห็นปัญหาที่สำคัญนี้กับคุณตอบในช่วงห้าปีที่ผ่านมา!
mnm

21

ฉันจะแยก 'a' ลงในรถไฟ (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

คำตอบนี้ช่วยฉันได้ แต่ฉันต้องปรับแต่งเพื่อให้ได้ผลลัพธ์ที่คาดหวัง เช่นเดียวกับชุดข้อมูล 'train' มี rownames = sid ของจำนวนเต็มต่อเนื่อง: 1,2,3,4, ... ในขณะที่คุณต้องการให้ sid เป็น rownumber จากชุดข้อมูลดั้งเดิม 'a' ซึ่งจะถูกสุ่มเลือก ไม่ใช่จำนวนเต็มตามลำดับ ดังนั้นจึงจำเป็นต้องสร้างตัวแปร id ใน 'a' ก่อน
Scott Murff

row.names (mtcars) <- NULL; รถไฟ <-dplyr :: sample_frac (mtcars, 0.5); ทดสอบ <-mtcars [-as.numeric (row.names (รถไฟ))] # ฉันทำอย่างนี้กับข้อมูลของฉันรหัสเดิมไม่ทำงานถ้าชื่อแถวของคุณถูกกำหนดให้เป็นตัวเลขแล้ว
คริสจอห์น

16

โซลูชันของฉันนั้นเหมือนกับของ dickoa แต่ตีความได้ง่ายขึ้นเล็กน้อย:

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,]สำหรับบรรทัดสุดท้าย
Matt L.

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% สุดท้ายเป็นการทดสอบ 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

ฉันสามารถแนะนำให้ใช้แพ็คเกจ 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ย่อยที่มีขนาดเท่ากันซึ่งไม่ใช่สิ่งที่คุณต้องการอย่างแน่นอน แต่อาจพิสูจน์ได้ว่ามีประโยชน์สำหรับผู้อื่น ในกรณีของฉันเพื่อสร้างแผนภูมิการจำแนกหลายต้นบนตัวอย่างขนาดเล็กเพื่อทดสอบการ overfitting:

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

ใช้ฟังก์ชั่นฐานอาร์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,]

นี่จะเป็นคำตอบที่ดียิ่งขึ้นถ้ามันแสดงให้เห็นว่าคู่พิเศษที่จะสร้างชุดฝึกอบรมและการทดสอบ (ซึ่งมือใหม่มักจะต่อสู้ด้วย)
Gregor Thomas

2

สมมติว่าdfเป็น data frame ของคุณและคุณต้องการสร้างรถไฟ 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 เป็นจริงจะได้รับการคัดลอกลงในรถไฟและแถวอื่น ๆ จะถูกคัดลอกไปทดสอบ 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 สถานที่ที่ย้ายทั้งหมด

อีกทางเลือกหนึ่งคือการใช้ฟังก์ชันแฮชเพื่อจับคู่รหัสเข้ากับตัวเลขสุ่มหลอกและจากนั้นสุ่มตัวอย่าง mod ของตัวเลขเหล่านี้ ตัวอย่างนี้มีเสถียรภาพมากขึ้นเนื่องจากการกำหนดถูกกำหนดโดยแฮชของการสังเกตแต่ละครั้งและไม่ใช่โดยตำแหน่งสัมพัทธ์

ตัวอย่างเช่น:

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

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 -calculating-โมดูโล


เพิ่มเป็นคำถามแยกต่างหาก: stackoverflow.com/questions/52769681/…
dzeltzer

ฉันต้องการพัฒนาโมเดล auto.arima จากข้อมูลอนุกรมเวลาหลายชุดและฉันต้องการใช้ข้อมูล 1 ปี, ข้อมูล 3 ปี, 5, 7 ... ในช่วงเวลาสองปีจากแต่ละชุดเพื่อสร้างแบบจำลองและทดสอบใน ชุดทดสอบที่เหลืออยู่ ฉันจะเซ็ตย่อยอย่างไรเพื่อที่โมเดลที่ติดตั้งจะมีสิ่งที่ฉันต้องการ? ฉันขอขอบคุณสำหรับความช่วยเหลือของคุณ
Stackuser


-2

มีวิธีที่ง่ายมากในการเลือกจำนวนแถวโดยใช้ดัชนี R สำหรับแถวและคอลัมน์ สิ่งนี้จะช่วยให้คุณแยกชุดข้อมูลที่กำหนดจำนวนแถวได้อย่างชัดเจน - พูด 80% แรกของข้อมูลของคุณ

ใน R แถวและคอลัมน์ทั้งหมดถูกทำดัชนีดังนั้น DataSetName [1,1] คือค่าที่กำหนดให้กับคอลัมน์แรกและแถวแรกของ "DataSetName" ฉันสามารถเลือกแถวโดยใช้ [x,] และคอลัมน์ที่ใช้ [, x]

ตัวอย่างเช่น: หากฉันมีชุดข้อมูลชื่อ "ข้อมูล" ที่สะดวกด้วย 100 แถวฉันสามารถดู 80 แถวแรกโดยใช้

View (ข้อมูล [1:80])

ในทำนองเดียวกันฉันสามารถเลือกแถวเหล่านี้และเซตย่อยโดยใช้:

รถไฟ = ข้อมูล [1:80,]

ทดสอบ = ข้อมูล [81: 100,]

ตอนนี้ฉันมีข้อมูลของฉันแบ่งออกเป็นสองส่วนโดยไม่มีความเป็นไปได้ของการสุ่มใหม่ ง่ายและรวดเร็ว


1
แม้ว่าจะเป็นความจริงที่ว่าข้อมูลสามารถแยกได้ด้วยวิธีนี้ แต่ก็ไม่แนะนำ ชุดข้อมูลบางชุดได้รับคำสั่งจากตัวแปรที่คุณไม่ทราบ ดังนั้นวิธีที่ดีที่สุดในการสุ่มตัวอย่างแถวใดจะถูกพิจารณาว่าเป็นการฝึกอบรมแทนที่จะใช้แถวแรก
user5029763

1
หากคุณสุ่มข้อมูลก่อนที่จะแยกพวกมันออกเป็นชุดทดสอบและฝึกอบรมคำแนะนำของคุณจะใช้ได้
Hadij
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.