【问题标题】:egen rowtotal (Stata) equivalent in R?R中的egen rowtotal(Stata)等价物?
【发布时间】:2014-11-27 17:18:02
【问题描述】:

我的数据看起来像这样

bankname    bankid  year    deposit dep_cert capital    surplus
Bank A         1    1881    244789  7250       20218    29513
Bank B         2    1881    195755  10243     185151    NA 
Bank C         3    1881    107736  13357     177612    NA
Bank D         4    1881    170600  NA         20000    NA
Bank E         5    1881    320000  351266    314012    NA

这是复制数据的代码。

bankname <- c("Bank A","Bank B","Bank C","Bank D","Bank E")
bankid <- c( 1, 2,  3,  4,  5)
year<- c( 1881, 1881,   1881,   1881,   1881)
deposit  <- c(244789,    195755, 107736, 170600, 32000000)
dep_cert<-c(7250,10243,13357,NA,351266)
capital<-c(20218,185151,177612,20000,314012)
surplus<-c(29513,NA,NA,NA,NA)
bankdata<-data.frame(bankname, bankid,year,deposit, dep_cert, capital, surplus)

我想创建一个名为liability 的新列作为depositdep_certcapitalsurplus 的总和。这意味着数据将如下所示。

bankname    bankid  year    deposit dep_cert capital    surplus liability
Bank A         1    1881    244789  7250       20218    29513   301770 
Bank B         2    1881    195755  10243     185151    NA      391149
Bank C         3    1881    107736  13357     177612    NA      298705
Bank D         4    1881    170600  NA         20000    NA      190600
Bank E         5    1881    320000  351266    314012    NA      32665278

但是,当我在 R 中使用 sum 命令时,由于缺少值,我得到了 NA。在Stata,我会这样做

egen liability = rowtotal(deposit, dep_cert,capital, surplus)

R 中的等效代码是什么?

另外,我的第二个问题是,用数据中的数字 0 替换所有缺失值 (NA),在 Stata 中,我会这样做

foreach x of varlist deposit dep_cert capital surplus {
    replace `x'=0 if missing(`x')
}

R 中的等效代码是什么?

