我在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
答案 0 :(得分:5)
这是一个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
答案 1 :(得分:4)
以下是使用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
要获得第二张桌子,请尝试以下方法:
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
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
答案 2 :(得分:3)
您可以使用基本功能执行此操作。使用您的数据
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()
变量
df
indv
sdf <- split(df, df$indv)
接下来,我们转换sdf
的每个组件,以类似于您建议的方式添加val_1
和val_change
变量
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