私は15の異なるIDに広がる約50,000行で作成されたdfを持っています(すべてのIDには何千もの観測があります)。 dfは次のようになります。
ID Year Temp ph
1 P1 1996 11.3 6.80
2 P1 1996 9.7 6.90
3 P1 1997 9.8 7.10
...
2000 P2 1997 10.5 6.90
2001 P2 1997 9.9 7.00
2002 P2 1997 10.0 6.93
IDごとに500のランダムな行を取得し(P1には500、P2には500など)、新しいdfを作成します。私が試す:
new_df<-df[df$ID %in% sample(unique(dfID),500),]
しかし、ランダムに1つのIDが必要ですが、IDごとに500個のランダムな行が必要です。
これを試して:
library(plyr)
ddply(df,.(ID),function(x) x[sample(nrow(x),500),])
これはsample_n
dplyr
の関数:
library(dplyr)
new_df <- df %>% group_by(ID) %>% sample_n(500)
これがベースRの1つのアプローチです。
まず、使用する前提条件のサンプルデータ:
set.seed(1)
mydf <- data.frame(ID = rep(1:3, each = 5), matrix(rnorm(45), ncol = 3))
mydf
# ID X1 X2 X3
# 1 1 -0.6264538 -0.04493361 1.35867955
# 2 1 0.1836433 -0.01619026 -0.10278773
# 3 1 -0.8356286 0.94383621 0.38767161
# 4 1 1.5952808 0.82122120 -0.05380504
# 5 1 0.3295078 0.59390132 -1.37705956
# 6 2 -0.8204684 0.91897737 -0.41499456
# 7 2 0.4874291 0.78213630 -0.39428995
# 8 2 0.7383247 0.07456498 -0.05931340
# 9 2 0.5757814 -1.98935170 1.10002537
# 10 2 -0.3053884 0.61982575 0.76317575
# 11 3 1.5117812 -0.05612874 -0.16452360
# 12 3 0.3898432 -0.15579551 -0.25336168
# 13 3 -0.6212406 -1.47075238 0.69696338
# 14 3 -2.2146999 -0.47815006 0.55666320
# 15 3 1.1249309 0.41794156 -0.68875569
次に、サンプリング:
do.call(rbind,
lapply(split(mydf, mydf$ID),
function(x) x[sample(nrow(x), 3), ]))
# ID X1 X2 X3
# 1.2 1 0.1836433 -0.01619026 -0.1027877
# 1.1 1 -0.6264538 -0.04493361 1.3586796
# 1.5 1 0.3295078 0.59390132 -1.3770596
# 2.10 2 -0.3053884 0.61982575 0.7631757
# 2.9 2 0.5757814 -1.98935170 1.1000254
# 2.8 2 0.7383247 0.07456498 -0.0593134
# 3.13 3 -0.6212406 -1.47075238 0.6969634
# 3.12 3 0.3898432 -0.15579551 -0.2533617
# 3.15 3 1.1249309 0.41794156 -0.6887557
strata
パッケージにはsampling
もあり、各グループから異なるサイズをサンプリングする場合に便利です。
# install.packages("sampling")
library(sampling)
set.seed(1)
x <- strata(mydf, "ID", size = c(2, 3, 2), method = "srswor")
getdata(mydf, x)
# X1 X2 X3 ID ID_unit Prob Stratum
# 2 0.1836433 -0.01619026 -0.1027877 1 2 0.4 1
# 5 0.3295078 0.59390132 -1.3770596 1 5 0.4 1
# 6 -0.8204684 0.91897737 -0.4149946 2 6 0.6 2
# 8 0.7383247 0.07456498 -0.0593134 2 8 0.6 2
# 9 0.5757814 -1.98935170 1.1000254 2 9 0.6 2
# 14 -2.2146999 -0.47815006 0.5566632 3 14 0.4 3
# 15 1.1249309 0.41794156 -0.6887557 3 15 0.4 3
IDのオンが500未満の場合のアプローチ。ここでは、mtcarsセットを使用しました。
n <- 8
df <- mtcars
df$ID <- df$cyl
FUN <- function(x, n) {
if (length(x) <= n) return(x)
x[x %in% sample(x, n)]
}
df[unlist(lapply(split(1:nrow(df), df$ID), FUN, n = 8)), ]
大きなデータセットがある場合、_data.table
_ソリューションは次のようになります。
_library(data.table)
# Generate 26 mil rows random data
set.seed(2019)
dt <- data.table(c1 = sample(length(LETTERS)*10^6),
c2 = sample(LETTERS, replace = TRUE))
# For each letter, sample 500 rows
dt_sample <- dt[, .SD[sample(x = .N, size = 500)], by = c2]
# We indeed sampled 500 rows for each letter
dt_sample[, .N, by = c2][order(c2)]
#> c2 N
#> 1: A 500
#> 2: D 500
#> 3: G 500
#> 4: I 500
#> 5: M 500
#> 6: N 500
#> 7: O 500
#> 8: P 500
#> 9: Q 500
#> 10: R 500
#> 11: S 500
#> 12: T 500
#> 13: U 500
#> 14: V 500
#> 15: W 500
#> 16: Y 500
#> 17: Z 500
_
2019-04-23に reprexパッケージ (v0.2.1)によって作成されました
一部のグループが目的のサンプルサイズよりも(行数として)小さいという意味でデータが不均衡な場合は、サンプルサイズがmin(500, .N)
のように防御トリックを設定する必要があります-参照 data.tableの各グループ内のランダムな行のサンプル 。以下のようなので:
dt[, .SD[sample(x = .N, size = min(500, .N))], by = c2]
mydata1 is your original data(not tested)
mydata2<- split(mydata1,mydata1$ID)
names(mydata2)<-paste0("mydata2",1:length(levels(ID)))
mysample<-Map(function(x) x[sample((1:nrow(x)),size=500,replace=FALSE),], mydata2)
library(plyr)# for rbinding the mysample
ldply(mysample)
これは非常にエレガントなソリューションではありませんが、機能する可能性があります。
library(data.table)
df <- data.table(df)
f <- list()
for(i in unique(df1$ID)){
f[[i]] <- df1[id == i][sample(.N,(500))]
}
dfnew <- rbindlist(f)
library(data.table) #1
df <- data.table(df) #2
df[,group_num := sample(2,.N,replace = TRUE,prob = c(500,.N-500)/.N),by = "ID"] #3
df_sample = df[group_num == 1,] #4
または、#3と#4の行を次のように変更できます。
df[,random_num := sample(.N,.N),by="ID"]
df_sample = df[random_num <=500,]