【问题标题】:Faster way to multiplication in data frame在数据框中进行乘法的更快方法
【发布时间】:2014-05-25 06:53:34
【问题描述】:

我有一个这样的数据框(名称 t)

ID N com_a com_b com_c
A  3   1     0    0
A  5   0     1    0
B  1   1     0    0
B  1   0     1    0
B  4   0     0    1
B  4   1     0    0 

我已经尝试过com_a*N com_b*N com_c*N

ID N com_a com_b com_c com_a_N com_b_N com_c_N
A  3   1     0    0       3       0       0
A  5   0     1    0       0       5       0
B  1   1     0    0       1       0       0
B  1   0     1    0       0       1       0
B  4   0     0    1       0       0       4     
B  4   1     0    0       4       0       0

我使用for-function,但它需要很多时间我如何在大数据中快速完成

for (i in 1:dim(t)[1]){
    t$com_a_N[i]=t$com_a[i]*t$N[i]
    t$com_b_N[i]=t$com_b[i]*t$N[i]
    t$com_c_N[i]=t$com_c[i]*t$N[i]
    }

【问题讨论】:

  • 你的数据集有多大?
  • t 不是 R 中数据集的好名字,因为它是一个存储函数
  • @BenBolker 数据为 1085350*70。
  • 你在为 2:69 列做乘法吗?
  • @BenBolker 必须乘以 4:70 列。变量 N 在 3 列中

标签: r


【解决方案1】:
t <- transform(t,
      com_a_N=com_a*N,
      com_b_N=com_b*N,
      com_c_N=com_c*N)

应该快得多data.table 解决方案可能会更快。

【讨论】:

  • 我认为transform(t, com_a_N=ifelse(com_a, com_a, N)) 也可以工作
  • 是的。我没有仔细查看数据的结构,发现com 列都是二进制的...
【解决方案2】:

您可以为此使用sweep

(st <- sweep(t[, 3:5], 1, t$N, "*"))
#  com_a com_b com_c
#1     3     0     0
#2     0     5     0
#3     1     0     0
#4     0     1     0
#5     0     0     4
#6     4     0     0

可以使用pastesetNames 创建新名称,并且可以使用cbind 将新列添加到现有data.frame。这将适用于任意数量的列。

cbind(t, setNames(st, paste(names(st), "N", sep="_")))
#  ID N com_a com_b com_c com_a_N com_b_N com_c_N
#1  A 3     1     0     0       3       0       0
#2  A 5     0     1     0       0       5       0
#3  B 1     1     0     0       1       0       0
#4  B 1     0     1     0       0       1       0
#5  B 4     0     0     1       0       0       4
#6  B 4     1     0     0       4       0       0

【讨论】:

    【解决方案3】:

    @BenBolker 提出的data.table 解决方案

    library(data.table)
    setDT(t)[, c("com_a_N", "com_b_N", "com_c_N") := list(com_a*N, com_b*N, com_c*N)]
    
    ##    ID N com_a com_b com_c com_a_N com_b_N com_c_N
    ## 1:  A 3     1     0     0       3       0       0
    ## 2:  A 5     0     1     0       0       5       0
    ## 3:  B 1     1     0     0       1       0       0
    ## 4:  B 1     0     1     0       0       1       0
    ## 5:  B 4     0     0     1       0       0       4
    ## 6:  B 4     1     0     0       4       0       0
    

    【讨论】:

    • 您还可以将.SDlapply.SDcols 一起使用。也许您也可以添加它?
    • @Arun,不确定如何有效地做到这一点,也许您会添加一个单独的答案或您的编辑? setDT(t)[, lapply(.SD, function(x) x*N, N), .SDcols = c("com_a", "com_b", "com_c")] 没用
    • LHS 是相同的(尽管您可以使用 paste 生成它们而不是输入),然后是 :=,然后 RHS 将使用 lapply(.SD, ...) 而不是手动创建列表,然后.SDcols。想再试一次? ;)
    • @Arun,我可以让它工作的唯一方法是setDT(t)[, c("com_a_N", "com_b_N", "com_c_N") := lapply(.SD, function(x) x*N), .SDcols = c("com_a", "com_b", "com_c", "N")],但这实际上是将 4 个变量解析为 3。我怎样才能让 lapply 识别 N 而无需将其解析为 @ 987654335@?
    • 嗯,是的,你想想。你是对的。也许最好在this one 修复之前留下它..
    【解决方案4】:

    使用矩阵乘法更快:

    cbind(dat,dat[,3:5]*dat$N)
    

    虽然你应该在....之后设置列名

    为避免使用显式列索引(不推荐),您可以使用一些grep 魔法:

    cbind(dat,dat[,grep('com',colnames(dat))]*dat$N)
    

    【讨论】:

      【解决方案5】:

      dplyr 的另一个选项:

      require(dplyr)
      
      t <- mutate(t, com_a_N=com_a*N,
                     com_b_N=com_b*N,
                     com_c_N=com_c*N)
      

      【讨论】:

      • 我认为这与transform() 解决方案相比没有任何好处——mutate 是否更快或在其他方面有所不同...?
      • @BenBolker 我没有比较性能。只是认为这可能是另一种尝试,因为据我了解,dplyr 在某些情况下比基础 R 更快(我不知道这是否适用于这种情况)。
      • 我实际上并不认为它在这里会有很大的不同(我认为dplyr 的最大优势超过了plyr,它优雅但缓慢,不一定超过base R) .
      • @BenBolker 在这种情况下,我很抱歉发布一个与以前的答案(在这种情况下是你的)没有显着差异的答案。我这边缺乏知识。
      • 在那种情况下t %&gt;% mutate_each(funs(. * N), vars = starts_with("com"))
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-02
      • 1970-01-01
      • 2019-03-15
      • 2022-01-16
      • 1970-01-01
      • 2020-08-11
      相关资源
      最近更新 更多