按多个条件进行子集筛选

7
也许这是一些基础的东西,但我找不到答案。
我有一个...
Id Year V1  
 1 2009 33   
 1 2010 67  
 1 2011 38  
 2 2009 45  
 3 2009 65  
 3 2010 74  
 4 2009 47  
 4 2010 51  
 4 2011 14

我需要选择仅在三年2009、2010和2011具有相同Id的行。

Id Year V1  
 1 2009 33  
 1 2010 67  
 1 2011 38  
 4 2009 47  
 4 2010 51  
 4 2011 14   

我尝试

d1_3 <- subset(d1, Year==2009 |Year==2010 |Year==2011 )

但它无法正常工作。

有人能提供一些建议吗,我该如何在R中实现这个功能?


在 SO 上发布一个最小示例、期望的输出和你尝试过的代码,会得到 +1 的赞哦! - Henrik
1
我想你在写'ANNO'时是不是想说'Year'? - Henrik
没错!这是因为原始数据库来自西班牙,所以我们用“año” = ANNO来代替“ñ”,以便在R中使用,但其含义是年。再次感谢。 - Tappin73
4个回答

4
我认为在这里可以使用 ave 。我将您的原始数据框命名为'df'。对于每个Id,检查Year中是否存在2009-2011( 2009:2011%in%x )。这会生成一个逻辑向量,可以用 sum 求和。测试和是否等于3(如果所有年份都存在,则总和为3),这将导致一个新的逻辑向量,该向量用于子集化数据框的行。
df[ave(df$Year, df$Id, FUN = function(x) sum(2009:2011 %in% x) == 3, ]
#   Id Year V1
# 1  1 2009 33
# 2  1 2010 67
# 3  1 2011 38
# 7  4 2009 47
# 8  4 2010 51
# 9  4 2011 14

+1 非常感谢!看起来运行良好。选择具有年份的观察结果。 - Tappin73
@Tappin73,请注意我将 x %in% 2009:2011 改为了 2009:2011 %in% x。可以比较一下 c(2009, 2009, 2009) %in% 2009:20112009:2011 %in% c(2009, 2009, 2009) - Henrik
@Henrik:你的更改不应该有任何影响,因为在任何情况下,你仍然会得到精确的3作为总和。 - CHP
1
@ChinmayPatil,感谢您的评论!sum(c(2009, 2009, 2009) %in% 2009:2011)是3,尽管并非所有年份都被表示出来。这就是为什么我交换了它们的原因。 - Henrik

2
这应该可以完成工作 :)
library(plyr)
ds<-ddply(ds,.(Id),mutate,Nobs=length(Year))
ds[ds$Nobs == 3 & ds$Year %in% 2009:2011,]

谢谢你的回答!但是这并没有解决问题。它继续选择只有一两年数据的一些观测值。我想要选择所有在调查中包含所有年份(2009年、2010年和2011年)的观测值。 - Tappin73
抱歉,在发布答案后我发现了错误。我使用了plyr包发布了可行的答案。但是如果您想使用标准的R函数,请参考@Henrik的答案。 - Maciej
如果一个ID出现在2009年、2010年或2011年以外的其他年份,这段代码将无法返回结果。 - CHP
但问题涉及2009年至2011年的年份,所以我认为在这种情况下它会起作用。 - Maciej

2

使用 ave 的另一种方法

DF
##   Id Year V1
## 1  1 2009 33
## 2  1 2010 67
## 3  1 2011 38
## 4  2 2009 45
## 5  3 2009 65
## 6  3 2010 74
## 7  4 2009 47
## 8  4 2010 51
## 9  4 2011 14


DF[ave(DF$Year, DF$Id, FUN = function(x) all(2009:2011 %in% x)) == 1, ]
##   Id Year V1
## 1  1 2009 33
## 2  1 2010 67
## 3  1 2011 38
## 7  4 2009 47
## 8  4 2010 51
## 9  4 2011 14

1
我认为使用ave方法是合理的。但解决这个问题有很多方法。我展示了一些使用基础 R 的其他方法。然后在最后两个例子中,我将介绍data.table包。
再次强调,提供这些选项只是为了使用语言的不同方面。
d1 <- data.frame(ID=c(1,1,1,2,3,3,4,4,4), Year=c(2009,2010,2011, 2009,2009, 2010, 2009, 2010, 2011), V1=c(33, 67, 38, 45, 65, 74, 47, 51, 14))


# long way
use_years <- as.character(2009:2011)
cnts <- table(d1[,c("ID","Year")])[,use_years]
use_id <- rownames(cnts)[rowSums(cnts)==length(use_years)]
d1[d1[,"ID"]%in%use_id,]
# 1  1 2009 33
# 2  1 2010 67
# 3  1 2011 38
# 7  4 2009 47
# 8  4 2010 51
# 9  4 2011 14

# another longish way
ind1 <- d1[,"Year"]%in%2009:2011
d1_ind <- d1[ind1,"ID"]
ind2 <- d1_ind %in% unique(d1_ind)[tabulate(d1_ind)==3]
d1[ind1,][ind2,]
#   ID Year V1
# 1  1 2009 33
# 2  1 2010 67
# 3  1 2011 38
# 7  4 2009 47
# 8  4 2010 51
# 9  4 2011 14

好的,让我们尝试一下使用data.table的几种方法。这是我所有时间最喜欢的包之一。虽然一开始可能有点棘手,但请确保您的靴子穿得紧(哦,是的,它很快!):)

# medium way
library(data.table)
d2 <- as.data.table(d1)

d2[ID%in%d2[Year%in%2009:2011, list(logic=nrow(.SD)==3),by="ID"][(logic),ID]]
#    ID Year V1
# 1:  1 2009 33
# 2:  1 2010 67
# 3:  1 2011 38
# 4:  4 2009 47
# 5:  4 2010 51
# 6:  4 2011 14


# short way
d2[Year%in%2009:2011][ID%in%unique(ID)[table(ID)==3]]
#    ID Year V1
# 1:  1 2009 33
# 2:  1 2010 67
# 3:  1 2011 38
# 4:  4 2009 47
# 5:  4 2010 51
# 6:  4 2011 14

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