R - 保持由多个变量识别的每组的第一次观察(Stata等效“bys var1 var2:keep if _n == 1”)

时间:2014-02-04 12:58:37

标签: r stata

所以我目前在R中遇到一个问题,我确切知道如何处理Stata,但是在R中浪费了两个多小时才完成。

使用下面的data.frame,我想要的结果是准确地获得每组的第一个观察,而组由多个变量组成,并且必须按另一个变量排序,即通过以下方式获得的data.frame mydata: / p>

id <- c(1,1,1,1,2,2,3,3,4,4,4)
day <- c(1,1,2,3,1,2,2,3,1,2,3)
value <- c(12,10,15,20,40,30,22,24,11,11,12)
mydata <- data.frame(id, day, value)

应该转变为:

   id day value   
   1   1    10 
   1   2    15 
   1   3    20 
   2   1    40 
   2   2    30 
   3   2    22 
   3   3    24 
   4   1    11 
   4   2    11 
   4   3    12 

通过仅保留其中一个行包含一个或多个重复的组标识符(此处仅为row[1]: (id,day)=(1,1)),首先排序值(以便保留具有最低值的行)。

在Stata中,这只是:

bys id day (value): keep if _n == 1

我找到了一个piece of code on the web,如果我首先生成一个组标识符,它就会正确地执行此操作:

mydata$id1 <- paste(mydata$id,"000",mydata$day, sep="")  ### the single group identifier

myid.uni <- unique(mydata$id1)
a<-length(myid.uni)

last <- c()

for (i in 1:a) {
  temp<-subset(mydata, id1==myid.uni[i])
  if (dim(temp)[1] > 1) {
    last.temp<-temp[dim(temp)[1],]
  }
  else {
    last.temp<-temp
  }
  last<-rbind(last, last.temp)
}

last

然而,这种方法存在一些问题:
1.需要创建单个标识符(快速完成) 2.与Stata中的单行代码相比,这似乎是一段繁琐的代码 3.在一个中等大小的数据集上(低于100,000个观测数据分组,大约6个),这种方法大约需要1.5小时。

是否有效的等效于Stata的bys var1 var2: keep if _n == 1

3 个答案:

答案 0 :(得分:10)

dplyr软件包使这种事情变得更容易。

library(dplyr)
mydata %>% group_by(id, day) %>% filter(row_number(value) == 1)

此命令在R中需要的内存多于在Stata中的内存:不会抑制行,而是创建数据集的新副本。

答案 1 :(得分:5)

我会订购data.frame,您可以使用by来查看:

mydata <- mydata[with(mydata, do.call(order, list(id, day, value))), ]

do.call(rbind, by(mydata, list(mydata$id, mydata$day), 
                  FUN=function(x) head(x, 1)))

或者,查看“data.table”包。继续上面的订购data.frame

library(data.table)

DT <- data.table(mydata, key = "id,day")
DT[, head(.SD, 1), by = key(DT)]
#     id day value
#  1:  1   1    10
#  2:  1   2    15
#  3:  1   3    20
#  4:  2   1    40
#  5:  2   2    30
#  6:  3   2    22
#  7:  3   3    24
#  8:  4   1    11
#  9:  4   2    11
# 10:  4   3    12

或者,从头开始,您可以通过以下方式使用data.table

DT <- data.table(id, day, value, key = "id,day")
DT[, n := rank(value, ties.method="first"), by = key(DT)][n == 1]

并且,通过扩展,在基础R:

Ranks <- with(mydata, ave(value, id, day, FUN = function(x) 
  rank(x, ties.method="first")))
mydata[Ranks == 1, ]

答案 2 :(得分:0)

使用 data.table ,假设mydata对象已经按照您要求的方式进行了排序,另一种方法是:

library(data.table)
mydata <- data.table(my.data)
mydata <- mydata[, .SD[1], by = .(id, day)]

dplyr magrittr 管道一起使用:

library(dplyr)
mydata <- mydata %>%
  group_by(id, day) %>%
  slice(1) %>%
  ungroup()

如果您不将ungroup()添加到末尾,则 dplyr 的分组结构仍然存在,并且可能会弄乱您的某些后续功能。