我正在尝试计算无意中聚合的数据的滞后差异(或实际增长)。数据中的每个连续年份都包含前一年的值。可以使用以下代码创建样本数据集:
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))我可以使用lapply()和split()的组合来计算每个唯一id的每年之间的差异,如下所示:
(diffs <- lapply(split(df, df$id), function(x){-diff(x$value)}))但是,由于diff()函数的性质,第1年的值没有结果,这意味着在我用Reduce()展平列表的diffs列表后,我不能将实际的年增量添加回数据框中,如下所示:
df$actual <- Reduce(c, diffs) # flatten the list of lists在本例中,只有10个计算出的差异或滞后,而数据框中有15行,因此R在尝试添加新列时会抛出错误。
如何使用(1)第1年的值和(2)计算出的所有后续年份的差异/滞后来创建实际增长的新列?
这就是我最终要找的输出。我的diffs列表可以很好地计算出第二年和第三年的实际值。
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发布于 2012-03-04 14:50:15
我想这对你会有用的。当你遇到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))),]有很多方法可以做到这一点,但这一种方法相当快,并且使用了base。
这里有第二和第三种方法来解决这个问题,利用聚合和:
聚合:
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))),]作者:
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))),]plyr
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]它为您提供了以下内容的最终产品:
> 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循环编辑:避免循环
我建议避免这个循环,把我给你的东西变成一个函数( 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当然,您必须重命名它们,除非您使用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))),]这将取决于您对多少个变量执行此操作。
发布于 2012-03-05 01:28:54
1) diff.zoo。使用zoo包,只需使用split=将其转换为zoo,然后执行diff:
library(zoo)
zz <- zz0 <- read.zoo(df, split = "id", index = "year", FUN = identity)
zz[2:3, ] <- diff(zz)它提供了以下内容(以宽形式,而不是您提到的长形式),其中每列是一个id,每行是一年减去前一年:
> zz
1 2 3 4 5
1 6 5 2 9 2
2 10 5 10 7 13
3 5 16 14 10 14显示的宽表单实际上可能更可取,但如果您希望这样做,则可以将其转换为长表单:
dt <- function(x) as.data.frame.table(t(x))
setNames(cbind(dt(zz), dt(zz0)[3]), c("id", "year", "value", "actual"))这使年份按升序排列,这是R中通常使用的约定。
2)滚动应用。同样使用zoo,这个替代方案使用滚动计算将实际列添加到数据中。它假设数据的结构如您所示,每个组中的年数按顺序排列:
df$actual <- rollapply(df$value, 6, partial = TRUE, align = "left",
FUN = function(x) if (length(x) < 6) x[1] else x[1]-x[6])3)减去。假设与前面的解决方案相同,我们可以将其进一步简化为从每个值中减去5个位置的值:
transform(df, actual = value - c(tail(value, -5), rep(0, 5)))或者这个变体:
transform(df, actual = replace(value, year > 1, -diff(ts(value), 5)))编辑:添加了rollapply和减法解决方案。
发布于 2012-03-04 15:14:33
你可以在0年的df中添加模拟行,这有点老土,但你可以保留你精彩的Reduce:
mockRows <- data.frame(id = 1:5, value = 0, year = 0)
(df <- rbind(df, mockRows))
(df <- df[order(df$id, df$year), ])
(diffs <- lapply(split(df, df$id), function(x){diff(x$value)}))
(df <- df[df$year != 0,])
(df$actual <- Reduce(c, diffs)) # flatten the list of lists
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 2https://stackoverflow.com/questions/9552771
复制相似问题