Optimization 如何更快地对观察结果进行分组?

Optimization 如何更快地对观察结果进行分组?,optimization,r,data.table,dplyr,Optimization,R,Data.table,Dplyr,我有一个非常简单的问题,但我可能没有足够的思考vector-y来有效地解决它。我尝试了两种不同的方法,它们在两台不同的计算机上循环了很长时间。我希望我能说比赛让它更激动人心,但是。。。呜呜 分组观察 我有很长的数据(每个人有很多行,每个人观察一行),我基本上想要一个变量,它告诉我这个人已经被观察了多久 我有前两列,想要第三列: person wave obs pers1 1999 1 pers1 2000 2 pers1 2003 3 pers2 1998

我有一个非常简单的问题,但我可能没有足够的思考vector-y来有效地解决它。我尝试了两种不同的方法,它们在两台不同的计算机上循环了很长时间。我希望我能说比赛让它更激动人心,但是。。。呜呜

分组观察 我有很长的数据(每个人有很多行,每个人观察一行),我基本上想要一个变量,它告诉我这个人已经被观察了多久

我有前两列,想要第三列:

person  wave   obs
pers1   1999   1
pers1   2000   2
pers1   2003   3
pers2   1998   1
pers2   2001   2
现在我使用两种循环方法。两者的速度都非常慢(15万行)。我肯定我遗漏了一些东西,但我的搜索查询并没有真正帮助我(很难用词来表达这个问题)

谢谢你的指点

# ordered dataset by persnr and year of observation
person.obs <- person.obs[order(person.obs$PERSNR,person.obs$wave) , ]

person.obs$n.obs = 0

# first approach: loop through people and assign range
unp = unique(person.obs$PERSNR)
unplength = length(unp)
for(i in 1:unplength) {
   print(unp[i])
   person.obs[which(person.obs$PERSNR==unp[i]),]$n.obs = 
1:length(person.obs[which(person.obs$PERSNR==unp[i]),]$n.obs)
    i=i+1
   gc()
}

# second approach: loop through rows and reset counter at new person
pnr = 0
for(i in 1:length(person.obs[,2])) {
  if(pnr!=person.obs[i,]$PERSNR) { pnr = person.obs[i,]$PERSNR
  e = 0
  }
  e=e+1
  person.obs[i,]$n.obs = e
  i=i+1
  gc()
}
#按个人和观察年份排序的数据集

person.obsby

> foo <-data.frame(person=c(rep("pers1",3),rep("pers2",2)),year=c(1999,2000,2003,1998,2011),obs=c(1,2,3,1,2))
> foo
  person year obs
1  pers1 1999   1
2  pers1 2000   2
3  pers1 2003   3
4  pers2 1998   1
5  pers2 2011   2
> by(foo, foo$person, nrow)
foo$person: pers1
[1] 3
------------------------------------------------------------ 
foo$person: pers2
[1] 2
>foo-foo
人年obs
1 pers1 1999 1
2 pers1 2000 2
3人事1 2003 3
4人事2 1998 1
5个人2 2011 2
>按(foo,foo$人,nrow)
foo$人:pers1
[1] 3
------------------------------------------------------------ 
foo$人:pers2
[1] 2
过去,马雷克的回答被证明非常有用。我把它写下来,几乎每天都用,因为它又快又有效。我们将使用
ave()


使用和包的一些备选方案

数据。表:

library(data.table)
# setDT(foo) is needed to convert to a data.table

# option 1:
setDT(foo)[, rn := rowid(person)]   

# option 2:
setDT(foo)[, rn := 1:.N, by = person]
library(dplyr)
# method 1
foo <- foo %>% group_by(person) %>% mutate(rn = row_number())
# method 2
foo <- foo %>% group_by(person) %>% mutate(rn = 1:n())
两者都给出:

如果你想要一个真正的排名,你应该使用
frank
函数:

setDT(foo)[, rn := frank(year, ties.method = 'dense'), by = person]
dplyr:

library(data.table)
# setDT(foo) is needed to convert to a data.table

# option 1:
setDT(foo)[, rn := rowid(person)]   

# option 2:
setDT(foo)[, rn := 1:.N, by = person]
library(dplyr)
# method 1
foo <- foo %>% group_by(person) %>% mutate(rn = row_number())
# method 2
foo <- foo %>% group_by(person) %>% mutate(rn = 1:n())

在基数R中使用
聚合
排名
的另一个选项:

foo$obs <- unlist(aggregate(.~person, foo, rank)[,2])

 # person year obs
# 1  pers1 1999   1
# 2  pers1 2000   2
# 3  pers1 2003   3
# 4  pers2 1998   1
# 5  pers2 2011   2

foo$obs D'oh我没有说清楚'nough:我需要
obs
列,我没有。我不需要每个人的观察次数,我知道了(用sqldf做的)你在做什么:?@Marek也谢谢你。@Marek-是的!我每周使用该代码段数次,并将其保存在工作中的“有用代码段”文件中。我应该开始复制那些代码片段的源代码。再次感谢。我将相应地更新Q。我想知道这两个问题是否应该合并,因为它们本质上是相同的?4年后的今天,我也是这样做的。啊,那时候我的代码。我使用了一个循环,手动增加循环计数器,并使用了
gc
。哇。@Ruben我认识这个经历;-)@鲁本虽然我不反对,但没有必要接受我的回答。我只是添加了这个答案,因为这个问题经常被用作重复的目标。我认为这是更好的方法。如果我有一段时间没有使用ave代码段,我必须查找它,dplyr方法更快、更地道。
> foo
Source: local data frame [5 x 3]
Groups: person [2]

  person  year    rn
  (fctr) (dbl) (int)
1  pers1  1999     1
2  pers1  2000     2
3  pers1  2003     3
4  pers2  1998     1
5  pers2  2011     2
foo$obs <- unlist(aggregate(.~person, foo, rank)[,2])

 # person year obs
# 1  pers1 1999   1
# 2  pers1 2000   2
# 3  pers1 2003   3
# 4  pers2 1998   1
# 5  pers2 2011   2