我注意到,根据数据集具有的变量/特征的数量,首先使用pivot_wider(更少的变量)或pivot_longer(更多的变量)可能会更快。我想知道这主要是因为什么?我的猜测是分组操作(更长的格式)和绑定(更宽的格式)之间的权衡,但我想知道是否有人有更多的见解。下面的示例将不同组的幂提高到随机值:
代码(很多功能):
# 5000 features , 100 observations
df_long = data.frame(grp=rep(1:100, each=5e3),
feat=paste0("V",rep(1:5e3, times=100)),
val=rnorm(5e5))
df_wide = df_long %>% group_by(feat) %>%
pivot_wider(names_from = feat,
values_from = val) %>% ungroup()
system.time({
df_long %>%
group_by(grp) %>% mutate(val=grp^val)
})
system.time({
df_wide %>% mutate(across(paste0("V",1:5000), ~grp^.))
})
结果:
user system elapsed
0.028 0.000 0.028
user system elapsed
0.158 0.000 0.158
代码(较少功能):
# 100 features , 5000 observations
df_long = data.frame(grp=rep(1:5e3, each=100),
feat=paste0("V",rep(1:100, times=5e3)),
val=rnorm(5e5))
df_wide = df_long %>% group_by(feat) %>%
pivot_wider(names_from = feat,
values_from = val) %>% ungroup()
system.time({
df_long %>%
group_by(grp) %>% mutate(val=grp^val)
})
system.time({
df_wide %>% mutate(across(paste0("V",1:100), ~grp^.))
})
结果:
user system elapsed
0.051 0.000 0.050
user system elapsed
0.025 0.000 0.025
比较不同尺寸的长格式,然后比较不同尺寸的宽格式可能会更容易。
对于长格式,具有 5000 个观测值的格式需要更长的时间,因为
group_by()
中有更多组。更多的组意味着他们需要更多次地进行相同的计算。这就是为什么 rowwise()
很强大,但通常是速度性能的瓶颈。 here提到了 dplyr 中的分组机制:
dplyr 是 Split-Apply-Combine 计算范式的有效实现。数据被分成组,然后将这些数据块传递给执行计算的函数,最后重新组合以生成聚合的数据帧。这种作案手法在 dplyr 的分组机制中很明显。当 data.frame 通过 group_by 传递时,会附加一个“groups”属性。
该对象是一个 data.frame,给出唯一的组,并且在第三(最后)列向量中包含属于该组的行的索引。像 summarise 这样的命令使用此信息将 data.frame 分成组,然后按顺序传递给所使用的函数,然后重新组合。这些步骤也是用 C++ 完成的,这使得 dplyr 非常高效。
对于宽格式,主要区别在于列数。速度差异来自于 R 中的数据帧是基于列的,这意味着它是按列存储的。因此,矢量化在这种情况下不起作用。
要点是列和组更少,速度更快。