![](/img/trans.png)
[英]Calculate mean time (H:M) difference from time intervals per day within each group in 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
要處理未分類的數據,例如您在編輯中發布的數據,請嘗試以下操作
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
現在,您可以將上述過程應用於此排序數據框
對數據幀進行排序的一種較簡單的方法是使用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
您甚至可以使用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_1
和val_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.