【问题标题】:R: assign previous non NA value 'n' times based on value in previous non NA rowR:根据前一个非 NA 行中的值分配前一个非 NA 值“n”次
【发布时间】:2016-03-12 16:29:35
【问题描述】:

我有一个数据框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 指定我想将收入中的值“结转”到后续行的次数(使用包 zoo 中的 na.locf() 方法)。例如,在上面的数据框中,cutoff 的值 2 表示应该将收入结转两次。

我在 SO 上看到了有关指定如何使用 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

【问题讨论】:

  • 如果第 1 个人和第 2 个人是不同的人,为什么要将第 1 个人 2012 年的收入结转到第 2 个人 2010 年的收入?

标签: r time-series zoo


【解决方案1】:

这是使用data.table 的尝试。分组方法在@jeremys 回答,虽然我在这里避免ifelselapply,而是将根据第一个income 值复制的第一个income 值与NAs 值复制.N - (cutoff[1L] + 1L) 次相结合.我也只对自第一次cutoff &gt; 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

【讨论】:

  • 不错的一个,不知道 rep 这样矢量化,以为它像 seq 一样工作
【解决方案2】:

这是使用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

【讨论】:

    【解决方案3】:

    使用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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 2015-01-28
      • 1970-01-01
      • 2021-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多