【问题标题】:Select nth observation and sum by group using data.table使用 data.table 选择第 n 个观察值并按组求和
【发布时间】:2017-04-08 12:09:31
【问题描述】:

我想通过选择ab 的组的最后一个观察值,c 的第一个观察值,将组的每个观察值相加,将第一个表变成第二个表de,对于f,检查是否存在有效日期并使用该日期。

表 1:

ID   a    b    c        d        e          f
1   10  100 1000    10000   100000  ?
1   10  100 1001    10010   100100  5/07/1977
1   11  111 1002    10020   100200  5/07/1977
2   22  222 2000    20000   200000  6/02/1980
3   33  333 3000    30000   300000  20/12/1978
3   33  333 3001    30010   300100  ?
4   40  400 4000    40000   400000  ?
4   40  400 4001    40010   400100  ?
4   40  400 4002    40020   400200  7/06/1944
4   44  444 4003    40030   400300  ?
4   44  444 4004    40040   400400  ?
4   44  444 4005    40050   400500  ?
5   55  555 5000    50000   500000  31/05/1976
5   55  555 5001    50010   500100  31/05/1976

表 2:

ID   a    b    c         d        e          f
1   11  111 1000     30030   300300  5/07/1977
2   22  222 2000     20000   200000  6/02/1980
3   33  333 3000     60010   600100 20/12/1978
4   44  444 4000    240150  2401500  7/06/1944
5   55  555 5000    100010  1000100 31/05/1976

我查看了 StackOverflow 问题,但我只看到了其中的元素。我可以按照以下步骤执行到 e。

library(data.table)

setwd('D:/Work/BRB/StackOverflow')

DT = data.table(fread('datatable.csv', header=TRUE))

AB = DT[ , .SD[.N], ID ]
AB = AB[ , c('a', 'b') ]

C = DT[ , .SD[1], ID ]
C = C[ , 'c' ]
DE = DT[ , .(d = sum(d), e = sum(e)) , by = ID ]

Final = cbind(AB, C, DE)
Final

我的问题是,我可以在一次转换中对变量abcde 进行操作而不必将其拆分为 3?

另外,我不知道该怎么做f。有什么建议吗?

最后,我是 R 新手。我的代码还有什么可以改进的吗?

【问题讨论】:

  • 类似:DT[, .(a = a[.N], b = b[.N], c = c[1], d = sum(d), e = sum(e)), ID]?
  • 顺便说一句:fread 返回一个 data.table,因此无需将其包装在 data.table()

标签: r data.table


【解决方案1】:

您可以改进以下几点:

  1. fread 将返回一个 data.table,因此无需将其包装在 data.table 中。您可以通过class(DT)查看。
  2. 在读入数据时使用na.strings 参数。请参阅下面的示例。
  3. 总结:

    DT[, .(a = a[.N], 
           b = b[.N], 
           c = c[1], 
           d = sum(d), 
           e = sum(e), 
           f = unique(na.omit(f)))
       , by = ID]
    

你会得到:

   ID  a   b    c      d       e          f
1:  1 11 111 1000  30030  300300  5/07/1977
2:  2 22 222 2000  20000  200000  6/02/1980
3:  3 33 333 3000  60010  600100 20/12/1978
4:  4 44 444 4000 240150 2401500  7/06/1944
5:  5 55 555 5000 100010 1000100 31/05/1976

一些解释和其他说明:

  • 使用[1] 进行子集化将为您提供组的第一个值。您还可以使用在 data.table 中优化的first-函数,因此速度更快。
  • 使用[.N] 进行子集化将为您提供组的最后一个值。您还可以使用在 data.table 中优化的last-函数,因此速度更快。
  • 不要使用在 R 中也是函数的变量名(在这种情况下,不要使用 c 作为变量名)。另请参阅 ?c,了解 c 函数的作用。
  • 为了总结f 变量,我将uniquena.omit 结合使用。如果ID 有多个唯一日期,您还可以使用例如na.omit(f)[1]

如果速度是个问题,您可以将上述优化为(感谢@Frank):

DT[order(f)
   , .(a = last(a), 
       b = last(b), 
       c = first(c), 
       d = sum(d), 
       e = sum(e), 
       f = first(f))
   , by = ID]

f 排序会将NA-values 放在最后。因此,现在内部 GForce 优化用于所有计算。


使用的数据:

DT <- fread("ID   a    b    c        d        e          f
             1   10  100 1000    10000   100000  ?
             1   10  100 1001    10010   100100  5/07/1977
             1   11  111 1002    10020   100200  5/07/1977
             2   22  222 2000    20000   200000  6/02/1980
             3   33  333 3000    30000   300000  20/12/1978
             3   33  333 3001    30010   300100  ?
             4   40  400 4000    40000   400000  ?
             4   40  400 4001    40010   400100  ?
             4   40  400 4002    40020   400200  7/06/1944
             4   44  444 4003    40030   400300  ?
             4   44  444 4004    40040   400400  ?
             4   44  444 4005    40050   400500  ?
             5   55  555 5000    50000   500000  31/05/1976
             5   55  555 5001    50010   500100  31/05/1976", na.strings='?')

【讨论】:

    【解决方案2】:

    我们可以使用tidyverse。按'ID'分组后,我们summarise基于firstlast观察的列

    library(dplyr) 
    DT %>% 
       group_by(ID) %>% 
       summarise(a = last(a),
                 b = last(b), 
                 c = first(c), 
                 d = sum(d), 
                 e = sum(e), 
                 f = f[f!="?"][1])
    # A tibble: 5 × 7
    #     ID     a     b     c      d       e          f
    #  <int> <int> <int> <int>  <int>   <int>      <chr>
    #1     1    11   111  1000  30030  300300  5/07/1977
    #2     2    22   222  2000  20000  200000  6/02/1980
    #3     3    33   333  3000  60010  600100 20/12/1978
    #4     4    44   444  4000 240150 2401500  7/06/1944
    #5     5    55   555  5000 100010 1000100 31/05/1976
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多