簡體   English   中英

如何計算R中每組的初始值的差異?

[英]How to calculate difference from initial value for each group in R?

我在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']

編輯:下面發布了兩個優秀的方法,但兩者都依賴於我的時間列進行排序,以便小時間值在高時間值之上。 我不確定我的數據總是如此。 (我知道我可以先在Excel中排序,但我試圖避免這種情況。)當表格顯示如下時,我怎么能處理一個案例:

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

這是一個data.table解決方案,它將在內存中高效,因為它是在data.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

這是使用ddply的plyr解決方案

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

要獲得第二個表,請嘗試以下方法:

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

對數據幀進行排序的一種較簡單的方法是使用doBy包中的sortBy函數

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

您甚至可以使用ddply對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

您可以使用基本功能執行此操作。 使用您的數據

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)

我們首先在indv變量上split() df

sdf <- split(df, df$indv)

接下來,我們以類似於您建議的方式轉換val_1val_change變量中的sdf添加的每個組件

sdf <- lapply(sdf, function(x) transform(x, val_1 = val[1],
                                         val_change = val - val[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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM