【发布时间】:2017-09-01 19:36:31
【问题描述】:
考虑以下DataFrame:
DF = structure(list(c_number = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L,
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L,
3L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L,
5L, 5L, 5L, 5L, 5L), date = c("2001-01-06", "2001-01-07", "2001-01-08",
"2001-01-09", "2001-01-10", "2001-01-11", "2001-01-12", "2001-01-13",
"2001-01-14", "2001-01-15", "2001-01-16", "2001-01-17", "2001-01-18",
"2001-01-19", "2001-01-20", "2001-01-21", "2001-01-22", "2001-01-23",
"2001-01-24", "2001-01-25", "2001-01-26", "2001-01-11", "2001-01-12",
"2001-01-13", "2001-01-14", "2001-01-15", "2001-01-16", "2001-01-17",
"2001-01-18", "2001-01-19", "2001-01-20", "2001-01-21", "2001-01-22",
"2001-01-23", "2001-01-24", "2001-01-25", "2001-01-26", "2001-01-27",
"2001-01-28", "2001-01-12", "2001-01-13", "2001-01-14", "2001-01-15",
"2001-01-16", "2001-01-17", "2001-01-18", "2001-01-19", "2001-01-20",
"2001-01-21", "2001-01-22", "2001-01-23", "2001-01-24", "2001-01-25",
"2001-01-26", "2001-01-27", "2001-01-28", "2001-01-29", "2001-01-30",
"2001-01-21", "2001-01-22", "2001-01-23", "2001-01-24", "2001-01-25",
"2001-01-26", "2001-01-27", "2001-01-28", "2001-01-29", "2001-01-30",
"2001-01-31", "2001-01-24", "2001-01-25", "2001-01-26", "2001-01-27",
"2001-01-28", "2001-01-29", "2001-01-30", "2001-01-31", "2001-02-01"
), value = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), .Names = c("c_number",
"date", "value"), row.names = c(NA, -78L), class = "data.frame")
我有 5 个客户在连续日期的销售数据;对于客户 1,我有连续 21 个日期的销售数据……对于客户 5,我有连续 9 个日期的销售数据……:
> table(DF[, 1])
1 2 3 4 5
21 18 19 11 9
对于每个客户,我想对连续 15 天(如果该客户至少有 15 个连续日期)或该客户的所有日期(如果该客户没有 15 个连续日期)的子 DF 进行抽样.
关键部分是,在情况 1(如果我为该客户至少有 15 个连续日期)这 15 个连续天应该有一个随机的开始日期(例如,并不总是客户的第一个或最后 15 个日期)避免在分析中引入偏差。
在普通的 R 中我会这样做:
library(dplyr)
slow_function <- function(i, DF, length_out = 15){
sub_DF = DF[DF$c_number == i, ]
if(nrow(sub_DF) <= length_out){
out_DF = sub_DF
} else {
random_start = sample.int(nrow(sub_DF) - length_out, 1)
out_DF = sub_DF[random_start:(random_start + length_out - 1), ]
}
}
a_out = lapply(1:nrow(a_1), slow_function, DF = DF, length_out = 15)
a_out = dplyr::bind_rows(a_out)
table(a_out[, 1])
1 2 3 4 5
15 15 15 11 9
但是我的数据要大得多,上面的操作慢得让人难以忍受。在 data.table/dplyr 中是否有快速获得相同结果的方法?
编辑:生成数据的代码。
num_customer = 10
m = 2 * num_customer
a_0 = seq(as.Date("2001-01-01"), as.Date("2001-12-31"), by = "day")
a_1 = matrix(sort(sample(as.character(a_0), m)), nc = 2)
a_2 = list()
for(i in 1:nrow(a_1)){
a_3 = seq(as.Date(a_1[i, 1]), as.Date(a_1[i, 2]), by = "day")
a_4 = data.frame(i, as.character(a_3), round(runif(length(a_3), 1)))
colnames(a_4) = c("c_number", "date", "value")
a_2[[i]] = a_4
}
DF = dplyr::bind_rows(a_2)
dim(DF)
table(DF[, 1])
dput(DF)
编辑2:
对于 10 万客户 DF,Christoph Wolk 的解决方案是最快的。 接下来是 G. Grothendieck 的(大约 4 倍以上的时间),接下来是 Nathan Werth 的(比 G. Grothendieck 的慢 2 倍)。 其他解决方案明显较慢。尽管如此,所有提案都比我试探的“slow_function”更快,所以感谢大家!
【问题讨论】:
-
问题有点不清楚。对于每个员工,您想选择一个随机的起始日期并在该起始点之后最多连续 15 天进行抽样?或者,如果随机选择会导致员工的数据点少于 15 个,那么只取最后 15 个?
-
@jdobres:感谢您的提问。实际上第二种解释('如果随机选择会导致员工的数据点少于 15 个,只取最后 15 个?')是我想要的。
标签: r dplyr data.table