Rdata.table計算で前の行の値を使用します


81

ある列の現在の値と別の列の前の値から計算されたdata.tableに新しい列を作成したいと思います。前の行にアクセスすることは可能ですか?

例えば:

> DT <- data.table(A=1:5, B=1:5*10, C=1:5*100)
> DT
   A  B   C
1: 1 10 100
2: 2 20 200
3: 3 30 300
4: 4 40 400
5: 5 50 500
> DT[, D := C + BPreviousRow] # What is the correct code here?

正解は

> DT
   A  B   C   D
1: 1 10 100  NA
2: 2 20 200 210
3: 3 30 300 320
4: 4 40 400 430
5: 5 50 500 540

私は通常私のdata.tablesにキーを設定:DT <- data.table(A=..., key = "A")
PatrickT

回答:


103

shift()実装v1.9.6、これは非常に簡単です。

DT[ , D := C + shift(B, 1L, type="lag")]
# or equivalently, in this case,
DT[ , D := C + shift(B)]

ニュースから:

  1. 新しい関数は、vectorlistdata.frames、またはdata.tablesのshift()高速lead/lagを実装します。「lag」(デフォルト)または「lead」のいずれかである引数を取ります。それは一緒に非常に便利な使い方ができますかを。例:。詳細については、をご覧ください。type:=set()DT[, (cols) := shift(.SD, 1L), by=id]?shift

以前の回答については、履歴を参照してください。


それ.Nは現在の行番号か何かを保持していますか?ここで質問して申し訳ありませんが、ヘルプファイルでそれを見つけることができないようです...
SlowLearner 2013

7
@SlowLearner:curren.Iグループの行の行インデックスを保持する便利な機能もあります。
Steve Lianoglou 2013

7
1 :(。N-1)の代わりにseq_len(.N-1)を使用します。これにより、1:0に関連する問題が回避されます。
mnel 2013

1
.SD例として+ 1-私はaを使おうとしていてlapply、ファンキーな結果を得ていました。これははるかに簡単です。
MichaelChirico 2015

このすべての新しい情報を含む更新されたPDFはどこにありますか?公式の1.9.4ビネットとウェブミナーには含まれていません。また、Rmd 1.9.5ビネットは快適ではなく、含まれていません。
skan 2015

44

dplyrあなたを使用して行うことができます:

mutate(DT, D = lag(B) + C)

それは与える:

#   A  B   C   D
#1: 1 10 100  NA
#2: 2 20 200 210
#3: 3 30 300 320
#4: 4 40 400 430
#5: 5 50 500 540

22

何人かの人々が特定の質問に答えました。このような状況で役立つ可能性のある汎用関数については、以下のコードを参照してください。前の行を取得するだけでなく、「過去」または「将来」の行をいくつでも移動できます。

rowShift <- function(x, shiftLen = 1L) {
  r <- (1L + shiftLen):(length(x) + shiftLen)
  r[r<1] <- NA
  return(x[r])
}

# Create column D by adding column C and the value from the previous row of column B:
DT[, D := C + rowShift(B,-1)]

# Get the Old Faithul eruption length from two events ago, and three events in the future:
as.data.table(faithful)[1:5,list(eruptLengthCurrent=eruptions,
                                 eruptLengthTwoPrior=rowShift(eruptions,-2), 
                                 eruptLengthThreeFuture=rowShift(eruptions,3))]
##   eruptLengthCurrent eruptLengthTwoPrior eruptLengthThreeFuture
##1:              3.600                  NA                  2.283
##2:              1.800                  NA                  4.533
##3:              3.333               3.600                     NA
##4:              2.283               1.800                     NA
##5:              4.533               3.333                     NA

これは素晴らしい答えです。これははるかに一般的な答えであるため、他の答えをすでに賛成していることに腹を立てています。実際、私はそれを私のジェネオラマパッケージで使用するつもりです(あなたが気にしないのであれば)。
Geneorama 2014年

確かに、それのために行きなさい。空き時間をdata.table
確保

と呼ばれる同様の関数がバージョン1.9.5shiftから追加さdata.tableれました。@Arunからの更新された回答を参照してください。
dnlbrky 2015

12

上記の@SteveLianoglouのコメントに基づいて、次のことを行ってください。

DT[, D:= C + c(NA, B[.I - 1]) ]
#    A  B   C   D
# 1: 1 10 100  NA
# 2: 2 20 200 210
# 3: 3 30 300 320
# 4: 4 40 400 430
# 5: 5 50 500 540

また、seq_lenまたはheadまたはその他の機能の使用は避けてください。


2
いいですが、グループ内で前のものを見つけたい場合、これは機能しません。
マシュー

1
@マシューあなたは正しいです。グループによってサブセット化した場合、私は代わる.Iseq_len(.N)
ゲイリー・ワイズマン

9

アルンの解決策に従うと、以下を参照しなくても同様の結果を得ることができます。 .N

> DT[, D := C + c(NA, head(B, -1))][]
   A  B   C   D
1: 1 10 100  NA
2: 2 20 200 210
3: 3 30 300 320
4: 4 40 400 430
5: 5 50 500 540

ある方法を別の方法よりも好む理由はありますか?それとも単に美的な違いですか?
コロネ2013

このシナリオ(つまり、.Nすぐに利用できる場所)では、ほとんどが審美的な選択だと思います。重要な違いはわかりません。
木2013


1

これが私の直感的な解決策です:

#create data frame
df <- data.frame(A=1:5, B=seq(10,50,10), C=seq(100,500, 100))`
#subtract the shift from num rows
shift  <- 1 #in this case the shift is 1
invshift <- nrow(df) - shift
#Now create the new column
df$D <- c(NA, head(df$B, invshift)+tail(df$C, invshift))`

ここinvshiftで、行数から1を引いた数は4です。nrow(df)データフレームまたはベクトルの行数を提供します。同様に、さらに以前の値を取得する場合は、nrow 2、3、...などから減算し、それに応じてNAを先頭に配置します。


-2

それはループで行うことができます。

# Create the column D
DT$D <- 0
# for every row in DT
for (i in 1:length(DT$A)) {
  if(i==1) {
    #using NA at first line
    DT[i,4] <- NA
  } else {
    #D = C + BPreviousRow
    DT[i,4] <- DT[i,3] + DT[(i-1), 2]   
  }
}

forを使用すると、この新しい列の行の以前の値を使用することもできます DT[(i-1), 4]

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.