r - 逐行加速data.frame的子集,避免循环(dplyr,R)
问题描述
我是新手dplyr
,我正在努力解决我认为是一个简单的功能。我有一个类似于以下的数据集:
require(dplyr)
dat <- data.frame(t = rep(seq(1, 5, 1),4), id = rep(c(rep("A",5), rep("B",5), rep("C",5), rep("D",5)), 1),
x = 1:20, y = 51:70, h = c(rep(1,10), rep(0,10) ) )
dat <- arrange(dat, t)
dat <- data.frame(dat, group = c("B", "A", "A", "A", "A", "B", "C", "D", "A", "B", "D", "C", "A", "D", "C", "A", "A", "C", "C", "B") )
dat
我想将一个新列附加到dat
包含以下操作的数据集:
- 对于每一行,例如带有 的第 3 行
id == C
,取剩余的行,使其 in 的值group
与起始的 不同id
,在这种情况下为 C - 按时间分组观察
t
id
如果(在这种情况下id
,第 3 行中的 C)1
在 col 中具有值,则执行以下操作h
:将所有值(来自基于 的组t
)相加x
并除以和中的值的标准差y
(x
来自基于的组t
)。Ifid
的值为0
in colh
place a0
。如果没有观察到,代码应该放置一个零。
例如,对于id
A
in row 1
,代码应该产生 a 0
,因为在 time 的所有观察结果t == 1
都有group == A
。对于id
B
行2
中的代码应该产生(11 + 16) / sd(c(11, 16, 61, 66))
.
如何以dplyr
不包括的方式或任何其他方式执行此操作looping
?谢谢你。
数据看起来像
dat
# t id x y h group
# 1 1 A 1 51 1 B
# 2 1 B 6 56 1 A
# 3 1 C 11 61 0 A
# 4 1 D 16 66 0 A
# 5 2 A 2 52 1 A
# 6 2 B 7 57 1 B
# 7 2 C 12 62 0 C
# 8 2 D 17 67 0 D
# 9 3 A 3 53 1 A
# 10 3 B 8 58 1 B
# 11 3 C 13 63 0 D
# 12 3 D 18 68 0 C
# 13 4 A 4 54 1 A
# 14 4 B 9 59 1 D
# 15 4 C 14 64 0 C
# 16 4 D 19 69 0 A
# 17 5 A 5 55 1 A
# 18 5 B 10 60 1 C
# 19 5 C 15 65 0 C
# 20 5 D 20 70 0 B
我尝试了以下方法,但没有产生正确的结果。
dat %>%
group_by(t) %>%
mutate(new = ifelse(id != group, h * (sum(x) /map_dbl(row_number(), ~
sd(c(x[-.x], y[-.x]) ))) , 0) )
解决方案
这应该只是说明data.tables
vs的速度表现dplyr
。我只是把变异的整个 ifelse 打包到一个 data.table 操作中,并用 ( by = t
) 分组。所以结果不会是期望的结果,但是对于 dplyr 和 data.tables 的结果至少是相同的。
library(data.table)
library(dplyr)
datDT <- data.table(dat)
DTF <- function(){
d <- datDT[ , new := ifelse( id != group, h * (sum(x) /
map_dbl(row_number(x), ~
sd(c(x[-.x], y[-.x])))) , 0) , by = t]
d
}
DPF <- function(){
d <- dat %>%
group_by(t) %>%
mutate(new = ifelse(id != group, h * (sum(x) /map_dbl(row_number(x), ~
sd(c(x[-.x], y[-.x]) ))) , 0) )
d
}
dtres = DTF()
dplres = DPF()
all.equal(dtres, data.table(dplres))
library(microbenchmark)
mc <- microbenchmark(times = 100,
DT = DTF(),
DPLYR = DPF()
)
mc
Unit: milliseconds expr min lq mean median uq max neval cld DT 7.428605 7.821919 8.324179 8.056762 8.429851 15.39028 100 a DPLYR 11.154076 11.439025 11.895716 11.720050 12.139022 16.40934 100 b
收益不是很大,但仍然很明显,我相信仍然可以通过设置键、摆脱 ifelse 等来完成一些优化,但我把它留给了真正的 data.table 专家:)。
因此,如果您对两者都不熟悉,也许可以深入研究 data.tables,因为您也可以将 dplyr-verbs 与它们一起使用(如下所示)并且比使用tbl
结构稍微快一些。
dtres %>%
group_by(t) %>%
summarise(mN = mean(new))
推荐阅读
- python - 矩阵元素乘法与移位列
- php - 在 codeigniter 上传 gojson 文件
- android-studio - 如何在 Android Studio 中使用我的 chromebook?
- functional-programming - 评估值相等时发生类型不匹配
- python - 客户端无法从 INTERNET 上的不同计算机连接到服务器
- c# - 我应该添加什么路由来映射到 API 控制器?
- spring-boot - 基于用户 ID 的 Spring Rest 虚拟 API 实现
- cpanel - 通过 cPanel 安装 10 月 CMS 时出错
- r - 写一个函数来计算所有员工的客户满意度?
- laravel - Laravel Nova:具有 3 个关系的数据透视表