我有一个非常大的数据框(150.000.000行),格式如下:
df = data.frame(pnr = rep(500+2*(1:15),each=3), x = runif(3*15))
pnr是person id,x是一些数据。我想抽样10%的人。在dplyr中有一种快速的方法吗?
以下是一个解决方案,但由于merge-statement
,它很慢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,]
答案 0 :(得分:4)
在基数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
个答案。它可能会快15米行。
答案 1 :(得分:4)
我实际上建议在“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
答案 2 :(得分:1)
如果您不一定需要完整的随机样本,那么您可以
filter(df, pnr %% 10 ==0).
哪个会占用每10个人(通过更改为==1
可以获得10个不同的样本,...)。您可以通过随机重新分配ID来实现此随机 - 使用sample(15)[(df$pnr-500)/2]
为您的玩具示例执行此操作非常简单 - 将pnr
的映射转换为适合sample
的集合可能是现实案例不太容易。