在R中选择具有特定条件的行

5

我目前有多个ID的数据,其格式如下(ID数量约为1600)

id  year    name    status
1   1980    James   3
1   1981    James   3
1   1982    James   3
1   1983    James   4
1   1984    James   4
1   1985    James   1
1   1986    James   1
1   1987    James   1
2   1982    John    2
2   1983    John    2
2   1984    John    1
2   1985    John    1

我希望将这些数据进行子集处理,只保留状态为1以及其之前的状态信息。同时,我想要去除多个1,并且只保留第一个1。最终,我需要得到:

id  year    name    status
1   1984    James   4
1   1985    James   1
2   1983    John    2
2   1984    John    1

我正在研究某年份有多少来自特定状态的人转换为状态1,因此需要进行翻译。我只知道subset命令,但是我认为无法通过执行subset(data, subset=(status==1))来获取这些数据。在那之前,我该如何保存信息呢?
我想再次补充一下这个问题 - 当我使用第一个回答(使用plr包)和第三个回答(使用duplicated命令)时,我没有得到相同的结果。我发现第一个回答准确地保留了信息,而第三个回答没有。
4个回答

4
这可以满足你的需求。
library(plyr)

ddply(d, .(name), function(x) {
  i <- match(1, x$status)
  if (is.na(i))
    NULL
  else
    x[c(i-1, i), ]
})

  id year  name status
1  1 1984 James      4
2  1 1985 James      1
3  2 1983  John      2
4  2 1984  John      1

1
+1并为编辑失败道歉,我将其作为评论留在此处:您可以使用match(1, x$status)代替which(x$status == 1)[1] - flodel
@flodel 是的,这样更好,谢谢!我应该经常使用 match - Mark Heckmann
根据@flodel的建议进行了更改。 - Mark Heckmann
@MarkHeckmann 我有一个问题 - 我可以使用相同的方法在状态为1之前通过c(i-5)保存五个条目吗?还是这只会保存五年前的信息,然后变成1? - halo09876
顺便说一句,谢谢你的答案,它像魔法一样起作用了! - halo09876
显示剩余3条评论

4
这里有一个解决方案-针对每一组数字(即cumsum部分),它查看第一个数字并取出前一行,如果状态为1:
library(data.table)
dt = data.table(your_df)

dt[dt[, if(status[1] == 1) c(.I[1]-1, .I[1]),
        by = cumsum(c(0,diff(status)!=0))]$V1]
#   id year  name status
#1:  1 1984 James      4
#2:  1 1985 James      1
#3:  2 1983  John      2
#4:  2 1984  John      1

2
使用基础 R,以下是实现此操作的方法:
# this first line is how I imported your data after highlighting and copying (i.e. ctrl+c)
d<-read.table("clipboard",header=T)

# find entries where the subsequent row's "status" is equal to 1
# really what's going on is finding rows where "status" = 1, then subtracting 1  
# to find the index of the previous row
e<-d[which(d$status==1)-1 ,]
# be careful if your first "status" entry = 1...

# What you want
# Here R will look for entries where "name" and "status" are both repeats of a 
# previous row and where "status" = 1, and it will get rid of those entries
e[!(duplicated(e[,c("name","status")]) & e$status==1),]

   id year  name status
 5  1 1984 James      4
 6  1 1985 James      1
10  2 1983  John      2
11  2 1984  John      1

1
对于Mac用户,根据https://dev59.com/T2Yr5IYBdhLWcg3wvslA,使用`x <- read.delim(pipe("pbpaste"))`来读取剪贴板中的数据。 - kdauria

0

我个人喜欢使用 data.table 解决方案,但实际上也有一种使用 subset 的方法。

# import data from clipboard
x = read.table(pipe("pbpaste"),header=TRUE)

# Get the result table that you want
x1 = subset(x, status==1 | 
               c(status[-1],0)==1 )
result = subset(x1, !duplicated(cbind(name,status)) )

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