我比较熟悉data.table,而不是那么熟悉dplyr.我已经阅读了一些出现在SO上的dplyr小插曲和例子,到目前为止我的结论是:
data.table并且dplyr在速度上具有可比性,除非有许多(即> 10-100K)组,并且在某些其他情况下(参见下面的基准)dplyr 有更多可访问的语法dplyr 摘要(或将)潜在的DB交互在我看来2.没有多大的重量,因为我对它很熟悉data.table,虽然我明白对于那些对这两者都不熟悉的用户来说这将是一个很重要的因素.我想避免争论哪个更直观,因为这与我从已经熟悉的人的角度提出的具体问题无关data.table.我还想避免讨论"更直观"如何导致更快的分析(当然是真的,但同样,不是我最感兴趣的).
我想知道的是:
最近的一个问题让我更多地思考这个问题,因为直到那时我才认为dplyr会提供超出我已经做过的东西data.table.这是dplyr解决方案(Q末尾的数据):
dat %.%
group_by(name, job) %.%
filter(job != "Boss" | year == min(year)) %.%
mutate(cumu_job2 = cumsum(job2))
Run Code Online (Sandbox Code Playgroud)
这比我的黑客尝试data.table解决方案要好得多.也就是说,好的data.table解决方案也相当不错(感谢Jean-Robert,Arun,并注意到这里我赞成对最严格的最佳解决方案的单一陈述):
setDT(dat)[,
.SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)],
by=list(id, job)
]
Run Code Online (Sandbox Code Playgroud)
后者的语法可能看起来非常深奥,但如果你习惯了data.table(即不使用一些更深奥的技巧),它实际上非常简单.
理想情况下,我希望看到的是一些很好的例子,dplyr …
如何使用data.table执行以下(直接使用sqldf)并得到完全相同的结果:
library(data.table)
whatWasMeasured <- data.table(start=as.POSIXct(seq(1, 1000, 100),
origin="1970-01-01 00:00:00"),
end=as.POSIXct(seq(10, 1000, 100), origin="1970-01-01 00:00:00"),
x=1:10,
y=letters[1:10])
measurments <- data.table(time=as.POSIXct(seq(1, 2000, 1),
origin="1970-01-01 00:00:00"),
temp=runif(2000, 10, 100))
## Alternative short names for data.tables
dt1 <- whatWasMeasured
dt2 <- measurments
## Straightforward with sqldf
library(sqldf)
sqldf("select * from measurments m, whatWasMeasured wwm
where m.time between wwm.start and wwm.end")
Run Code Online (Sandbox Code Playgroud) 我知道data.table与dplyr 的比较是 SO 上的常客。(完全披露:我喜欢并使用这两个包。)
但是,在尝试为我正在教授的课程提供一些比较时,我遇到了令人惊讶的 wrt 内存使用情况。我的期望是dplyr在需要(隐式)过滤或数据切片的操作中表现特别差。但这不是我要发现的。相比:
首先dplyr。
library(bench)
library(dplyr, warn.conflicts = FALSE)
library(data.table, warn.conflicts = FALSE)
set.seed(123)
DF = tibble(x = rep(1:10, times = 1e5),
y = sample(LETTERS[1:10], 10e5, replace = TRUE),
z = rnorm(1e6))
DF %>% filter(x > 7) %>% group_by(y) %>% summarise(mean(z))
#> # A tibble: 10 x 2
#> y `mean(z)`
#> * <chr> <dbl>
#> 1 A -0.00336
#> 2 B -0.00702
#> 3 C …Run Code Online (Sandbox Code Playgroud) 我最近在一些旧代码中注意到,在对a data.table进行子集化并重复执行函数时(包括计算相关矩阵),我一直包括额外的方括号.所以,
# Slow way
rcorr(DT[subgroup][, !'Group', with=F])
# Faster way
rcorr(DT[subgroup, !'Group', with=F])
Run Code Online (Sandbox Code Playgroud)
(差异在于之后subgroup).出于好奇,为什么会出现这种情况?使用额外的括号,是否data.table必须执行一些额外的计算?
我有一个数据集customerId,transactionDate,productId,purchaseQty加载到data.table中.对于每一行,我想计算前45天的总和,以及购买数量的平均值
productId customerID transactionDate purchaseQty
1: 870826 1186951 2016-03-28 162000
2: 870826 1244216 2016-03-31 5000
3: 870826 1244216 2016-04-08 6500
4: 870826 1308671 2016-03-28 221367
5: 870826 1308671 2016-03-29 83633
6: 870826 1308671 2016-11-29 60500
Run Code Online (Sandbox Code Playgroud)
我正在寻找这样的输出:
productId customerID transactionDate purchaseQty sumWindowPurchases
1: 870826 1186951 2016-03-28 162000 162000
2: 870826 1244216 2016-03-31 5000 5000
3: 870826 1244216 2016-04-08 6500 11500
4: 870826 1308671 2016-03-28 221367 221367
5: 870826 1308671 2016-03-29 83633 305000
6: 870826 1308671 2016-11-29 60500 60500
Run Code Online (Sandbox Code Playgroud)
因此,sumWindowPurchases包含当前交易日期45天窗口内客户/产品的purchaseQty总和.一旦我有了这个工作,抛出我需要的平均值和其他计算应该是微不足道的
我回到我的SQL根源并想到了一个自我加入:
select …Run Code Online (Sandbox Code Playgroud) 我有两个数据框ev1和ev2,描述了在许多测试中收集的两种类型事件的时间戳.因此,每个数据帧都有"test_id"和"timestamp"列.我需要找到的是在同一测试中每个ev2的最小距离ev1.
我有一个工作代码合并两个数据集,计算距离,然后使用dplyr过滤最小距离:
ev1 = data.frame(test_id = c(0, 0, 0, 1, 1, 1), time=c(1, 2, 3, 2, 3, 4))
ev2 = data.frame(test_id = c(0, 0, 0, 1, 1, 1), time=c(6, 1, 8, 4, 5, 11))
data <- merge(ev2, ev1, by=c("test_id"), suffixes=c(".ev2", ".ev1"))
data$distance <- data$time.ev2 - data$time.ev1
min_data <- data %>%
group_by(test_id, time.ev2) %>%
filter(abs(distance) == min(abs(distance)))
Run Code Online (Sandbox Code Playgroud)
虽然这很有效,但合并部分非常慢并且感觉效率低下 - 我正在为同一个test_id生成一个包含ev2-> ev1的所有组合的巨大表格,只是将其过滤为一个.在合并期间,似乎应该有一种"即时过滤"的方法.在那儿?
更新:当使用akrun概述的data.table方法时,以下两个"group by"列的情况会失败:
ev1 = data.frame(test_id = c(0, 0, 0, 1, 1, 1), time=c(1, 2, 3, 2, 3, 4), group_id=c(0, …Run Code Online (Sandbox Code Playgroud) 这可能非常复杂,我怀疑需要先进的知识.我现在有两种不同类型的data.frames需要组合:
数据:
数据帧A:
按患者ID列出所有输血日期.每次输血都由一个单独的行代表,患者可以进行多次输血.不同的患者可以在同一天进行输血.
Patient ID Transfusion.Date
1 01/01/2000
1 01/30/2000
2 04/01/2003
3 04/01/2003
Run Code Online (Sandbox Code Playgroud)
B类数据帧包含其他日期的测试结果,也包括患者ID:
Patient ID Test.Date Test.Value
1 11/30/1999 negative
1 01/15/2000 700 copies/uL
1 01/27/2000 900 copies/uL
2 03/30/2003 negative
Run Code Online (Sandbox Code Playgroud)
我想要的是具有相同行数的Dataframe A(每次输入为1),并将最新的Test.Value作为单独的列.每个输血日期应该具有与输血最密切(之前)进行的测试的测试结果.
期望的输出:
- >
Patient ID Transfusion.Date Pre.Transfusion.Test
1 01/01/2000 negative
1 01/30/2000 900 copies/ul
2 04/01/2003 negative
3 04/01/2003 NA
Run Code Online (Sandbox Code Playgroud)
我认为一般策略是按患者ID对data.frames进行子集化.然后获取患者1的所有输血日期,检查哪个结果最接近每个元素的所有可用test_dates,然后返回最接近的值.
如何解释R来做到这一点?
编辑1:这是这些示例的R代码
df_A <- data.frame(MRN = c(1,1,2,3),
Transfusion.Date = as.Date(c('01/01/2000', '01/30/2000',
'04/01/2003','04/01/2003'),'%m/%d/%Y'))
df_B <- data.frame(MRN = c(1,1,1,2),
Test.Date = as.Date(c('11/30/1999', '01/15/2000', '01/27/2000', …Run Code Online (Sandbox Code Playgroud) 我需要一些dplyr的帮助.我有两个数据框 - 一个是巨大的,有几个时间序列A,B,...在那里(LargeDF),另一个是(Categories)有时间间隔(左边界和右边界).
我想添加另一列LargeDF,标记为leftBoundary包含适当的边界值,如下所示:
LargeDF
ts timestamp signal # left_boundary
1 A 0.3209338 10.43279 # 0
2 A 1.4791524 10.34295 # 1
3 A 2.6007494 10.71601 # 2
Run Code Online (Sandbox Code Playgroud)
和
Categories
ts left right
1 A 0 1
2 A 1 2
3 A 2 3
Run Code Online (Sandbox Code Playgroud)
我想出的代码是
LargeDF %>%
group_by(ts) %>%
do(myFUN(., Categories))
# calls this ...
myFUN <- function(Large, Categ) {
CategTS <- Categ %>%
filter(ts == Large[1, "ts"][[1]])
Large …Run Code Online (Sandbox Code Playgroud)