【问题标题】:R: data.table custom function on subsetR:子集上的data.table自定义函数
【发布时间】:2017-09-07 20:27:17
【问题描述】:

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

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”(例如,参见 volume = 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"]值执行该函数,结果长度与原表相同

我相信这可以通过 data.table 方法有效地完成,但我并没有完全让它发挥作用。 在.SDs 上操作似乎很自然。所以我首先尝试通过

扩展每个子集
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”,然后计算上面的公式,即所有 C 和 P 的 volume/10+price_in[cp_flag=="C"]-price_out[cp_flag=="P"]。但如果只有 Cs 或 Ps,则仅使用他们的信息,即 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")]

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

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

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

【问题讨论】:

  • 我以为这是原生日期格式? IE。 %YYYY-%MM-%DD,既然是as.Date()的默认格式?
  • 啊,我明白你的意思了。添加了“as.Date”
  • 谢谢。我在正文中提到了它(“P”和“C”的向量),但现在也将它编辑到枚举中以便更好地参考

标签: r data.table


【解决方案1】:

我猜是这样的:

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

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

【讨论】:

  • 谢谢弗兰克!像魅力一样工作
猜你喜欢
  • 1970-01-01
  • 2019-11-05
  • 1970-01-01
  • 2013-01-08
  • 1970-01-01
  • 2020-11-19
  • 2021-01-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多