【问题标题】:R data.table calculate function on subset vector for each member of groupR data.table 为组的每个成员计算子集向量的函数
【发布时间】:2015-09-12 21:19:16
【问题描述】:

我有一个非常相似的数据表

set.seed(1)

dt<-data.table(med=sample(letters,50,T),
    diag=sample(LETTERS[1:7],50,T),
    val=sample(1:100,50,F))

我想计算任何val 大于val 对于相同diag 的概率,并将其分配给表格的新列,例如prob(我知道这个事实概率不一定是正常的。我可以接受这种情况)。

我可以用 for 循环来做到这一点:

for (i in 1:50){
    dg<-dt[i,diag]
    vl<-dt[i,val]
    dt$prob[i]<-pnorm(vl,
                      mean(dt[diag==dg,val]),
                      sd(dt[diag==dg,val]),
                      lower.tail = F)
}

但我的数据相当大(dt 大约是 800k 行,diag 上有一些 2k 级别),所以我想矢量化而不是循环。

我试过了

dt[,
   .(lapply(.SD,function(x) 
                pnorm(x[1],
                mean(x),
                sd(x),
                lower.tail = F))),
   by=diag,
   .SDcols="val"]

当然,按diag 分组只产生一个概率,因此没有多大用处。 我也试过了

dt[,
   .(lapply(.SD,function(x) 
                pnorm(x[1],
                mean(x),
                sd(x),
                lower.tail = F))),
   by=.EACHI,
   .SDcols="val"]

但它会产生错误:

Error in `[.data.table`(dt, , .(lapply(.SD, function(x) pnorm(x[1], mean(x),  : 
  logicial error. i is not data.table, but mult='all' and 'by'=.EACHI

通过矢量化产生所需结果的代码是什么?

由于我正在习惯data.tables,我更喜欢使用该软件包的解决方案,但是我绝对愿意接受任何其他解决方案来源(plyr、dplyr 等)。

谢谢,

【问题讨论】:

  • dt[,prob2:= 1 - pnorm(val,mean(val),sd(val),lower.tail=FALSE),by=diag] 或类似的东西似乎与您的结果相匹配。不知道为什么我需要做1 - pnorm
  • 结果的长度不会是 7 吗?我想要一个长度为 50 的结果,prob 计算 for each 行,只是它是通过考虑 share 相同@的所有值的分布来计算的987654335@
  • 不,by= 默认为每个组中的每一行进行计算。这就是重点。
  • 你的例子有几个问题。 50 比您需要的多,如果显示在答案中以显示结果,则会占用大量空间。而且您的示例是随机生成的,但您没有设置种子,因此无法重现。
  • dt[,prob2:= pnorm(val,mean(val),sd(val),lower.tail=FALSE),by=diag] 现在给出了相同的结果 - 仅需要 1 - 是因为您使用了 lower.tail=F 而不是 lower.tail=FALSE 并且我有一个名为 F 的变量浮动。充分输入FALSETRUE 的好理由。

标签: r data.table vectorization subset


【解决方案1】:

data.table:

dt[, prob2 := pnorm(val, mean(val), sd(val), lower.tail=FALSE), by=diag]

似乎符合你的要求:

head(dt)
#   med diag val       prob      prob2
#1:   p    E  91 0.04713131 0.04713131
#2:   f    E   3 0.92991675 0.92991675
#3:   o    B  26 0.83792988 0.83792988
#4:   t    C  38 0.70877125 0.70877125
#5:   g    E  71 0.16909178 0.16909178
#6:   i    E  25 0.75428819 0.75428819

【讨论】:

  • 我什至没有考虑尝试这个,这就是我选择.SD 的原因。我不完全明白,在对pnorm 的调用中,第一个val 是一个值,第二个和第三个是向量。我想如果我在val 上调用pnorm,那么我会得到一个向量。如果您能帮助我理解为什么不是这样,我将不胜感激。谢谢
  • @PavoDive - pnorm 已矢量化。给定pnorm(1:3,mean=mean(1:10),sd=sd(1:10)),它将遍历1:3,为每个计算“循环”平均值(5.5)和sd(3.02)的单个值。与pnorm(1,mean(1:10),sd(1:10)); pnorm(2,mean(1:10),sd(1:10)); pnorm(3,mean(1:10),sd(1:10))基本相同
【解决方案2】:

这是dplyr 解决方案:

dt %>% group_by(diag) %>% 
       mutate(prob = pnorm(val, mean(val), sd(val), lower.tail = FALSE))

【讨论】:

    猜你喜欢
    • 2018-02-27
    • 1970-01-01
    • 2019-09-03
    • 1970-01-01
    • 1970-01-01
    • 2014-09-11
    • 1970-01-01
    • 2015-12-15
    • 2020-03-26
    相关资源
    最近更新 更多