R:子集上的data.table自定义函数

时间:2017-09-07 20:27:18

标签: r data.table

这是我的数据的最小工作示例:

library(data.table)
df <- data.table(date=as.Date(c("1999-01-04","1999-01-04","1999-01-04","1999-01-04","1999-01-04","1999-01-04","1999-01-04","1999-01-04")),volume=c(1000,1000,1200,1250,1200,1300,1250,1200),cp_flag=c("P","C","C","P","C","C","P","P"),price_in=c(10.1,120.4,100.3,0.1,90.2,45.7,99.1,7.4), price_out=c(12.4,122.1,102.0,0.6,99.1,48.1,100.0,8.1), dtm=c(10,10,12,12,12,15,15,12))
setorder(df,date,dtm,volume)
df
         date volume cp_flag price_in price_out dtm
1: 1999-01-04   1000       P     10.1      12.4  10
2: 1999-01-04   1000       C    120.4     122.1  10
3: 1999-01-04   1200       C    100.3     102.0  12
4: 1999-01-04   1200       P      7.4       8.1  12
5: 1999-01-04   1200       C     90.2      99.1  13
6: 1999-01-04   1250       P      0.1       0.6  12
7: 1999-01-04   1250       P     99.1     100.0  15
8: 1999-01-04   1300       C     45.7      48.1  15

我的目标是:每个日期我想计算具有相同1)音量和2)dtm(又名持续时间)的所有项目的惯用功能,具体取决于它是否为“ C“或”P“产品,例如:volume/10+price_in[cp_flag=="C"]-price_out[cp_flag=="P"]

这里的另一个难点是每个日期/体积/ dtm组合可能有不同数量的“P”和“C”(例如参见体积= 1200),我想将其视为如下所述。

作为输出我寻找

         date volume dtm
1: 1999-01-04   1000  10
2: 1999-01-04   1200  12
3: 1999-01-04   1200  13
4: 1999-01-04   1250  12
5: 1999-01-04   1250  15
6: 1999-01-04   1300  15

附加列表示上述函数的结果,表的长度由所有日期/体积/ dtm以下列方式确定:

  1. 如果恰好有1个“P”产品和1个“C”产品(如第一个组合),那么公式的计算很简单,并且得到1个结果
  2. 如果有多个“P”产品和1个“C”产品,或者相反,那么结果列中有“P”和“C”产品之间所有交叉组合的条目
  3. 如果有几个“P”产品和几个“C”产品,即“C”和“P”之间的所有可能的交叉组合,则相同
  4. 如果只有一个产品/类别(例如C),则使用相同产品的price_in[cp_flag="C"]price_out[cp_flag="C"]值执行该功能,并且结果的长度与原始表
  5. 我相信这可以通过data.table方法有效地完成,但我还是不能让它工作。 在.SD s上操作似乎很自然。所以我首先尝试通过

    扩展每个子集
    df[,print(.SD),by=.(date,volume,dtm),.SDcols=c("price_in","price_out","volume","cp_flag")]
    

    这给了我所有想要的组合:

       price_in price_out cp_flag
    1:     10.1      12.4       P
    2:    120.4     122.1       C
       price_in price_out cp_flag
    1:    100.3     102.0       C
    2:      7.4       8.1       P
       price_in price_out cp_flag
    1:     90.2      99.1       C
       price_in price_out cp_flag
    1:      0.1       0.6       P
       price_in price_out cp_flag
    1:     99.1       100       P
       price_in price_out cp_flag
    1:     45.7      48.1       C
    

    但现在我不确定如何计算惯用函数,即检查每组中有多少“C”和“P”,然后计算上面的公式,即volume/10+price_in[cp_flag=="C"]-price_out[cp_flag=="P"]表示所有C和普的。但是,如果只有C或P只使用他们的信息,即price_in和price_out的相同产品。 对于第一部分,我尝试过像

    这样的东西
    df[,lapply(.SD,function(x) x[cp_flag=="C",volume/10]+x[cp_flag=="C",price_in]-x[cp_flag=="P",price_out]),by=.(date,volume,dtm),.SDcols=c("price_in","price_out","volume","cp_flag")]
    

    但这失败了,因为在这种情况下我似乎误解了如何使用自定义函数。

    问题:如何在具有此类附加案例结构的数据表的子集上正确使用此类自定义函数?

    注意:我知道这个例子看起来很复杂,也许我已经太深了,可能花了太多时间来破解它,但我看不出更简单的方式来呈现我的问题。如果我有任何进一步的许可,请告诉我。任何帮助都非常感谢!

1 个答案:

答案 0 :(得分:2)

我猜是这样的:

res = df[, {
  flags   = sort(unique(cp_flag))
  n_flags = length(flags)

  if (n_flags == 1L) 
    .(g = .GRP, price_in, price_out, flags = flags) 

  else CJ(
    g = .GRP,
    price_in = price_in[cp_flag == "C"], 
    price_out = price_out[cp_flag == "P"], 
    flags = toString(flags)
  )
}, by=.(date, volume, dtm)][, v := volume/10 + price_in - price_out][]

         date volume dtm g price_in price_out flags     v
1: 1999-01-04   1000  10 1    120.4      12.4  C, P 208.0
2: 1999-01-04   1200  12 2     90.2       8.1  C, P 202.1
3: 1999-01-04   1200  12 2    100.3       8.1  C, P 212.2
4: 1999-01-04   1250  12 3      0.1       0.6     P 124.5
5: 1999-01-04   1250  15 4     99.1     100.0     P 124.1
6: 1999-01-04   1300  15 5     45.7      48.1     C 127.6

我不会说这是有效的,但至少计算是以矢量化方式完成的。