在data.table中,基于值选择R组。

6

你好,我想选择数据表中按日期和id分组的所有正值列,其中条件是e == 1。

   id   date     e       logret 
   7 2011-07-29  1   -0.0272275211      
   7 2011-07-29  2    0.0034229025      
   7 2011-07-29  3    0.0042622177      
   8 2011-07-29  1    0.0035662770      
   8 2011-07-29  2   -0.0015268474 
   8 2011-07-29  3    0.0013333333
   7 2011-07-30  1    0.0044444444      
   7 2011-07-30  2   -0.0001111111 
   7 2011-07-30  3    0.0013333333

这里选择了所有id为8且日期为2011-07-29的元素,以及所有id为7且日期为2011-07-30的元素,因为其中e等于1时的logret>0。而所有在2011-07-29日期中id为7的元素则被忽略,因为第一个e等于1时的logret<0。

   8 2011-07-29  1    0.0035662770      
   8 2011-07-29  2   -0.0015268474 
   8 2011-07-29  3    0.0013333333
   7 2011-07-30  1    0.0044444444      
   7 2011-07-30  2   -0.0001111111 
   7 2011-07-30  3    0.0013333333    

在 SQL 中,我会使用子查询来实现这一点。 我会:
1) Select the id and date where e=1 and logret > 0
2) Select * join on results of subselect

我认为data.table也可以实现这一点,但我发现用data.table的术语表达起来有些棘手。具体来说,我可以复制步骤1,但无法在步骤2中进行连接。

pos <- DT[e==1][logret > 0]

但是我无法将pos值重新加入到我的DT中。
2个回答

3

虽然不太美观,也不是在data.table中实现的,但是以下代码似乎能够解决问题:

# Recreate your data
df = read.table(header=TRUE, text="id   date    e       logret 
    7 2011-07-29 1   -0.0272275211      
    7 2011-07-29 2    0.0034229025      
    7 2011-07-29 2    0.0042622177      
    8 2011-07-29 1    0.0035662770      
    8 2011-07-29 2   -0.0015268474 
    8 2011-07-29 3    0.0013333333")
df[which(df$id != df$id[which(df$e == 1 & df$logret < 0)]),]
#   id       date e       logret
# 4  8 2011-07-29 1  0.003566277
# 5  8 2011-07-29 2 -0.001526847
# 6  8 2011-07-29 3  0.001333333
#
## Or the equivalent in "positive" terms
#
# df[which(df$id == df$id[which(df$e == 1 & df$logret > 0)]),]

根据评论和新样本数据进行更新

仅凭直觉(我没有任何使用data.table包的经验,它在我的“学习”清单上)。这里有一个可能的解决方案:

temp = split(df, df$date)
lapply(temp, 
       function(x) 
         x[which(x$id == x$id[which(x$e == 1 & x$logret > 0)]),])
# $`2011-07-29`
#   id       date e       logret
# 4  8 2011-07-29 1  0.003566277
# 5  8 2011-07-29 2 -0.001526847
# 6  8 2011-07-29 3  0.001333333
# 
# $`2011-07-30`
#   id       date e        logret
# 7  7 2011-07-30 1  0.0044444444
# 8  7 2011-07-30 2 -0.0001111111
# 9  7 2011-07-30 3  0.0013333333

更新2

值得尝试的方法还包括使用merge

merge(df, df[which(df$e == 1 & df$logret > 0), c(1, 2)])
#   id       date e        logret
# 1  7 2011-07-30 1  0.0044444444
# 2  7 2011-07-30 2 -0.0001111111
# 3  7 2011-07-30 3  0.0013333333
# 4  8 2011-07-29 1  0.0035662770
# 5  8 2011-07-29 2 -0.0015268474
# 6  8 2011-07-29 3  0.0013333333

顺便提一下,上述方法没有考虑按日期分组。例如,如果我有两个具有相同ID的日期,并且一个具有e==1的正回报,另一个具有e==1的负回报,它仍将包括这两个日期。 - user1480926
添加了一些数据,您可以清楚地看到上述解决方案不起作用,因为它只选择ID 8。 - user1480926
@user1480926,如果有时间的话,我会探索 data.table 包,但是我已经为你所指出的限制添加了一个临时可能的解决方案。如果您更喜欢那种格式,也很容易将其放回到单个数据框中。 - A5C1D2H2I1M1N2O1R2T1
感谢 @mrdwab 的帮助。我认为我已经使用 data.table 解决了这个问题(请参见下文)。我从您的解决方案中得到了提示/直觉。 - user1480926

2
我已经以一个迂回的方式解决了它:
pos <- DT[e==1][logret > 0, list(id,date)]
ans <- DT[J(pos$id,pos$date)];

如果 DT 的键值已经是 (id,date),那么可以使用以下一行代码来实现:

DT[, .SD[which.max(value)], by = id]

欢迎分享更多在 data.table 中优雅的一行代码实现。

DT[DT[e==1 & logret>0, list(id,date)]]

而且这样做应该更快。如果您可以确信iddateDT的前两列,那么它可以缩短为:

DT[DT[e==1 & logret>0]]

1
看起来你已经找到了一种高效的方法来做这件事。我猜你已经将iddate设置为你的键值。从这个"反编译"中,我也为你提供了另一个基于R的解决方案(只是为了好玩):merge(df, df[which(df$e == 1 & df$logret > 0), c(1, 2)]) - A5C1D2H2I1M1N2O1R2T1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接