2012-11-23 65 views
15

我試圖對R,2/3進行訓練和1/3進行測試。我有一個分類變量和七個數值變量。每個觀察分類爲A,B,C或D.基於多個觀測類別在r中對數據集進行分區

爲簡單起見,假設分類變量c1對於前100個觀察值是A,對於觀察101到200,C到300是B ,D到400.我試圖得到一個分區,其中A,B,C和D中的每一個都有2/3的觀測值(而不是簡單地獲取整個數據集的2/3觀測值因爲它可能不會有相同數量的每個分類)。

當我嘗試從數據的子集中進行採樣(如sample(subset(data, cl=='A')))時,列將被重新排序而不是行。總而言之,我的目標是將A,B,C和D各自的67個隨機觀測值作爲我的訓練數據,並將A,B,C和D中每一個的其餘33個觀測值存儲爲測試數據數據。我發現了一個非常類似的問題,但它沒有考慮到多個變量。

回答

5

這可能會更長,但我認爲它更直觀,可以在基礎R完成;)

# create the data frame you've described 
x <- 
    data.frame(
     cl = 
      c( 
       rep('A' , 100) , 
       rep('B' , 100) , 
       rep('C' , 100) , 
       rep('D' , 100) 
      ) , 

     othernum1 = rnorm(400) , 
     othernum2 = rnorm(400) , 
     othernum3 = rnorm(400) , 
     othernum4 = rnorm(400) , 
     othernum5 = rnorm(400) , 
     othernum6 = rnorm(400) , 
     othernum7 = rnorm(400) 
    ) 

# sample 67 training rows within classification groups 
training.rows <- 
    tapply( 
     # numeric vector containing the numbers 
     # 1 to nrow(x) 
     1:nrow(x) , 

     # break the sample function out by 
     # the classification variable 
     x$cl , 

     # use the sample function within 
     # each classification variable group 
     sample , 

     # send the size = 67 parameter 
     # through to the sample() function 
     size = 67 
    ) 

# convert your list back to a numeric vector 
tr <- unlist(training.rows) 

# split your original data frame into two: 

# all the records sampled as training rows 
training.df <- x[ tr , ] 

# all other records (NOT sampled as training rows) 
testing.df <- x[ -tr , ] 
+0

太棒了!我還沒有聽說過無名單功能。這似乎正是我想要的,並且比我最終做的更短。 – Danny

4

下面將一個set柱值"train""test"添加到您的data.frame:

library(plyr) 
df <- ddply(df, "cl", transform, set = sample(c("train", "test"), length(cl), 
               replace = TRUE, prob = c(2, 1))) 

您可以使用基本ave功能得到類似的東西,但我覺得ddply很乾淨(讀取)爲這個特殊用法。

train.data <- subset(df, set == "train") 
test.data <- subset(df, set == "test") 

後續:

然後,您可以使用subset功能分割你的數據,每個組拆分成完全相同2/3和1/3的大小,你可以使用:

