在具有多个逻辑条件的组中求和,同时省略sum R data.table中的值

时间:2014-08-26 23:25:58

标签: r sum data.table multiple-conditions

我无法弄清楚如何在data.table中对行进行求和,同时省略过程中某个组的值。

我们说我有data.table以下表格:

library(data.table)
dt <- data.table(year = c(2000, 2001, 2002, 2003, 2000, 2001, 2002, 2003, 2000, 2001, 2002, 2003, 2000, 2001, 2002, 2003), 
               name = c("Tom", "Tom", "Tom", "Tom", "Fred", "Fred", "Fred", "Fred", "Gill", "Gill", "Gill", "Gill", "Ann", "Ann", "Ann", "Ann"),
               g1 = c(1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1),
               g2 = c(1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1),
               g3 = c(1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1),
               g4 = c(0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1))

setkey(dt, name, year)

其中g1 - g4name中的玩家参与year的游戏的指标变量。

我想要做的是计算每个游戏NPg1 - NPg4的玩家数量,其中两个玩家都参加了焦点游戏,但前提是他们还在另一个游戏中互相对战在同一年的游戏中,此总和应排除正在计算的玩家。

我使用从how to cumulatively add values in one vector in R修改的代码,例如NPg1

来接近
dtg1 <- dt[,.SD[(g1==1) & (g2==1 | g3==1 | g4==1)][, NPg1:= sum(g1)], by=year]

这会根据我的条件对dt进行子集并创建总和,但总和包括焦点玩家。例如,NPg1中的year==2000对于Tom来说是1,但它应该是0,因为即使他在g1中玩,他也没有在那一年的另一个游戏中玩另一个玩家。一旦我得到了正确的金额,我就可以为每个游戏执行此操作并将结果合并回data.table。主要问题是,如何才能得到这些条件的正确总和。

NPg1的结果应如下所示

dtg1$NPg1result <- c(0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3)

非常感谢任何想法。

在@ Mike.Gahan的评论之后:

这是g1的子结果,也许这不会在我的帖子中变得非常清晰。一旦我有了正确的信息,我就可以轻松地将其加回到完整的data.table使用:

library(plyr)
dt <- join(dt, dtg1)

或其他合并/加入操作,但由于我的问题主要与子结果有关,所以我不想打扰所有人。

在@ Ricardo Saportas解决方案后编辑

所有游戏的完整预期结果如下:

dtresult <- data.table(year = c(2000, 2001, 2002, 2003, 2000, 2001, 2002, 2003, 2000, 2001, 2002, 2003, 2000, 2001, 2002, 2003), 
                   name = c("Ann", "Ann", "Ann", "Ann", "Fred", "Fred", "Fred", "Fred", "Gill", "Gill", "Gill", "Gill", "Tom", "Tom", "Tom", "Tom"), 
                   NPg1 = c(0, 1, 3, 3, 0, 0, 3, 3, 0, 0, 3, 3, 0, 1, 3, 3), 
                   NPg2 = c(0, 0, 2, 3, 0, 0, 2, 3, 1, 0, 0, 3, 1, 0, 2, 3), 
                   NPg3 = c(0, 0, 3, 2, 0, 2, 3, 0, 1, 2, 3, 2, 1, 2, 3, 2), 
                   NPg4 = c(0, 0, 2, 2, 0, 1, 0, 0, 0, 1, 2, 2, 0, 0, 2, 2))

1 个答案:

答案 0 :(得分:2)

一种方法是在year-g1-g2-..-gn组合上进行笛卡尔联接。

然后在新表上,你可以忽略行&#34;不符合条件的 [见底部注释] - 即玩家对抗自己,以及只玩一场比赛的玩家组合。

setkeyv(dt, c("year", games))
dt.merged <- merge(dt, dt, all=TRUE, allow.cartesian=TRUE, suffixes=c("", ".y"))
## ignore players playing against themselves
dt.merged[name != name.y, (games) := 0 ]
## ignore player combinations that only shared one game
dt.merged[ (rowSums(dt.merged[, games, with=FALSE]) <= 1) , (games) := 0 ]
## now just sum itup
results <- dt.merged[, lapply(.SD, sum), keyby=list(year, name), .SDcols=games]
## clean up the names
setnames(results, games, paste0("NP", games))

哪个收益

results

    year name g1 g2 g3 g4
 1: 2000  Ann  0  0  0  0
 2: 2000 Fred  0  0  0  0
 3: 2000 Gill  0  1  1  1
 4: 2000  Tom  1  1  1  0
 5: 2001  Ann  1  1  0  0
 6: 2001 Fred  0  0  1  1
 7: 2001 Gill  0  0  1  1
 8: 2001  Tom  1  0  1  0
 9: 2002  Ann  1  1  1  1
10: 2002 Fred  1  1  1  0
11: 2002 Gill  1  0  1  1
12: 2002  Tom  1  1  1  1
13: 2003  Ann  1  1  1  1
14: 2003 Fred  1  1  0  0
15: 2003 Gill  1  1  1  1
16: 2003  Tom  1  1  1  1

请注意,您有两个选项可以&#34;忽略行&#34;

如果你想保留&#34; 0&#34;计算年度玩家,然后使用

dt.merged[ <filter>,  (games) := 0 ]

如果你不关心&#34; 0&#34;计算年度玩家,然后使用

dt.merged <- dt.merged[ ! <filter> ]