长与宽,整齐与高效

时间:2016-12-04 23:44:20

标签: r tidyverse

在长格式和宽格式之间切换时,我在当前的数据分析工作流程中找到了一些不理想的步骤。考虑下面显示的三条曲线,使用常见的x

enter image description here

我的数据格式很长,可用于绘图和各种各样的pipy事物,但对于分析的某些部分,处理宽(类似矩阵)格式似乎更容易。例如,在这个虚拟示例中,我可能希望通过减去0到0.25之间每条迹线的平均值(阴影灰色区域),将所有迹线的基线设置为0。

我找不到一种简单的方法来做长格式的这种事情。

我目前的策略是切换回宽格式,但i)我永远不会记住dcast / reshape的正确语法,ii)在两者之间来回切换是非常低效的。

dwide <- reshape2::dcast(dlong, x~..., value.var="y")
dwide[,-1] <- sweep(dwide[,-1], 2, colMeans(dwide[dwide$x < 0.25, -1]), FUN="-")
dlong2 <- melt(dwide, id="x")

enter image description here

我错过了一些可以提供帮助的工具吗?我愿意接受data.table建议。

完全可重复的例子:

library(ggplot2)
library(plyr)
library(reshape2)

## dummy data as noisy lorentzian-shaped peaks with random offset

set.seed(1234)
fake_data <- function(a, x = seq(0, 1, length=100)){ 
  data.frame(x = x, 
             y = jitter(1e-3 / ((x - a)^2 + 1e-3) + runif(1,0,1), 
                   amount = 0.1))
}

## apply function to all combinations of parameters (one here)
dlong <- plyr::mdply(data.frame(a = c(0.4,0.5,0.6)), fake_data)

ggplot(dlong, aes(x, y, colour=factor(a))) + geom_line() +
  annotate("rect", xmin=-Inf, xmax=0.25, ymin=-Inf, ymax=Inf, fill="grey", alpha = 0.3) +
  theme_minimal()

dwide <- reshape2::dcast(dlong, x~..., value.var="y")
str(dwide)

dwide[,-1] <- sweep(dwide[,-1], 2, colMeans(dwide[dwide$x < 0.25, -1]), FUN="-")
dlong2 <- melt(dwide, id="x")

ggplot(dlong2, aes(x, value, colour=variable)) + geom_line()  +
  theme_minimal()

1 个答案:

答案 0 :(得分:6)

也许你的最小例子太过微不足道,无法捕捉到你想要长到很长的所有情况。但至少对于你的例子,我通常会使用data.table进行这种操作:

setDT(dlong)[, y2 := y - mean(y[x < 0.25]), by=a]

ggplot(dlong, aes(x, y2, colour=factor(a))) + 
  geom_line() +
  theme_minimal()

enter image description here

打破这个局面:

  • by = a对数据进行分组,以便将[。data.table的第二个参数中的操作应用于与

    的每个值对应的dlong的子集
  • 因此,
  • y2 := y - mean(y[x < 0.25])分别为a的每个值计算

  • :=是data.table中的一个特殊运算符,它通过引用提供赋值,而不是通过复制赋值(非常有效)

  • [的第一个参数.atat.table在这里留空,因为我们希望对原始dlong数据的所有行进行操作。

使用dplyr

可以完成同样的事情
dlong %>% 
  group_by(a) %>% 
  mutate(y2 = y - mean(y[x < 0.25]))