【问题标题】:calculate row sum and product in data.frame计算 data.frame 中的行总和和乘积
【发布时间】:2015-01-22 01:24:26
【问题描述】:

我想在 R 中的 data.frame 中附加一列,其中包含行和和乘积 考虑以下数据框

x    y     z
1    2     3
2    3     4
5    1     2

我想得到以下内容

x    y     z    sum    prod
1    2     3    6       6  
2    3     4    9       24 
5    1     2    8       10

我试过了

 sum = apply(ages,1,add)

但它给了我一个行向量。有人可以告诉我一个有效的命令来求和和乘积并将它们附加到原始数据框,如上所示?

【问题讨论】:

    标签: r dataframe apply


    【解决方案1】:

    只是部分答案,但如果所有值都大于等于0,可以使用rowSums/rowsum计算乘积:

    df <- data.frame(x = c(1, 2, 5), y = c(2, 3, 1), z = c(3, 4, 2))
    
    # custom row-product-function
    my_rowprod <- function(x) exp(rowSums(log(x)))
    
    df$prod <- my_rowprod(df)
    df
    

    通用版本是(包括底片):

    my_rowprod_2 <- function(x) {
      sign <- ifelse((rowSums(x < 0) %% 2) == 1, -1, 1)
      prod <- exp(rowSums(log(abs(x)))) * sign
      prod
    }
    df$prod <- my_rowprod_2(df)
    df
    

    【讨论】:

      【解决方案2】:

      以下也可以,但需要输入列名:

      ddf$sum = with(ddf, x+y+z)
      ddf$prod = with(ddf, x*y*z)
      ddf
        x y z sum prod
      1 1 2 3   6    6
      2 2 3 4   9   24
      3 5 1 2   8   10
      

      有了data.table,另一种形式可以是:

      library(data.table)    
      cbind(dt, dt[,list(sum=x+y+z, product=x*y*z),])
         x y z sum product
      1: 1 2 3   6       6
      2: 2 3 4   9      24
      3: 5 1 2   8      10
      

      @David Arenberg 在 cmets 中建议了一个更简单的版本:

      dt[, ":="(sum = x+y+z, product = x*y*z)]
      

      【讨论】:

      • 我想知道您是否可以通过引用而不是使用 cbind... 之类的 dt[, ":="(sum = x+y+z, product = x*y*z)] 来分配?
      • 我不知道这个更简单的版本。
      【解决方案3】:

      另一种方法。

      require(data.table)
      
      # Create data
      dt <- data.table(x = c(1,2,5), y = c(2,3,1), z = c(3,4,2))
      
      # Create index
      dt[, i := .I]
      
      # Compute sum and prod
      dt[, sum := sum(x, y, z), by = i]
      dt[, prod := prod(x, y, z), by = i]
      dt
      
      
      # Compute sum and prod using .SD
      dt[, c("sum", "prod") := NULL]
      dt
      dt[, sum := sum(.SD), by = i, .SDcols = c("x", "y", "z")]
      dt[, prod := prod(.SD), by = i, .SDcols = c("x", "y", "z")]
      dt
      
      
      # Compute sum and prod using .SD and list
      dt[, c("sum", "prod") := NULL]
      dt
      dt[, c("sum", "prod") := list(sum(.SD), prod(.SD)), by = i,
         .SDcols = c("x", "y", "z")]
      dt
      
      
      # Compute sum and prod using .SD and lapply
      dt[, c("sum", "prod") := NULL]
      dt
      dt[, c("sum", "prod") := lapply(list(sum, prod), do.call, .SD), by = i,
         .SDcols = c("x", "y", "z")]
      dt
      

      【讨论】:

      • 您应该演示如何将lapply.SD.SDcols 结合使用。
      • @Roland,别以为lapply.SDcols这里有必要,他应该只是做了setDT(df)[, ":="(sum = rowSums(.SD), prod = Reduce("*", .SD))]之类的事情
      • 我添加了.SD 的解决方案。我看不出lapply 在这里有什么帮助。
      • @Roland,我添加了lapply 解决方案。在某些情况下可能有用,但我认为它很难看。
      • 为什么我需要在您的第一种方法中创建索引?
      【解决方案4】:

      试试

       transform(df, sum=rowSums(df), prod=x*y*z)
       #  x y z sum prod
       #1 1 2 3   6    6
       #2 2 3 4   9   24
       #3 5 1 2   8   10
      

      或者

       transform(df, sum=rowSums(df), prod=Reduce(`*`, df))
       #   x y z sum prod
       #1 1 2 3   6    6
       #2 2 3 4   9   24
       #3 5 1 2   8   10
      

      另一种选择是使用来自matrixStatsrowProds

       library(matrixStats)
       transform(df, sum=rowSums(df), prod=rowProds(as.matrix(df)))
      

      如果您使用的是apply

       df[,c('sum', 'prod')] <-  t(apply(df, 1, FUN=function(x) c(sum(x), prod(x))))
       df
       #  x y z sum prod
       #1 1 2 3   6    6
       #2 2 3 4   9   24
       #3 5 1 2   8   10
      

      【讨论】:

      • 你能告诉我Reduce(`*`, df)是做什么的吗?
      • @Khurram Majeed 类似于Reduce(*,as.list(df))。因为data.framelist,所以你不需要使用as.list。它将对应位置的每个元素相乘,即第一行、第二行等。
      猜你喜欢
      • 2022-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      • 2016-02-01
      • 1970-01-01
      相关资源
      最近更新 更多