从数据框中每个分组行的值中减去前一年的值

And*_*rew 5 r

我试图计算无意中聚合的数据的滞后差异(或实际增加).数据中的每个连续年份包括上一年的值.可以使用以下代码创建示例数据集:

set.seed(1234)
x <- data.frame(id=1:5, value=sample(20:30, 5, replace=T), year=3)
y <- data.frame(id=1:5, value=sample(10:19, 5, replace=T), year=2)
z <- data.frame(id=1:5, value=sample(0:9, 5, replace=T), year=1)
(df <- rbind(x, y, z))
Run Code Online (Sandbox Code Playgroud)

我可以使用lapply()split()计算每个唯一ID的每年之间的差异的组合,如下所示:

(diffs <- lapply(split(df, df$id), function(x){-diff(x$value)}))
Run Code Online (Sandbox Code Playgroud)

但是,由于diff()函数的性质,第1年的值没有结果,这意味着在我用diffs列表压缩列表后Reduce(),我无法将实际的年度增量添加回数据框,如下所示:

df$actual <- Reduce(c, diffs)  # flatten the list of lists
Run Code Online (Sandbox Code Playgroud)

在此示例中,只有10个计算差异或滞后,而数据框中有15行,因此在尝试添加新列时R会引发错误.

如何创建一个新的实际增长列,其中(1)第1年的值和(2)所有后续年份的计算差异/滞后?

这是我最终要寻找的输出.我的diffs列表列表计算了第2年和第3年的实际值.

id value year actual
 1    21    3      5
 2    26    3     16
 3    26    3     14
 4    26    3     10
 5    29    3     14
 1    16    2     10
 2    10    2      5
 3    12    2     10
 4    16    2      7
 5    15    2     13
 1     6    1      6
 2     5    1      5
 3     2    1      2
 4     9    1      9
 5     2    1      2
Run Code Online (Sandbox Code Playgroud)

Tyl*_*ker 4

我认为这对你有用。当您遇到 diff 问题时,只需将 0 作为第一个数字来延长向量即可。

df <- df[order(df$id, df$year), ]
sdf <-split(df, df$id)
df$actual <- as.vector(sapply(seq_along(sdf), function(x) diff(c(0, sdf[[x]][,2]))))
df[order(as.numeric(rownames(df))),]
Run Code Online (Sandbox Code Playgroud)

有很多方法可以做到这一点,但是这个方法相当快并且使用基础。

这是利用聚合来解决此问题的第二种和第三种方法:

总计的:

df <- df[order(df$id, df$year), ]
diff2 <- function(x) diff(c(0, x))
df$actual <- c(unlist(t(aggregate(value~id, df, diff2)[, -1])))
df[order(as.numeric(rownames(df))),]
Run Code Online (Sandbox Code Playgroud)

经过:

df <- df[order(df$id, df$year), ]
diff2 <- function(x) diff(c(0, x))
df$actual <- unlist(by(df$value, df$id, diff2))
df[order(as.numeric(rownames(df))),]
Run Code Online (Sandbox Code Playgroud)

普利尔

df <- df[order(df$id, df$year), ]
df <- data.frame(temp=1:nrow(df), df)
library(plyr)
df <- ddply(df, .(id), transform, actual=diff2(value))
df[order(-df$year, df$temp),][, -1]
Run Code Online (Sandbox Code Playgroud)

它为您提供的最终产品:

> df[order(as.numeric(rownames(df))),]
   id value year actual
1   1    21    3      5
2   2    26    3     16
3   3    26    3     14
4   4    26    3     10
5   5    29    3     14
6   1    16    2     10
7   2    10    2      5
8   3    12    2     10
9   4    16    2      7
10  5    15    2     13
11  1     6    1      6
12  2     5    1      5
13  3     2    1      2
14  4     9    1      9
15  5     2    1      2
Run Code Online (Sandbox Code Playgroud)

编辑:避免循环

我可以建议避免循环并将我给您的内容转换为一个函数(by 解决方案对我来说是最容易使用的)并将其应用于您想要的两列。

set.seed(1234)  #make new data with another numeric column
x <- data.frame(id=1:5, value=sample(20:30, 5, replace=T), year=3)
y <- data.frame(id=1:5, value=sample(10:19, 5, replace=T), year=2)
z <- data.frame(id=1:5, value=sample(0:9, 5, replace=T), year=1)
df <- rbind(x, y, z)
df <- df.rep <- data.frame(df[, 1:2], new.var=df[, 2]+sample(1:5, nrow(df), 
          replace=T), year=df[, 3])


df <- df[order(df$id, df$year), ]
diff2 <- function(x) diff(c(0, x))                   #function one
group.diff<- function(x) unlist(by(x, df$id, diff2)) #answer turned function
df <- data.frame(df, sapply(df[, 2:3], group.diff))  #apply group.diff to col 2:3
df[order(as.numeric(rownames(df))),]                 #reorder it
Run Code Online (Sandbox Code Playgroud)

当然,除非您使用以下内容,否则您必须重命名它们transform

df <- df[order(df$id, df$year), ]
diff2 <- function(x) diff(c(0, x))                   #function one
group.diff<- function(x) unlist(by(x, df$id, diff2)) #answer turned function
df <- transform(df, actual=group.diff(value), actual.new=group.diff(new.var))   
df[order(as.numeric(rownames(df))),]
Run Code Online (Sandbox Code Playgroud)

这取决于您执行此操作的变量数量。