R:根据前一个非 NA 行中的值分配前一个非 NA 值 'n' 次
R: assign previous non NA value 'n' times based on value in previous non NA row
我有一个数据框 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
指定我想将 income 中的值 'carry forward' 到后续行的次数(使用包 zoo 中的 na.locf() 方法) .例如,在上面的数据框中,cutoff 的值为 2 表示收入应结转两次。
我在 SO 上看到了关于指定如何使用 na.locf 结转 n 次 当 n 为常量时的示例。 但就我而言,我遇到了麻烦当 n 变化时泛化 (R -- Carry last observation forward n times)。
这是我的原始数据框:
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
这是使用 dplyr
的答案。
它通过按不同截止值的累积总和进行分组来工作。
如果截止值为 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
使用 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
这是使用 data.table
的尝试。分组方法在@jeremys 的回答中,虽然我在这里避免使用 ifelse
或 lapply
,而是将根据第一个 income
值复制的第一个 income
值与 NA
s 值重复 .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
我有一个数据框 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
指定我想将 income 中的值 'carry forward' 到后续行的次数(使用包 zoo 中的 na.locf() 方法) .例如,在上面的数据框中,cutoff 的值为 2 表示收入应结转两次。
我在 SO 上看到了关于指定如何使用 na.locf 结转 n 次 当 n 为常量时的示例。 但就我而言,我遇到了麻烦当 n 变化时泛化 (R -- Carry last observation forward n times)。
这是我的原始数据框:
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
这是使用 dplyr
的答案。
它通过按不同截止值的累积总和进行分组来工作。
如果截止值为 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
使用 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
这是使用 data.table
的尝试。分组方法在@jeremys 的回答中,虽然我在这里避免使用 ifelse
或 lapply
,而是将根据第一个 income
值复制的第一个 income
值与 NA
s 值重复 .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