【问题标题】:R Summary stats by column of data tableR 按数据表列汇总统计信息
【发布时间】:2020-12-03 19:36:51
【问题描述】:

我想为一个包含 50 多列的数据表创建一个数据字典。首先,我想创建汇总对象、数据表或类似对象,在源数据表中每列有一行,列显示最早和最新的非缺失值、最小值和最大值、缺失值的数量等.我试图通过循环我的源数据表的列来做到这一点,但我无法让计算工作。这是我的代码的简化版本,加上一大块代码,可以满足我的要求,但没有循环:

require("data.table")

dtTest <- data.table(dObsDt = c("2020-08-01","2020-08-02","2020-08-03")
                 , nPrcp.LAKE = c(NA,12,13)
                 , nPrcp.PLAT = c(NA,NA,33)
)
dtTest

# Using loop
# Runs without error but does not produce desired results
vsCols <- colnames(dtTest)
dtColDesc <- data.table()
for (lasCol in vsCols) {
  ldtVar <- data.table()
  ladEarliest <- dtTest[!is.na(eval(lasCol)),list(dLatest=min(dObsDt))][[1]]
  lanMax <- dtTest[!is.na(eval(lasCol)),list(dMax=max(eval(lasCol)))][[1]]
  ldtVar[,':=' (sColName = lasCol
                , nMax = lanMax
                , dEarliest = ladEarliest
  )]
  dtColDesc <- rbind(dtColDesc, ldtVar, fill=TRUE)
}
dtColDesc

# Remove loop
# Runs without error and produces desired results but not scalable
vsCols <- colnames(dtTest)
dtColDesc <- data.table()

ldtVar <- data.table()
ladEarliest <- dtTest[!is.na(dObsDt),list(dLatest=min(dObsDt))][[1]]
lanMax <- dtTest[!is.na(dObsDt),list(dMax=max(dObsDt))][[1]]
ldtVar[,':=' (sColName = lasCol
              , nMax = lanMax
              , dEarliest = ladEarliest
)]
dtColDesc <- rbind(dtColDesc, ldtVar, fill=TRUE)

ldtVar <- data.table()
ladEarliest <- dtTest[!is.na(nPrcp.LAKE),list(dLatest=min(dObsDt))][[1]]
lanMax <- dtTest[!is.na(nPrcp.LAKE),list(dMax=max(nPrcp.LAKE))][[1]]
ldtVar[,':=' (sColName = lasCol
              , nMax = lanMax
              , dEarliest = ladEarliest
)]
dtColDesc <- rbind(dtColDesc, ldtVar, fill=TRUE)

ldtVar <- data.table()
ladEarliest <- dtTest[!is.na(nPrcp.PLAT),list(dLatest=min(dObsDt))][[1]]
lanMax <- dtTest[!is.na(nPrcp.PLAT),list(dMax=max(nPrcp.PLAT))][[1]]
ldtVar[,':=' (sColName = lasCol
              , nMax = lanMax
              , dEarliest = ladEarliest
)]
dtColDesc <- rbind(dtColDesc, ldtVar, fill=TRUE)

dtColDesc

