[英]Using dplyr to make sample from data frame
我有一個非常大的數據框(1500萬行),其格式如下:
df = data.frame(pnr = rep(500+2*(1:15),each=3), x = runif(3*15))
pnr是個人ID,x是一些數據。 我想抽樣10%的人。 在dplyr中有快速的方法嗎?
以下是解決方案,但是由於合並語句,它很慢
prns = as.data.frame(unique(df$prn))
names(prns)[1] = "prn"
prns$s = rbinom(nrow(prns),1,0.1)
df = merge(df,prns)
df2 = df[df$s==1,]
在基數R中,對10%的行進行采樣,向上舍入到下一行
> df[sample(nrow(df), ceiling(0.1*nrow(df)), FALSE), ]
## pnr x
## 16 512 0.9781232
## 21 514 0.5279925
## 33 522 0.8332834
## 14 510 0.7989481
## 4 504 0.7825318
或四舍五入到下一行
> df[sample(nrow(df), floor(0.1*nrow(df)), FALSE), ]
## pnr x
## 43 530 0.449985180
## 35 524 0.996350657
## 2 502 0.499871966
## 25 518 0.005199058
或取樣pnr
色譜柱的10%,四舍五入
> sample(df$pnr, ceiling(0.1*length(df$pnr)), FALSE)
## [1] 530 516 526 518 514
加:
如果您想對10%的人(唯一的pnr
ID)進行抽樣,並返回這些人及其各自的數據,我認為您想要
> S <- sample(unique(df$pnr), ceiling(0.1*length(unique(df$pnr))), FALSE)
> df[df$pnr %in% S, ]
## pnr x
## 1 502 0.7630667
## 2 502 0.4998720
## 3 502 0.4839460
## 22 516 0.8248153
## 23 516 0.5795991
## 24 516 0.1572472
PS:我會等一個dplyr
答案。 1500萬行上的速度可能會更快。
我實際上建議在“ dplyr”上使用“ data.table”包。 這是一個包含大量示例數據的示例(比您自己的1500萬行小很多)。
我還將展示一些正確和錯誤的方法:-)
這是示例數據。
library(data.table)
library(dplyr)
library(microbenchmark)
set.seed(1)
mydf <- DT <- data.frame(person = sample(10000, 1e7, TRUE),
value = runif(1e7))
我們還將創建一個“ data.table”並將鍵設置為“ person”。 創建“ data.table”不需要花費大量時間,但是可以設置鍵。
system.time(setDT(DT))
# user system elapsed
# 0.001 0.000 0.001
## Setting the key takes some time, but is worth it
system.time(setkey(DT, person))
# user system elapsed
# 0.620 0.025 0.646
我無法想到一種比以下方法更有效的選擇“人”值的方法,因此我將其從基准中刪除了,它們對於所有方法都是通用的。
## Common to all tests...
A <- unique(mydf$person)
B <- sample(A, ceiling(.1 * length(A)), FALSE)
為了方便起見,將不同的測試表示為功能...
## Base R #1
fun1a <- function() {
mydf[mydf$person %in% B, ]
}
## Base R #2--sometimes using `which` makes things quicker
fun1b <- function() {
mydf[which(mydf$person %in% B), ]
}
## `filter` from "dplyr"
fun2 <- function() {
filter(mydf, person %in% B)
}
## The "wrong" way to do this with "data.table"
fun3a <- function() {
DT[which(person %in% B)]
}
## The "right" (I think) way to do this with "data.table"
fun3b <- function() {
DT[J(B)]
}
現在,我們可以進行基准測試:
## The benchmarking
microbenchmark(fun1a(), fun1b(), fun2(), fun3a(), fun3b(), times = 20)
# Unit: milliseconds
# expr min lq median uq max neval
# fun1a() 382.37534 394.27968 396.76076 406.92431 494.32220 20
# fun1b() 401.91530 413.04710 416.38470 425.90150 503.83169 20
# fun2() 381.78909 394.16716 395.49341 399.01202 417.79044 20
# fun3a() 387.35363 397.02220 399.18113 406.23515 413.56128 20
# fun3b() 28.77801 28.91648 29.01535 29.37596 42.34043 20
看看正確使用“ data.table”獲得的性能! 所有其他方法都非常快。
summary
顯示的結果是相同的。 (由於已排序,因此“ data.table”解決方案的行順序將有所不同。)
summary(fun1a())
# person value
# Min. : 16 Min. :0.000002
# 1st Qu.:2424 1st Qu.:0.250988
# Median :5075 Median :0.500259
# Mean :4958 Mean :0.500349
# 3rd Qu.:7434 3rd Qu.:0.749601
# Max. :9973 Max. :1.000000
summary(fun2())
# person value
# Min. : 16 Min. :0.000002
# 1st Qu.:2424 1st Qu.:0.250988
# Median :5075 Median :0.500259
# Mean :4958 Mean :0.500349
# 3rd Qu.:7434 3rd Qu.:0.749601
# Max. :9973 Max. :1.000000
summary(fun3b())
# person value
# Min. : 16 Min. :0.000002
# 1st Qu.:2424 1st Qu.:0.250988
# Median :5075 Median :0.500259
# Mean :4958 Mean :0.500349
# 3rd Qu.:7434 3rd Qu.:0.749601
# Max. :9973 Max. :1.000000
如果您不一定需要完全隨機的樣本,則可以
filter(df, pnr %% 10 ==0).
每10個人要花費一次(更改為==1
,您可以獲得10個不同的樣本,...)。 您可以通過隨機地重新分配ID來使其隨機-對於玩具示例,使用sample(15)[(df$pnr-500)/2]
來做到這一點相當簡單-將pnr
的映射pnr
映射到適合sample
的集合上在現實世界中可能不太容易。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.