【问题讨论】:

    标签: r rstudio stata


    【解决方案1】:

    对于这两个任务,您还可以使用 dplyr 包中的 mutate

    library(dplyr)
    vars <- c("deposit", "dep_cert", "capital", "surplus")
    

    计算行总和/总计

    正如 A Handcart And Mohair 在他们的 answer 中所解释的,您可以将 rowSumsna.rm = TRUE 一起使用:

    bankdata = bankdata %>%
        mutate(liability = rowSums(.[vars], na.rm = TRUE))
    

    将 NA 设置为 0

    我还建议您不要这样做(请参阅Nick Cox 的评论),但如果需要,您可以将mutate_replace 一起使用(另请参阅this answer 关于SO)。

    var_fun <- paste("replace(", vars, ", is.na(", vars, "), 0)", sep="")
    
    bankdata = bankdata %>%
        mutate_(.dots = setNames(var_fun, eval(vars)))
    

    setNames 创建一个包含变量名称和生成它的函数的向量。您需要在此处使用mutate_ 的下划线变体才能使用带引号的变量名。该技术在vignette on NSE(非标准评估)中有更详细的说明。

    【讨论】:

      【解决方案2】:

      使用data.table

      library(data.table)
      nm1 <- c("deposit", "dep_cert", "capital", "surplus")
      
      setDT(bankdata)[,liabiliy:=Reduce(`+`,
                 lapply(.SD, function(x) replace(x, is.na(x), 0))),.SDcols=nm1]
      
      
       bankdata
       #   bankname bankid year  deposit dep_cert capital surplus liabiliy
       #1:   Bank A      1 1881   244789     7250   20218   29513   301770
       #2:   Bank B      2 1881   195755    10243  185151      NA   391149
       #3:   Bank C      3 1881   107736    13357  177612      NA   298705
       #4:   Bank D      4 1881   170600       NA   20000      NA   190600
       #5:   Bank E      5 1881 32000000   351266  314012      NA 32665278
      

      0 替换NA 并执行rowSums

       setDT(bankdata)[, (nm1):=lapply(.SD, function(x) 
             replace(x, is.na(x), 0)), .SDcols=nm1][,
                   liability:=Reduce(`+`, .SD), .SDcols=nm1]
      
       bankdata
       #   bankname bankid year  deposit dep_cert capital surplus liability
       #1:   Bank A      1 1881   244789     7250   20218   29513    301770
       #2:   Bank B      2 1881   195755    10243  185151       0    391149
       #3:   Bank C      3 1881   107736    13357  177612       0    298705
       #4:   Bank D      4 1881   170600        0   20000       0    190600
       #5:   Bank E      5 1881 32000000   351266  314012       0  32665278
      

      基准测试

       bankdata1 <- bankdata[rep(1:nrow(bankdata), 1e5),]
       row.names(bankdata1) <- 1:nrow(bankdata1)
      
       f1 <- function() {rowSums(bankdata1[c("deposit", "dep_cert", 
                                           "capital", "surplus")], 
                                na.rm = TRUE)
      
                    }
      
      
      
       f2 <- function() {nm1 <- c("deposit", "dep_cert", "capital", "surplus")
                       DT <- data.table(bankdata1, key=c('bankname', 'bankid', 'year'))  
                       DT[, liabiliy:=Reduce(`+`,
                           lapply(.SD, function(x) replace(x, is.na(x), 0))),.SDcols=nm1]
                    }
      
       library(microbenchmark)
       microbenchmark(f1(), f2(), unit="relative")
       #   Unit: relative
       #expr      min       lq   median       uq      max neval
       #f1() 1.558999 1.355819 1.457036 1.426796 1.525313   100
       #f2() 1.000000 1.000000 1.000000 1.000000 1.000000   100
      

      【讨论】:

        【解决方案3】:

        不是一个完整的答案,但太长了,无法发表评论:

        您最初声明的 Stata 代码

        foreach `x' of varlist deposit dep_cert capital surplus {
            replace `x'=0 if missing(`x')
        }
        

        (1) 不起作用 (2) 无论如何都是个坏主意。

        这样就可以了

        foreach x of varlist deposit dep_cert capital surplus {
            replace `x' = 0 if missing(`x')
        }
        

        这也可以,而且更简洁,

        foreach x in deposit dep_cert capital surplus {
            replace `x' = 0 if missing(`x')
        }
        

        但是,在原始数据中用零覆盖缺失可能会导致信息丢失,并对数据的完整性造成打击。由于默认情况下egen 在计算行总数时会忽略缺失,因此在这种情况下不需要任何方式。

        【讨论】:

          【解决方案4】:

          在这种情况下,等效值为 rowSums

          rowSums(bankdata[c("deposit", "dep_cert", "capital", "surplus")], na.rm = TRUE)
          # [1]   301770   391149   298705   190600 32665278
          

          您缺少的主要是 na.rm = TRUE 参数。

          要将其添加到您的data.frame,您可以:

          bankdata$liability <- rowSums(bankdata[c("deposit", "dep_cert", 
                                                   "capital", "surplus")], 
                                        na.rm = TRUE)
          

          要将同一列中的NA 值替换为“0”,您可以:

          ## save some typing
          cols <- c("deposit", "dep_cert", "capital", "surplus")
          
          bankdata[cols][is.na(bankdata[cols])] <- 0
          bankdata
          #   bankname bankid year  deposit dep_cert capital surplus
          # 1   Bank A      1 1881   244789     7250   20218   29513
          # 2   Bank B      2 1881   195755    10243  185151       0
          # 3   Bank C      3 1881   107736    13357  177612       0
          # 4   Bank D      4 1881   170600        0   20000       0
          # 5   Bank E      5 1881 32000000   351266  314012       0
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-12-27
            • 2022-09-26
            • 1970-01-01
            • 1970-01-01
            • 2019-11-04
            • 1970-01-01
            相关资源
            最近更新 更多