【问题讨论】:

    标签: r loops datatable


    【解决方案1】:

    对于单列统计数据,其他两种建议的解决方案都运行良好。对于两列统计数据,这可能不是最优雅的解决方案,但它确实有效:

    vsCols <- colnames(dtTest)
    dtColDesc <- data.table()
    for (lasCol in vsCols) {
      ldtVar <- data.table()
      ladEarliest <- dtTest[!is.na(dtTest[[lasCol]]),list(dEarliest=min(dObsDt))][[1]]
      ladLatest <- dtTest[!is.na(dtTest[[lasCol]]),list(dLatest=max(dObsDt))][[1]]
      ldtVar[,':=' (sColName = lasCol
                    , dEarliest = ladEarliest
                    , dLatest = ladLatest
      )]
      dtColDesc <- rbind(dtColDesc, ldtVar, fill=TRUE)
    }
    dtColDesc
    

    【讨论】:

      【解决方案2】:

      对于数据框中最早和最新的非缺失值以外的信息,psych 包中的describe() 函数会生成一个表格,其中输入数据框中的列按行排列,各种描述性统计以列表示。我们用mtcars 数据框来说明:

      library(psych)
      describe(mtcars)
      
      
      > describe(mtcars)
           vars  n   mean     sd median trimmed    mad   min    max  range  skew
      mpg     1 32  20.09   6.03  19.20   19.70   5.41 10.40  33.90  23.50  0.61
      cyl     2 32   6.19   1.79   6.00    6.23   2.97  4.00   8.00   4.00 -0.17
      disp    3 32 230.72 123.94 196.30  222.52 140.48 71.10 472.00 400.90  0.38
      hp      4 32 146.69  68.56 123.00  141.19  77.10 52.00 335.00 283.00  0.73
      drat    5 32   3.60   0.53   3.70    3.58   0.70  2.76   4.93   2.17  0.27
      wt      6 32   3.22   0.98   3.33    3.15   0.77  1.51   5.42   3.91  0.42
      qsec    7 32  17.85   1.79  17.71   17.83   1.42 14.50  22.90   8.40  0.37
      vs      8 32   0.44   0.50   0.00    0.42   0.00  0.00   1.00   1.00  0.24
      am      9 32   0.41   0.50   0.00    0.38   0.00  0.00   1.00   1.00  0.36
      gear   10 32   3.69   0.74   4.00    3.62   1.48  3.00   5.00   2.00  0.53
      carb   11 32   2.81   1.62   2.00    2.65   1.48  1.00   8.00   7.00  1.05
           kurtosis    se
      mpg     -0.37  1.07
      cyl     -1.76  0.32
      disp    -1.21 21.91
      hp      -0.14 12.12
      drat    -0.71  0.09
      wt      -0.02  0.17
      qsec     0.34  0.32
      vs      -2.00  0.09
      am      -1.92  0.09
      gear    -1.07  0.13
      carb     1.26  0.29
      > 
      

      最早和最新的非缺失值可以添加sapply() 的组合,如另一个答案中所述,以及pastecs::first()pastecs::last()。当我们在这些函数上设置参数na.rm = TRUE 时,它们会检索第一个(或最后一个)非缺失值。

      summaryDf <- describe(mtcars)
      library(pastecs)
      summaryDf$earliest <- sapply(mtcars, function(x) { first(x,na.rm=TRUE)})
      summaryDf$latest <- sapply(mtcars, function(x) {last(x,na.rm=TRUE)})
      

      ...和输出:

      > summaryDf
           vars  n   mean     sd median trimmed    mad   min    max  range  skew
      mpg     1 32  20.09   6.03  19.20   19.70   5.41 10.40  33.90  23.50  0.61
      cyl     2 32   6.19   1.79   6.00    6.23   2.97  4.00   8.00   4.00 -0.17
      disp    3 32 230.72 123.94 196.30  222.52 140.48 71.10 472.00 400.90  0.38
      hp      4 32 146.69  68.56 123.00  141.19  77.10 52.00 335.00 283.00  0.73
      drat    5 32   3.60   0.53   3.70    3.58   0.70  2.76   4.93   2.17  0.27
      wt      6 32   3.22   0.98   3.33    3.15   0.77  1.51   5.42   3.91  0.42
      qsec    7 32  17.85   1.79  17.71   17.83   1.42 14.50  22.90   8.40  0.37
      vs      8 32   0.44   0.50   0.00    0.42   0.00  0.00   1.00   1.00  0.24
      am      9 32   0.41   0.50   0.00    0.38   0.00  0.00   1.00   1.00  0.36
      gear   10 32   3.69   0.74   4.00    3.62   1.48  3.00   5.00   2.00  0.53
      carb   11 32   2.81   1.62   2.00    2.65   1.48  1.00   8.00   7.00  1.05
           kurtosis    se earliest latest
      mpg     -0.37  1.07    21.00  21.40
      cyl     -1.76  0.32     6.00   4.00
      disp    -1.21 21.91   160.00 121.00
      hp      -0.14 12.12   110.00 109.00
      drat    -0.71  0.09     3.90   4.11
      wt      -0.02  0.17     2.62   2.78
      qsec     0.34  0.32    16.46  18.60
      vs      -2.00  0.09     0.00   1.00
      am      -1.92  0.09     1.00   1.00
      gear    -1.07  0.13     4.00   4.00
      carb     1.26  0.29     4.00   2.00
      > 
      

      我们可以通过将数据框的第一行和最后一行设置为NA,然后重新运行计算来验证非缺失值的行为。

      mtcars[c(1,32),] <- NA 
      summaryDf$earliest = sapply(mtcars, function(x){ first(x,na.rm=TRUE) })
      summaryDf$latest <- sapply(mtcars, function(x) {last(x,na.rm=TRUE)})
      summaryDf
      mtcars[c(2,31),]
      

      ...以及输出,说明第一个和最后一个值取自第 2 行和第 31 行,而不是第 1 行和第 32 行:

      > summaryDf
           vars  n   mean     sd median trimmed    mad   min    max  range  skew
      mpg     1 32  20.09   6.03  19.20   19.70   5.41 10.40  33.90  23.50  0.61
      cyl     2 32   6.19   1.79   6.00    6.23   2.97  4.00   8.00   4.00 -0.17
      disp    3 32 230.72 123.94 196.30  222.52 140.48 71.10 472.00 400.90  0.38
      hp      4 32 146.69  68.56 123.00  141.19  77.10 52.00 335.00 283.00  0.73
      drat    5 32   3.60   0.53   3.70    3.58   0.70  2.76   4.93   2.17  0.27
      wt      6 32   3.22   0.98   3.33    3.15   0.77  1.51   5.42   3.91  0.42
      qsec    7 32  17.85   1.79  17.71   17.83   1.42 14.50  22.90   8.40  0.37
      vs      8 32   0.44   0.50   0.00    0.42   0.00  0.00   1.00   1.00  0.24
      am      9 32   0.41   0.50   0.00    0.38   0.00  0.00   1.00   1.00  0.36
      gear   10 32   3.69   0.74   4.00    3.62   1.48  3.00   5.00   2.00  0.53
      carb   11 32   2.81   1.62   2.00    2.65   1.48  1.00   8.00   7.00  1.05
           kurtosis    se earliest latest
      mpg     -0.37  1.07    21.00  15.00
      cyl     -1.76  0.32     6.00   8.00
      disp    -1.21 21.91   160.00 301.00
      hp      -0.14 12.12   110.00 335.00
      drat    -0.71  0.09     3.90   3.54
      wt      -0.02  0.17     2.88   3.57
      qsec     0.34  0.32    17.02  14.60
      vs      -2.00  0.09     0.00   0.00
      am      -1.92  0.09     1.00   1.00
      gear    -1.07  0.13     4.00   5.00
      carb     1.26  0.29     4.00   8.00
      > mtcars[c(2,31),]
                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
      Mazda RX4 Wag  21   6  160 110 3.90 2.875 17.02  0  1    4    4
      Maserati Bora  15   8  301 335 3.54 3.570 14.60  0  1    5    8
      

      【讨论】:

        【解决方案3】:

        你可以用这样的方式做你想做的事情:

        data.table(sColName = colnames(dtTest),
                   max = sapply(dtTest, max, na.rm=T),
                   min = sapply(dtTest, min, na.rm=T),
                   median = sapply(dtTest, median, na.rm=T),
                   nmissing = sapply(dtTest, function(x) sum(is.na(x)))
        )
        

        但是请注意,您最终将在每一列中使用多个数据类型,这意味着您的大多数列最终都将数字和日期存储为字符。如果这只是为了快速总结,这没什么大不了的,但如果您想将此数据传递给其他事物,则会有问题。

        【讨论】:

        • 谢谢。这让我得到了大部分的帮助,但我需要为每个变量找到最早的 (min dObsDt) 和最新的 (max dObsDt) 非缺失值,我不认为这种方法会这样做。我错过了什么吗?
        • 我的回答只是一般方法的一个例子 :-) 您可以为您可能想要执行的任何其他操作添加行。例如earliest = sapply(dtTest, function(x){ first(x[!is.na(x)]) }
        • 据我了解 sapply 在应用于数据表时的工作方式,它将每一列作为向量提取并允许我进行计算,这为我提供了我需要的大部分描述性统计信息,但我不要以为它会让我做最早和最新的计算。对于这些值,我需要对两列进行计算:为所有具有另一列非缺失值的行(在本例中为 nPrcp.PLAT)找到一列 dObsDt 的最小值和最大值,并对每个列执行此操作超过 50 列。
        • sapply 可以很好地处理这个问题:您可以使用它向您的函数发送其他静态参数。因此,如果您扩展该函数以获取第二列(日期),那么您始终可以将该列作为第二个函数参数传递。即earliest = sapply(dtTest, function(x){ ... }, dtTest$MyDateCol)
        • 感谢您的帮助,但我无法正常工作。我已经尝试了所有我能想到的逗号、圆括号和大括号的组合,但我无法同时使用“循环”列和日期列。你有没有机会向我指出一个可以详细说明这一点的资源?
        猜你喜欢
        • 1970-01-01
        • 2014-01-15
        • 2018-08-11
        • 2023-02-21
        • 2014-04-09
        • 2021-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多