1

グループごとに最初と最後の行を見つける効率的な方法を見つけようとしています。

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);
}

結果:applyAll(ex,c("state","city","code"))しかし、これはの多数のコピーを作成しますDT。私の質問は、グループごとに最初/最後に取得できないような予定または既存のものがあるかどうかです. SAS(これはまたはkdbまたはのかなりバニラですSQL)

SAS

data DT;
    set ex;
    by state city code;
    if first.code then firstcode=1;
    if last.code then lastcode=1;
    if first.city then firstcity=1;
    if last.city then lastcity=1;
    if first.state then firststate=1;
    if last.state then laststate=1;
run;
4

2 に答える 2

5

これが質問の場合:

by="x"一連の列 (x、y、z) について、各グループの最初の項目の位置を示す整数列を追加したいと思いby="x,y"ますby="x,y,z"(3 つの新しい列)。新しい各列の最初の行は、常に最初のグループの最初の項目であるため、常に 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 がコメントしたように、最終的な目標を達成するためのより良い方法がおそらくあります。

そして、要求に応じて、 and を使用したより高速なソリューションは次の.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
}

最初のソリューションとは異なり、グループ化は列ごとに 1 回だけ行われ、多くの小さなベクトルが作成されない (グループごとに呼び出しがない)c()ため、高速になるはずです。rep()

于 2013-01-09T19:23:51.527 に答える
2

何が必要かは完全には明らかではありませんが、インデックスに複数の列を含めることができます。

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
于 2013-01-09T15:02:01.233 に答える