首页 文章

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

提问于
浏览
5

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

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

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.需要创建单个标识符(快速完成) .
与Stata中的单行代码相比,这似乎是一段繁琐的代码 .
3.在一个中等大小的数据集上(低于100,000个观测数据分组,大约6个),这种方法大约需要1.5个小时 .

有没有效率相当于Stata的 bys var1 var2: keep if _n == 1

2 回答

  • 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, ]
    
  • 10

    dplyr包使这种事情变得更容易 .

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

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

相关问题