df <- ddply(df, "cl", transform, 
      set = sample(c(rep("train", round(2/3 * length(cl)), 
          rep("test", round(1/3 * length(cl))))) 
+0

你的意思是轉換,而不是總結? – frankc

+0

@frankc。對了謝謝。固定。 – flodel

+0

我可能對此有錯,但看起來這可能不會每次都給我每組2/3。這不就是說這個概率是2/3嗎?我的問題是,我每次都需要67個組。 – Danny

16

其實有一個很好的包裝插入符用於處理機器學習問題,它包含一個函數createDataPartition()這幾乎做到這一點取樣從供給因素的每個級別2 /三分之二:

#2/3rds for training 
library(caret) 
inTrain = createDataPartition(df$yourFactor, p = 2/3, list = FALSE) 
dfTrain=df[inTrain,] 
dfTest=df[-inTrain,] 
+0

這工作就像一個魅力 – salvu

1

碰到這個問題,同時構建我自己的函數分區數據交叉驗證與多個因素分層。您可以通過將數據分成3個(或N個)相同大小的部分來構建這樣的數據集,同時將每個分層內的觀測值等分爲部分,然後選擇三分之一作爲測試集,然後將剩餘部分組合爲訓練集。我會處理如列表 R中的元素。

這是一個函數,我使用支持多個分層因子的基礎包構建,表示爲希望作爲分層的字段的列編號或列名稱(mtcars數據集示例)。我認爲這是在功能上ddply頗爲相似,不同之處在於,你也可以使用列數和所產生的子集一個列表內給出:

# Function that partitions data into a number of equally (or almost-equally) sized bins that do not overlap, and returns the data bins as a list 
# Useful for cross validation 
partition_data <- function(
    # Data frame to partition (default example: mtcars data, assuming rows correspond to observations) 
    dat = mtcars, 
    # Number of equally sized bins to partition to (default here: 2 bins) 
    bins = 2, 
    # Stratification element, homogeneous subpopulations according to a column that should be subsampled, 
    # Observations within a substrata are divided equally to the partitioned bins 
    stratum = NA 
){ 
    # Total number of observations 
    nobs <- dim(dat)[1] 
    # Allocation vector, to be used for randomly distributing the samples to the bins 
    loc <- rep(1:bins, times=ceiling(nobs/bins))[1:nobs] 


    # If the dataset is stratified, each subpopulation is distributed equally to the bins, otherwise the whole population is the "subpopulation" 
    if(missing(stratum)){ 
     pops <- list(sample(1:dim(dat)[1])) 
    }else{ 
     uniqs <- na.omit(as.matrix(unique(dat[,stratum]))) 
     pops <- list() 
     for(i in 1:nrow(uniqs)){ 
      # If some of the stratified fields include NA-values, these will not be included in the sampling 
      w <- apply(as.matrix(dat[,stratum]), MARGIN=1, FUN=function(x) all(x==uniqs[i,])) 
      pops[[i]] <- sample(which(w)) 
     } 
    } 
    indices <- vector(length=nobs) 
    # Assign the group indices according to permutated samples within each subpopulation 
    indices[unlist(pops)] <- loc 
    # Assign observations to separate locations in a list 
    partitioned_data <- lapply(unique(indices), FUN=function(x) dat[x==indices,]) 
    # Return the result 
    partitioned_data 
} 

它是如何工作的實例;在這個假設的例子人願意爲「VS」的因素和「AM」在所有的垃圾箱中平等地表示:

set.seed(1) 

# Stratified sampling, so that combinations of binary covariates vs = {0,1} & am = {0,1} appear equally over the randomized bins of data 
pt <- partition_data(mtcars, stratum=c("vs", "am"), bins=3) 

# Instances are distributed equally 
lapply(pt, FUN=function(x) table(x[,c("vs","am")])) 
#> lapply(pt, FUN=function(x) table(x[,c("vs","am")])) 
#[[1]] 
# am 
#vs 0 1 
# 0 4 2 
# 1 3 2 
# 
#[[2]] 
# am 
#vs 0 1 
# 0 4 2 
# 1 2 3 
# 
#[[3]] 
# am 
#vs 0 1 
# 0 4 2 
# 1 2 2 

# 10 or 11 samples (=rows) per partition of data (data had 11 columns) 
lapply(pt, FUN=dim) 

# Training set containing 2/3 of the stratified samples 
# Constructed by dropping out the first third of samples 

train <- do.call("rbind", pt[-1]) 

# Test set containing the remaining 1/3 

test <- pt[[1]] 

# 21 samples in training dataset 
print(dim(train)) 
# 11 samples in testing dataset 
print(dim(test)) 



> print(train) 
        mpg cyl disp hp drat wt qsec vs am gear carb 
Mazda RX4 Wag  21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 
Datsun 710   22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 
Hornet 4 Drive  21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 
Merc 450SE   16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3 
Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4 
Fiat 128   32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1 
Toyota Corona  21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1 
Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2 
Camaro Z28   13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4 
Ford Pantera L  15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4 
Volvo 142E   21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2 
Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2 
Duster 360   14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4 
Merc 230   22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2 
Merc 280   19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4 
Merc 450SLC  15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3 
Honda Civic  30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2 
Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2 
Porsche 914-2  26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2 
Lotus Europa  30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2 
Ferrari Dino  19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6 
> print(test) 
        mpg cyl disp hp drat wt qsec vs am gear carb 
Mazda RX4   21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 
Valiant    18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 
Merc 240D   24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2 
Merc 280C   17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4 
Merc 450SL   17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3 
Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4 
Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4 
Toyota Corolla  33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1 
AMC Javelin   15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2 
Fiat X1-9   27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1 
Maserati Bora  15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8 


# Example of sampling without stratification; the binary covariates 'vs' and 'am' are probably not distributed equally over the bins 
lapply(pt2 <- partition_data(mtcars, bins=3), FUN=function(x) table(x[,c("vs","am")])) 

# Stratified according to a single covariate (cylinders) 
lapply(pt3 <- partition_data(mtcars, stratum="cyl", bins=3), FUN=function(x) table(x[,c("cyl")])) 

在討論這個特定的數據集,與安東尼的回答data.frame:

xpt <- partition_data(x, stratum="cl", bins=3) 
# Same as: 
#xpt <- partition_data(x, stratum=1, bins=3) 

train_xpt <- do.call("rbind", xpt[-1]) 
test_xpt <- xpt[[1]] 
#> summary(train_xpt[,"cl"]) 
# A B C D 
#67 66 67 67 
#> summary(test_xpt[,"cl"]) 
# A B C D 
#33 34 33 33 
相關問題