【问题标题】:Calculare for each row the percentage of a variable by another in data.table为每一行计算一个变量在 data.table 中的百分比
【发布时间】:2023-03-17 03:07:01
【问题描述】:

我正在寻找一种方法来优化 data.table 中的聚合,我有几百万个数据,而我目前的实现速度很慢。

可重现的例子:

library(data.table)
df <- data.table(Factor = as.factor(rep(LETTERS[1:3], 3)),
                 Variable = 1:9)

当前实施:

aux <- df[, .(sumVar = sum(Variable)/sum(df$Variable)), by = .(Factor)]
df[aux, sumVar := sumVar, on = .(Factor = Factor)]

期望的输出:

> df
   Factor Variable    sumVar
1:      A        1 0.2666667
2:      B        2 0.3333333
3:      C        3 0.4000000
4:      A        4 0.2666667
5:      B        5 0.3333333
6:      C        6 0.4000000
7:      A        7 0.2666667
8:      B        8 0.3333333
9:      C        9 0.4000000

我认为我的问题在merge,但我不知道如何改进它,我对dplyr不熟悉,我还没有找到任何方法可以与data.table一起操作.

感谢任何帮助!

【问题讨论】:

  • 这里使用dplyr df %&gt;% group_by(Factor) %&gt;% mutate(A=sum(Variable)/sum(df$Variable))

标签: r performance dplyr data.table


【解决方案1】:

您的示例中有很多重复正确,因此不确定我是否对其进行了解释。尽管如此,最好只计算一次分母并使用gsum

BigTotal <- df[, sum(Variable)]
df[, sumVar1 := sum(Variable), by = .(Factor)][, propVar := sumVar1 / BigTotal]

大约是 Ben 最快解决方案的一半时间。

df <- data.table(
  Factor = as.factor(sample(LETTERS, size = 10^8, replace = T)),
  Variable = sample(10^3, size = 10^8, replace = T)
)

microbenchmark::microbenchmark(dt1 = {
  aux <- df[, .(sumVar = sum(Variable)/sum(df$Variable)), keyby = .(Factor)]
  df[aux, sumVar := sumVar, on = .(Factor = Factor)]
},
dt2 = {
BigTotal <- df[, sum(Variable)]
df[, sumVar1 := sum(Variable), by = .(Factor)][, propVar := sumVar1 / BigTotal]
}, 
times = 2)


Unit: seconds
 expr      min       lq     mean   median       uq      max neval cld
  dt1 9.523696 9.523696 9.567555 9.567555 9.611414 9.611414     2   b
  dt2 3.996581 3.996581 4.521274 4.521274 5.045967 5.045967     2  a 

【讨论】:

    【解决方案2】:

    类似

    df[ , ':='(sumVar = sum(Variable)/sum(df$Variable)), by = .(Factor)] 
    

    【讨论】:

    • 最后,您在@Hugh 的帮助下的回答似乎是最好的解决方案:BigTotal &lt;- df[, sum(Variable)]; df[ , sumVar := sum(Variable)/BigTotal, by = .(Factor)]。谢谢大家!
    【解决方案3】:

    您拥有什么样的数据以及您期望的时间?在以下具有 100M 行的示例中,我得到以下时间

    library(data.table)
    
    df <- data.table(
      Factor = as.factor(sample(LETTERS, size = 10^8, replace = T)),
      Variable = sample(10^3, size = 10^8, replace = T)
    )
    
    # data.table solution 1
    system.time({
      aux <- df[, .(sumVar = sum(Variable)/sum(df$Variable)), by = .(Factor)]
      df[aux, sumVar := sumVar, on = .(Factor = Factor)]
    })  # ~10.5 seconds
    
    # data.table solution 2
    system.time({
      df[, sumVar := sum(Variable)/sum(df$Variable), by = Factor]
    })  # ~8.3 seconds
    
    # dplyr solution 1
    system.time({
      df %>% dplyr::group_by(Factor) %>% dplyr::mutate(A=sum(Variable)/sum(df$Variable))
    })  # ~10.0 seconds
    

    请注意,随着 Factor 的基数增加,data.table 的加速变得更加令人印象深刻..

    df <- data.table(
      Factor = as.factor(sample(as.character(10^6), size = 10^8, replace = T)),
      Variable = as.numeric(sample(10^3, size = 10^8, replace = T))
    )
    
    # data.table solution 1
    system.time({
      aux <- df[, .(sumVar = sum(Variable)/sum(df$Variable)), by = .(Factor)]
      df[aux, sumVar := sumVar, on = .(Factor = Factor)]
    })  # ~5.0 seconds
    
    # data.table solution 2
    system.time({
      df[, sumVar := sum(Variable)/sum(df$Variable), by = Factor]
    })  # ~3.1 seconds
    
    # dplyr solution 1
    system.time({
      df %>% dplyr::group_by(Factor) %>% dplyr::mutate(A=sum(Variable)/sum(df$Variable))
    })  # ~6.9 seconds
    

    【讨论】:

      猜你喜欢
      • 2020-03-15
      • 1970-01-01
      • 2019-03-19
      • 1970-01-01
      • 1970-01-01
      • 2021-05-02
      • 2021-12-09
      • 2015-10-07
      • 1970-01-01
      相关资源
      最近更新 更多