我有一个数据框,其中包含与不同事件得分相关的数据。一场比赛可以有很多得分事件。我想做的是分数高于5或低于-5的情况。我还希望得到每个ID的最后一行。因此,对于每个ID,我将有一行或多行,具体取决于分数是高于5还是低于-5。我的实际数据集包含许多其他信息列,但如果我学会了如何执行此操作,那么我将能够将其应用于我可能想要做的任何其他事情。
这是一个数据集
ID Score Time
1 0 0
1 3 5
1 -2 9
1 -4 17
1 -7 31
1 -1 43
2 0 0
2 -3 15
2 0 19
2 4 25
2 6 29
2 9 33
2 3 37
3 0 0
3 5 3
3 2 11
所以对于这个数据集,我希望得到这个输出:
ID Score Time
1 -7 31
1 -1 43
2 6 29
2 9 33
2 3 37
3 2 11
所以至少,对于每个ID,将会有一行打印出该ID的最后得分,无论在事件期间得分是高于5还是低于-5(这发生在ID 3中)。
我的尝试可以在值高于5或低于-5时进行分组,我只是不知道如何编写代码来获取每个ID的最后一行:
Data[Data$Score > 5 | Data$Score < -5]
如果您需要更多信息,请与我们联系。
答案 0 :(得分:3)
以下是 data.table 中的内容,其中df
是您的原始数据框。
library(data.table)
setDT(df)
df[df[, c(.I[!between(Score, -5, 5)], .I[.N]), by = ID]$V1]
# ID Score Time
# 1: 1 -7 31
# 2: 1 -1 43
# 3: 2 6 29
# 4: 2 9 33
# 5: 2 3 37
# 6: 3 2 11
我们按ID
进行分组。 between
函数找到介于-5和5之间的值,我们否定它以获得超出该范围的所需值。然后,我们使用.I
子集来获取每组的索引。然后.I[.N]
为我们提供每组最后一个条目的行号。我们使用该结果的V1
列作为整个表的行子集。如果需要唯一行,则可以采用唯一值。
注意: .I[c(which(!between(Score, -5, 5)), .N)]
也可以在第一个操作的j
条目中使用。不确定它是否效率更高或更低。
添加:另一种方法,即仅使用逻辑值并且永远不会在输出中产生重复行的方法
df[df[, .I == .I[.N] | !between(Score, -5, 5), by = ID]$V1]
# ID Score Time
# 1: 1 -7 31
# 2: 1 -1 43
# 3: 2 6 29
# 4: 2 9 33
# 5: 2 3 37
# 6: 3 2 11
答案 1 :(得分:3)
您可以使用rle
获取每个ID的最后一行。查看?rle
以获取有关此有用功能的更多信息。
Data2 <- Data[cumsum(rle(Data$ID)$lengths), ]
Data2
# ID Score Time
#6 1 -1 43
#13 2 3 37
#16 3 2 11
要结合这两个条件,请使用rbind
。
Data2 <- rbind(Data[Data$Score > 5 | Data$Score < -5, ], Data[cumsum(rle(Data$ID)$lengths), ])
要删除满足这两个条件的行,您可以使用duplicated
和rownames
。
Data2 <- Data2[!duplicated(rownames(Data2)), ]
当然,您也可以根据需要进行排序。
答案 2 :(得分:2)
这是另一个基础R解决方案。
df[as.logical(ave(df$Score, df$ID,
FUN=function(i) abs(i) > 5 | seq_along(i) == length(i))), ]
ID Score Time
5 1 -7 31
6 1 -1 43
11 2 6 29
12 2 9 33
13 2 3 37
16 3 2 11
abs(i) > 5 | seq_along(i) == length(i)
构造一个逻辑向量,为符合条件的每个元素返回TRUE。 ave
将此函数应用于每个ID。生成的逻辑向量用于选择data.frame的行。
答案 3 :(得分:0)
这是一个tidyverse
解决方案。不像上面的内容那么简洁,但是更容易理解。
library(tidyverse)
lastrows <- Data %>% group_by(ID) %>% top_n(1, Time)
scorerows <- Data %>% group_by(ID) %>% filter(!between(Score, -5, 5))
bind_rows(scorerows, lastrows) %>% arrange(ID, Time) %>% unique()
# A tibble: 6 x 3
# Groups: ID [3]
# ID Score Time
# <int> <int> <int>
# 1 1 -7 31
# 2 1 -1 43
# 3 2 6 29
# 4 2 9 33
# 5 2 3 37
# 6 3 2 11