7

Rで次のように配置されたデータがあります:

indv    time    val
A          6    5
A         10    10
A         12    7
B          8    4
B         10    3
B         15    9

各個体 ( ) ごとに、初期時からのindv値の変化 ( ) を計算したいと思います。valだから私はこのようなものになるだろう:

indv time   val val_1   val_change
A       6     5    5       0
A      10    10    5       5
A      12     7    5       2
B       8     4    4       0
B      10     3    4      -1
B      15     9    4       5

誰かが私にこれを行う方法を教えてもらえますか? 使うことができます

ddply(df, .(indv), function(x)x[which.min(x$time), ])

のようなテーブルを取得するには

indv    time    val
A          6    5   
B          8    4   

val_1しかし、個人ごとに最小値を合わせた列の作り方がわかりません。ただし、それができれば、val_change次のようなものを使用して列を追加できるはずです。

df['val_change'] = df['val_1'] - df['val']

編集: 2 つの優れた方法が以下に掲載されていますが、どちらも私の時間列が並べ替えられているため、小さな時間値が高い時間値の上に表示されます。これが私のデータに常に当てはまるかどうかはわかりません。(Excel で最初に並べ替えることができることはわかっていますが、それを避けようとしています。) テーブルが次のように表示される場合、どのように対処すればよいでしょうか。

indv    time    value
A          10   10
A           6   5
A          12   7
B           8   4
B          10   3
B          15   9
4

3 に答える 3

5

これは、 data.tabledata.table内で参照によって設定されるため、メモリ効率の高いソリューションです。キーを設定すると、キー変数で並べ替えられます

library(data.table)
DT <- data.table(df)  
# set key to sort by indv then time
setkey(DT, indv, time)
DT[, c('val1','change') := list(val[1], val - val[1]),by = indv]
# And to show it works....
DT
##    indv time val val1 change
## 1:    A    6   5    5      0
## 2:    A   10  10    5      5
## 3:    A   12   7    5      2
## 4:    B    8   4    4      0
## 5:    B   10   3    4     -1
## 6:    B   15   9    4      5
于 2012-11-14T22:21:40.437 に答える
4

これがを使用したplyrソリューションですddply

ddply(df, .(indv), transform, 
      val_1 = val[1],
      change = (val - val[1]))

  indv time val val_1 change
1    A    6   5     5      0
2    A   10  10     5      5
3    A   12   7     5      2
4    B    8   4     4      0
5    B   10   3     4     -1
6    B   15   9     4      5

2番目のテーブルを取得するには、次のことを試してください。

ddply(df, .(indv), function(x) x[which.min(x$time), ])
  indv time val
1    A    6   5
2    B    8   4

編集1

編集で投稿したようなソートされていないデータを処理するには、次のことを試してください

unsort <- read.table(text="indv    time    value
A          10   10
A           6   5
A          12   7
B           8   4
B          10   3
B          15   9", header=T)


do.call(rbind, lapply(split(unsort, unsort$indv), 
                  function(x) x[order(x$time), ]))
    indv time value
A.2    A    6     5
A.1    A   10    10
A.3    A   12     7
B.4    B    8     4
B.5    B   10     3
B.6    B   15     9

これで、上記の手順をこのソートされたデータフレームに適用できます。

編集2

sortByデータフレームを並べ替える簡単な方法は、doByパッケージの関数を使用することです。

library(doBy)
orderBy(~ indv + time, unsort)
  indv time value
2    A    6     5
1    A   10    10
3    A   12     7
4    B    8     4
5    B   10     3
6    B   15     9

編集3

を使用してdfを並べ替えることもできますddply

ddply(unsort, .(indv, time), sort)
  value time indv
1     5    6    A
2    10   10    A
3     7   12    A
4     4    8    B
5     3   10    B
6     9   15    B
于 2012-11-14T21:11:56.327 に答える
4

これは基本関数で行うことができます。あなたのデータを使用して

df <- read.table(text = "indv    time    val
A   6   5
A   10  10
A   12  7
B   8   4
B   10  3
B   15  9", header = TRUE)

最初split() dfindv変数について

sdf <- split(df, df$indv)

次に、あなたが提案する方法と同様の方法で変数と変数をsdf追加する各コンポーネントを変換しますval_1val_change

sdf <- lapply(sdf, function(x) transform(x, val_1 = val[1],
                                         val_change = val - val[1]))

最後に、個々のコンポーネントが行単位で 1 つのデータ フレームにバインドされるようにします。

df <- do.call(rbind, sdf)
df

これにより、次のことが得られます。

R> df
    indv time val val_1 val_change
A.1    A    6   5     5          0
A.2    A   10  10     5          5
A.3    A   12   7     5          2
B.4    B    8   4     4          0
B.5    B   10   3     4         -1
B.6    B   15   9     4          5

編集

OP がコメントで提起する並べ替えの問題に対処するには、lapply()呼び出しを変更して、transform(). 例えば:

sdf <- lapply(sdf, function(x) {
                     x <- x[order(x$time), ]
                     transform(x, val_1 = val[1],
                               val_change = val - val[1])
                   })

使用中

## scramble `df`
df <- df[sample(nrow(df)), ]
## split
sdf <- split(df, df$indv)
## apply sort and transform
sdf <- lapply(sdf, function(x) {
                     x <- x[order(x$time), ]
                     transform(x, val_1 = val[1],
                               val_change = val - val[1])
                   })
## combine
df <- do.call(rbind, sdf)

これも次のようになります。

R> df
    indv time val val_1 val_change
A.1    A    6   5     5          0
A.2    A   10  10     5          5
A.3    A   12   7     5          2
B.4    B    8   4     4          0
B.5    B   10   3     4         -1
B.6    B   15   9     4          5
于 2012-11-14T21:10:05.757 に答える