R:根据先前非NA行

时间:2015-12-07 22:12:13

标签: r time-series zoo

我有一个数据框test_case。我在列(income)中缺少数据。

test_case <- data.frame(
person=c(1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3),
year=c(2010, 2011, 2012, 2010, 2011, 2012, 2010, 2011, 2013, 2014, 2014, 2014),
income=c(4, 10, 13, NA, NA, NA, 13, NA, NA, NA, NA, NA),
cutoff=c(0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0)
)

变量cutoff指定我希望将收入中的值“结转”到后续行中的次数(使用包动物园中的na.locf()方法)。例如,在上面的数据框中,截止值为2表示收入应该结转两次。

我已经看过关于指定如何使用na.locf来向前移n次当n是常数时的示例。但在我的情况下,我在泛化时遇到了问题(R -- Carry last observation forward n times当n正在改变时。

这是我的原始数据框:

   person year income cutoff
1       1 2010      4      0
2       1 2011     10      0
3       1 2012     13      2
4       2 2010     NA      0
5       2 2011     NA      0
6       2 2012     NA      0
7       3 2010     13      3
8       3 2011     NA      0
9       3 2013     NA      0
10      3 2014     NA      0
11      3 2014     NA      0
12      3 2014     NA      0

这是所需的输出:

   person year income cutoff
1       1 2010      4      0
2       1 2011     10      0
3       1 2012     13      2
4       2 2010     13      0
5       2 2011     13      0
6       2 2012     NA      0
7       3 2010     13      3
8       3 2011     13      0
9       3 2013     13      0
10      3 2014     13      0
11      3 2014     NA      0
12      3 2014     NA      0

3 个答案:

答案 0 :(得分:5)

此处尝试使用data.table。分组方法是@jeremys的答案,虽然我在这里避免使用ifelselapply,而是将根据第一个income值复制的第一个income值与NA个值复制.N - (cutoff[1L] + 1L)次。我自第一次cutoff > 0L)

以来也只对这些值进行操作
library(data.table)
setDT(test_case)[which.max(cutoff > 0L):.N, # Or `cutoff > 0L | is.na(income)`
                 income := c(rep(income[1L], cutoff[1L] + 1L), rep(NA, .N - (cutoff[1L] + 1L))), 
                 by = cumsum(cutoff != 0L)]
test_case
#     person year income cutoff
#  1:      1 2010      4      0
#  2:      1 2011     10      0
#  3:      1 2012     13      2
#  4:      2 2010     13      0
#  5:      2 2011     13      0
#  6:      2 2012     NA      0
#  7:      3 2010     13      3
#  8:      3 2011     13      0
#  9:      3 2013     13      0
# 10:      3 2014     13      0
# 11:      3 2014     NA      0
# 12:      3 2014     NA      0

答案 1 :(得分:3)

以下是使用dplyr的答案。

它的工作原理是按不同截止值的累积和进行分组。

如果cutoff为0,它会生成一个FALSE列表,并且TRUE的截止数量是未列出的并切成组的大小。

然后使用ifelse,收入未经修改或成为第一笔收入(即截止收入)。

library(dplyr)

test_case %>% group_by(z = cumsum(cutoff != 0)) %>%
              mutate(income = ifelse(unlist(lapply(cutoff, function(x) rep(as.logical(x), max(1,x + 1))))[1:n()], income[1], income))

Source: local data frame [12 x 5]
Groups: z [3]

       z person  year income cutoff
   (int)  (dbl) (dbl)  (dbl)  (dbl)
1      0      1  2010      4      0
2      0      1  2011     10      0
3      1      1  2012     13      2
4      1      2  2010     13      0
5      1      2  2011     13      0
6      1      2  2012     NA      0
7      2      3  2010     13      3
8      2      3  2011     13      0
9      2      3  2013     13      0
10     2      3  2014     13      0
11     2      3  2014     NA      0
12     2      3  2014     NA      0

答案 2 :(得分:2)

使用na.locf的解决方案可以与@ jeremycg的解决方案类似的方式工作。我们只需要按cumsum(cutoff != 0)和另一个变换row_number

进行分组

我的解决方案并不像jeremycg那样优雅,但这就是我接触它的方式:

library(dplyr)
library(zoo)
test_case %>%
  mutate(
    rownum = row_number(),
    cutoff2 = ifelse(cutoff == 0, NA, cutoff + rownum),
    cutoff2 = na.locf(cutoff2, na.rm = FALSE),
    cutoff2 = ifelse(rownum > cutoff2, NA, cutoff2)
  ) %>%
  group_by(z = cumsum(cutoff != 0), cutoff2) %>%
  mutate(income = na.locf(income, na.rm = FALSE))
# Source: local data frame [12 x 7]
# Groups: z, cutoff2 [5]
# 
#    person  year income cutoff rownum cutoff2     z
#     (dbl) (dbl)  (dbl)  (dbl)  (int)   (dbl) (int)
# 1       1  2010      4      0      1      NA     0
# 2       1  2011     10      0      2      NA     0
# 3       1  2012     13      2      3       5     1
# 4       2  2010     13      0      4       5     1
# 5       2  2011     13      0      5       5     1
# 6       2  2012     NA      0      6      NA     1
# 7       3  2010     13      3      7      10     2
# 8       3  2011     13      0      8      10     2
# 9       3  2013     13      0      9      10     2
# 10      3  2014     13      0     10      10     2
# 11      3  2014     NA      0     11      NA     2
# 12      3  2014     NA      0     12      NA     2