如何计算R中各组初始值的差值?

如何计算R中各组初始值的差值?,r,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

我在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
indv    time    value
A          10   10
A           6   5
A          12   7
B           8   4
B          10   3
B          15   9
谁能告诉我怎么做?我可以用

ddply(df, .(indv), function(x)x[which.min(x$time), ])
得到一张像这样的桌子

indv    time    val
A          6    5   
B          8    4   
但是,我不知道如何制作一个列
val_1
,其中每个个体的最小值是匹配的。但是,如果我能做到这一点,我应该能够使用以下方法添加列
val\u change

df['val_change'] = df['val_1'] - df['val']
编辑:下面发布了两个很好的方法,但是都依赖于我的时间列被排序,这样小时间值就位于高时间值之上。我不确定我的数据是否总是这样。(我知道我可以先在Excel中进行排序,但我正在努力避免这种情况。)当表格显示如下时,我如何处理这种情况:

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
indv    time    value
A          10   10
A           6   5
A          12   7
B           8   4
B          10   3
B          15   9

您可以使用基本函数来实现这一点。使用您的数据

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)
接下来,我们将变换
sdf
的每个组件,添加
val_1
val_change
变量,方式与您建议的类似

sdf <- lapply(sdf, function(x) transform(x, val_1 = val[1],
                                         val_change = val - val[1]))
编辑 要解决OP在注释中提出的排序问题,请修改
lappy()
调用以在
transform()之前包含排序步骤。例如:

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

这是一个使用
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(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
要获得第二张桌子,请尝试以下操作:

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
编辑3 您甚至可以使用
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(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

这是一个
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
库(data.table)

亲爱的吉尔伯,非常感谢你的帮助!但是,只有当“时间”列的值从低到高排序时,这才有效。我不确定在我的数据中是否总是这样,尽管我可以先在Excel中对其进行排序(但我尽量避免使用Excel)。如果没有对值进行排序,是否会有一种方法,如下表所示:indv时间值a 10 10 a 6 5 a 12 7 B 8 4 B 10 3 B 15 9亲爱的Jilber,您的编辑似乎很有效,非常感谢!我一整天都在想这个问题!现在我将用我的真实数据来尝试,再次感谢你的帮助!!!很高兴有用。请参阅我的第二次编辑,了解对数据进行排序的较短方法。frame.亲爱的Gavin,感谢您的帮助!这种方法确实适用于我的数据,但是,只有当时间列排序时,第一个值才会出现在后面的值之前。我不确定我的数据是否总是以这种方式排序。有没有类似的方法来处理时间无序的情况,如下表中所示:indv时间值a 10 10 a 6 5 a 12 7 B 8 4 B 10 3 B 15 9然后先排序
val
或按
时间排序
。首先对数据帧进行排序比在差分操作中处理数据帧容易得多。我已经提出了一个解决方案。在将来,它有助于制定完整的问题,以避免延长更新的答案等。希望我对我的问题所做的编辑有帮助吗?亲爱的加文,谢谢。是的,编辑有帮助。很抱歉,我没有完整地阐述这个问题,直到我阅读了答案,我才意识到我的表述有误。下次我会更加小心的@用户7462639用一个可重复的例子作为一个新问题提问
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
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