R “查找第一行/最后一行”;递归地;分组
我试图找到一种有效的方法,按组查找第一行和最后一行R “查找第一行/最后一行”;递归地;分组,r,data.table,R,Data.table,我试图找到一种有效的方法,按组查找第一行和最后一行 R) ex=data.table(state=c("az","fl","fl","fl","fl","fl","oh"),city=c("TU","MI","MI","MI","MI","MI","MI"),code=c(85730,33133,33133,33133,33146,33146,45056)) R) ex state city code 1: az TU 85730 2: fl M
R) ex=data.table(state=c("az","fl","fl","fl","fl","fl","oh"),city=c("TU","MI","MI","MI","MI","MI","MI"),code=c(85730,33133,33133,33133,33146,33146,45056))
R) ex
state city code
1: az TU 85730
2: fl MI 33133
3: fl MI 33133
4: fl MI 33133
5: fl MI 33146
6: fl MI 33146
7: oh MI 45056
我想找出组中每个变量的第一个和最后一个
R) ex
state city code first.state last.state first.city last.city first.code last.code
1: az TU 85730 1 1 1 1 1 1
2: fl MI 33133 1 0 1 0 1 0
3: fl MI 33133 0 0 0 0 0 0
4: fl MI 33133 0 0 0 0 0 1
5: fl MI 33146 0 0 0 0 1 0
6: fl MI 33146 0 1 0 1 0 1
7: oh MI 45056 1 1 1 1 1 1
据我所知,data.table
对于这样的事情很难有帮助,因为by=“state,city,code”
会看到4
三胞胎
我知道的唯一方法是在by=“state,city,code”中查找first/last.code,然后在by=“state,city”中查找first/last.city
这就是我的意思:
applyAll <- function(DT, by){
f<- function(n, vec){ return(vec[1:n]) }
by <- lapply(1:length(by), FUN=f, by)
out <- Reduce(f=firstLast, init=DT, x=by)
return(out)
}
firstLast <- function(DT, by){
addNames <- paste(c("first", "last"),by[length(by)], sep=".")
DT[DT[,list(IDX=.I[1]), by=by]$IDX, addNames[1]:=1]
DT[DT[,list(IDX=.I[.N]), by=by]$IDX, addNames[2]:=1]
return(DT);
}
您想要什么还不完全清楚,但您肯定可以在索引中有多个列:
ex[, list(first=head(code, 1), last=tail(code, 1)), by=c("state", "city")]
state city first last
1: az TU 85730 85730
2: fl MI 33133 33146
3: oh MI 45056 45056
您可以通过以下方式在您的组中自动执行此操作:
by <- c("state", "city", "code")
byList <- lapply(seq_along(by), function(i)by[sequence(i)])
lapply(byList,
function(i) ex[, list(first=head(code, 1), last=tail(code, 1)), by=i] )
[[1]]
state first last
1: az 85730 85730
2: fl 33133 33146
3: oh 45056 45056
[[2]]
state city first last
1: az TU 85730 85730
2: fl MI 33133 33146
3: oh MI 45056 45056
[[3]]
state city code first last
1: az TU 85730 85730 85730
2: fl MI 33133 33133 33133
3: fl MI 33146 33146 33146
4: oh MI 45056 45056 45056
by不完全清楚您想要什么,但您可以在索引中有多个列:
ex[, list(first=head(code, 1), last=tail(code, 1)), by=c("state", "city")]
state city first last
1: az TU 85730 85730
2: fl MI 33133 33146
3: oh MI 45056 45056
您可以通过以下方式在您的组中自动执行此操作:
by <- c("state", "city", "code")
byList <- lapply(seq_along(by), function(i)by[sequence(i)])
lapply(byList,
function(i) ex[, list(first=head(code, 1), last=tail(code, 1)), by=i] )
[[1]]
state first last
1: az 85730 85730
2: fl 33133 33146
3: oh 45056 45056
[[2]]
state city first last
1: az TU 85730 85730
2: fl MI 33133 33146
3: oh MI 45056 45056
[[3]]
state city code first last
1: az TU 85730 85730 85730
2: fl MI 33133 33133 33133
3: fl MI 33146 33146 33146
4: oh MI 45056 45056 45056
如果问题是这样的:
对于一组列(x,y,z),我想添加一个整数列,标记每组第一项的位置by=“x”
,by=“x,y”
和by=“x,y,z”
(三个新列)。每个新列的第一行将始终为1,因为它始终是第一组的第一项。我还想再添加3列,用同样的3个分组分别标记最后一项。不过,我可能不止有3个分组,所以有没有一些程序化的可能呢
那么:
ex=data.table(state=c("az","fl","fl","fl","fl","fl","oh"),
city=c("TU","MI","MI","MI","MI","MI","MI"),
code=c(85730,33133,33133,33133,33146,33146,45056))
ex
state city code
1: az TU 85730
2: fl MI 33133
3: fl MI 33133
4: fl MI 33133
5: fl MI 33146
6: fl MI 33146
7: oh MI 45056
cols = c("state","city","code")
for (i in seq_along(cols)) {
ex[,paste0("f.",cols[i]):=c(1L,rep(0L,.N-1L)),by=eval(head(cols,i))] # first
ex[,paste0("l.",cols[i]):=c(rep(0L,.N-1L),1L),by=eval(head(cols,i))] # last
}
ex
state city code f.state l.state f.city l.city f.code l.code
1: az TU 85730 1 1 1 1 1 1
2: fl MI 33133 1 0 1 0 1 0
3: fl MI 33133 0 0 0 0 0 0
4: fl MI 33133 0 0 0 0 0 1
5: fl MI 33146 0 0 0 0 1 0
6: fl MI 33146 0 1 0 1 0 1
7: oh MI 45056 1 1 1 1 1 1
但正如@Roland所评论的,可能有更好的方法来实现你的最终目标
根据要求,下面是使用.I
和.N
的更快解决方案:
cols = c("state","city","code")
for (i in seq_along(cols)) {
w = ex[,list(f=.I[1],l=.I[.N]),by=eval(head(cols,i))]
ex[,paste0(c("f.","l."),cols[i]):=0L] # add the two 0 columns
ex[w$f,paste0("f.",cols[i]):=1L] # mark the firsts
ex[w$l,paste0("l.",cols[i]):=1L] # mark the lasts
}
它应该更快,因为与第一个解决方案不同,每个列只进行一次分组,并且没有创建大量小向量(每个组不调用c()
或rep()
)。如果这是问题:
对于一组列(x,y,z),我想添加一个整数列,标记每组第一项的位置by=“x”
,by=“x,y”
和by=“x,y,z”
(三个新列)。每个新列的第一行将始终为1,因为它始终是第一组的第一项。我还想再添加3列,用同样的3个分组分别标记最后一项。不过,我可能不止有3个分组,所以有没有一些程序化的可能呢
那么:
ex=data.table(state=c("az","fl","fl","fl","fl","fl","oh"),
city=c("TU","MI","MI","MI","MI","MI","MI"),
code=c(85730,33133,33133,33133,33146,33146,45056))
ex
state city code
1: az TU 85730
2: fl MI 33133
3: fl MI 33133
4: fl MI 33133
5: fl MI 33146
6: fl MI 33146
7: oh MI 45056
cols = c("state","city","code")
for (i in seq_along(cols)) {
ex[,paste0("f.",cols[i]):=c(1L,rep(0L,.N-1L)),by=eval(head(cols,i))] # first
ex[,paste0("l.",cols[i]):=c(rep(0L,.N-1L),1L),by=eval(head(cols,i))] # last
}
ex
state city code f.state l.state f.city l.city f.code l.code
1: az TU 85730 1 1 1 1 1 1
2: fl MI 33133 1 0 1 0 1 0
3: fl MI 33133 0 0 0 0 0 0
4: fl MI 33133 0 0 0 0 0 1
5: fl MI 33146 0 0 0 0 1 0
6: fl MI 33146 0 1 0 1 0 1
7: oh MI 45056 1 1 1 1 1 1
但正如@Roland所评论的,可能有更好的方法来实现你的最终目标
根据要求,下面是使用.I
和.N
的更快解决方案:
cols = c("state","city","code")
for (i in seq_along(cols)) {
w = ex[,list(f=.I[1],l=.I[.N]),by=eval(head(cols,i))]
ex[,paste0(c("f.","l."),cols[i]):=0L] # add the two 0 columns
ex[w$f,paste0("f.",cols[i]):=1L] # mark the firsts
ex[w$l,paste0("l.",cols[i]):=1L] # mark the lasts
}
它应该更快,因为与第一种解决方案不同,每列只进行一次分组,并且没有创建许多小向量(每个组不调用c()
或rep()
),这有什么不对?如果你有N个分组变量,你需要重复“先查找后查找”的指令N次。我很好奇你为什么要这样做。也许有更好的方法来实现你的最终目标。重新审视你的最后一句话,有什么错吗?如果你有N个分组变量,你需要重复“先发现后发现”的指令N次。我很好奇你为什么要这样做。也许有更好的方法来实现你的最终目标。这正是我试图以自动化的方式做的,如果我有一组10人,我宁愿避免写10人lines@Andrie:署名这正是我试图以自动化方式做的事情,如果我有一组10人,我宁愿避免写10人lines@Andrie:署名这看起来不错。我想知道data.table
是否包含类似.I
,.GRP
。。。我想我现在知道了,这本可以帮助更快地实现这一目标。干杯,伙计们。@statquant你们是说这个解决方案很慢,你们想知道它是否能更快?你的英语不是很清楚。听起来你好像不是100%高兴。我仍然在等待你提到的其他语言的“相当普通”的解决方案,它们可以轻松完成这项任务;e、 SQL和SAS(您发布的SAS解决方案是逐列写出的)。慢是相对的,这是迄今为止我见过的最好的,我自己也做不到更快。我想知道它是否可以使用.variables,因为使用它通常是最快的方法,但是你知道的更好。。。关于香草,我认为SAS代码在简单性方面相当不错,不是在代码行数方面,而是在语法方面。关于我的英语,我承认有罪,我想这对我们很多非母语人士来说是很常见的…@statquant好的,谢谢你的澄清,我将使用.variables添加解决方案。但是在SAS语法方面,我想到了你的抱怨:“如果你有N个分组变量,你需要重复先查找然后查找最后N次的指令。”。这看起来就是你在SAS里所做的。在这一点上是有意义的,我真的不想回到所有的评论流。关键是您的解决方案是快速、高效的(没有无用的对象副本)。这就是我想要的,关键是使用.variables来利用数据的内部分组过程。我想知道data.table
是否包含类似.I
,.GRP
。。。我想我现在知道了,这本可以帮助更快地实现这一目标。干杯,伙计们。@statquant你们是说这个解决方案很慢,你们想知道它是否能更快?你的英语不是很清楚。听起来你好像不是100%高兴。我仍然在等待你提到的其他语言的“相当普通”的解决方案,它们可以轻松完成这项任务;e、 SQL和SAS(您发布的SAS解决方案是逐列写出的)。慢是相对的,这是迄今为止我见过的最好的,我自己也做不到更快。我