R:计算具有案例和观察的数据帧中从一个观察到下一个观察值的变化

时间:2014-02-28 01:00:33

标签: r dataframe

您好我是R的新手,我在完成应该是一项相当简单的任务时遇到了麻烦。我确信有一个简单的解决方案,但我无法在线找到它(包括在StackOverflow上)

我的数据框有CasesObservations和变量AmountCases是因子,observations是整数,它们一起构成一个索引,以便包含Case = 3和Observation = 4的行对应于第4次观察第三种情况,包含Case = 4和Observation = 1的行对应于第四种情况的第一次观察。

我正在尝试编写一个脚本来计算每个案例中一个观察值到同一个案例中下一个观察值的金额变化,然后将该差异存储在与第一个案例相关联的行的数据框中的新列中这两个观察。因此,当我完成后,新列将包含从当前行观察到同一情况下的下一个观察的量的变化。

数据框的格式为:

case <- c(1,2,3,4,5,6,1,2,3,4,5,6,1,2,3,4)
obs <- c(rep(1,6),rep(2,6),rep(3,4))
amount <- c(0,2,12,1,0,20,1,2,22,2,1,50,5,2,100,28)
d.example <- data.frame(case,obs,amount)
d.example$case <- as.factor(d.example$case)
case obs Amount 
1    1   0
2    1   2 
3    1   12
4    1   1
5    1   0 
6    1   20
1    2   1
2    2   2
3    2   22
4    2   2
5    2   1
6    2   50
1    3   5
2    3   2
3    3   100
4    3   28

注意:数据不均衡,每个案例可以有不同的观察次数

结果应该是(现在我将-1放入NA)

case obs Amount deltaAmount
1    1   0      1
2    1   2      0
3    1   12     10
4    1   1      1
5    1   0      1
6    1   20     30
1    2   1      4
2    2   2      0
3    2   22     78
4    2   2      26
5    2   1      -1
6    2   50     -1
1    3   5      -1
2    3   2      -1
3    3   100    -1
4    3   28     -1

我一直在尝试使用嵌套for循环

deltaAmount <- NULL
deltaAmount <- rep(-1, length(d$Case))
d$deltaAmount <- deltaAmount

x <- NULL
y <- NULL


for( i in unique(d$Case)) {   # i is the case index
    x <- NULL
# set x equal to a vector containing all the observations for the ith case except the first observation 
    x <- subset( unique(d$Observation[which(d$Case == i)]), unique( d$Observation[which(d$Case == i)]) > 1)

    for( j in x ) { # j is the observation index (starts at 2 to avoid the error that would occur if we subtract a preceeding obsevation from the first observation)

        d$AmountRaised[which(d$Case == i) & which(d$Observation == j)] - d$AmountRaised[which(d$Case == i) & which(d$Observation == j-1)] -> y
        y -> d$deltaAmount[which( d$Case == i & d$Observation == j-1 )] 

    }
}

当我运行此命令时需要很长时间才能运行。几乎就好像它被卡在一个无限循环中(我还没有运行它完成)当我终止程序时R表示我有超过50条警告信息。它们都是

形式

1: In which(d$Case == i) & which(d$Observation == j) : longer object length is not a multiple of shorter object length

但是,已创建附加列,并且已将多个值从-1更改为0

我的数据框很大(770000行)。

一旦我开始工作,我将需要做同样的事情,除了使用difftime()的日期。我意识到我可能会以错误的方式解决这个问题(也就是说,如果不使用嵌套的for循环,可能有更好的方法),但请记住,如果你建议一个日期,我需要区分日期。不同的方法。

很抱歉提出这么长的问题,我希望我能说清楚一切。

提前谢谢你的帮助。

2 个答案:

答案 0 :(得分:3)

这就是为plyr(和dplyr)构建的情况 - split / apply / combine。您可以使用diff()来获取行之间的差异。正如评论中指出的那样,diff()依赖于订单,所以只有在订购合适时才会有效:

使用dplyr:

library(dplyr)
d.example %.%
  group_by(case) %.%
  mutate(deltaAmount = c(diff(amount), NA))

#    case obs amount deltaAmount
# 1     1   1      0           1
# 2     2   1      2           0
# 3     3   1     12          10
# 4     4   1      1           1
# 5     5   1      0           1
# 6     6   1     20          30
# 7     1   2      1           4
# 8     2   2      2           0
# 9     3   2     22          78
# 10    4   2      2          26
# 11    5   2      1          NA
# 12    6   2     50          NA
# 13    1   3      5          NA
# 14    2   3      2          NA
# 15    3   3    100          NA
# 16    4   3     28          NA

和plyr:

library(plyr)
d.out <- ddply(d.example, .(case), mutate, 
               deltaAmount = c(diff(amount), NA))
d.out
#    case obs amount deltaAmount
# 1     1   1      0           1
# 2     1   2      1           4
# 3     1   3      5          NA
# 4     2   1      2           0
# 5     2   2      2           0
# 6     2   3      2          NA
# 7     3   1     12          10
# 8     3   2     22          78
# 9     3   3    100          NA
# 10    4   1      1           1
# 11    4   2      2          26
# 12    4   3     28          NA
# 13    5   1      0           1
# 14    5   2      1          NA
# 15    6   1     20          30
# 16    6   2     50          NA

答案 1 :(得分:3)

假设数据按obs排序(很容易做到),这里是基础R中的实现:

d.example$case.delta <- 
  with(d.example, ave(amount, case, FUN=function(x) c(diff(x), NA)))

ave函数将amount向量分解为case,然后对于每个组使用diff函数(稍微修改,如您所见)。这产生(为了清楚起见,按个案排序):

with(d.example, d.example[order(case, obs), ])
#    case obs amount case.delta
# 1     1   1      0          1
# 7     1   2      1          4
# 13    1   3      5         NA
# 2     2   1      2          0
# 8     2   2      2          0
# 14    2   3      2         NA
# 3     3   1     12         10
# 9     3   2     22         78
# 15    3   3    100         NA
# 4     4   1      1          1
# 10    4   2      2         26
# 16    4   3     28         NA
# 5     5   1      0          1
# 11    5   2      1         NA
# 6     6   1     20         30
# 12    6   2     50         NA