用 R 中最后一个或下一个非 NA 值填充 NA
Fill NAs with either last or next non NA value in R
我正在尝试用 R 中同一组中的其他非 NA 值填充列中的 NA 值。
所以我的数据看起来像这样:
df
id year pop
1 E1 2000 NA
2 E2 2000 NA
3 E2 2001 NA
4 E2 2003 120
5 E2 2005 125
6 E3 1999 115
7 E3 2001 300
8 E3 2003 NA
9 E4 2004 10
10 E4 2005 NA
11 E4 2008 NA
12 E4 2009 9
13 E5 2002 12
14 E5 2003 80
并且我希望 NA 值在同一组 id
中具有 pop
的最后一个非 NA 值或下一个非 NA 值。看起来像这样:
df.desired
id year pop
1 E1 2000 NA
2 E2 2000 120
3 E2 2001 120
4 E2 2003 120
5 E2 2005 125
6 E3 1999 115
7 E3 2001 300
8 E3 2003 300
9 E4 2004 10
10 E4 2005 10
11 E4 2008 9
12 E4 2009 9
13 E5 2002 12
14 E5 2003 80
我在 zoo::na.locf()
和 dplyr::fill()
上尝试了不同的方法,但我一直有两个主要问题:1. 我收到错误,因为整个组只有 NA(比如这里的 id == "E1"
)和 2. 我只能选择最后一个或 naxt 非 NA 值。
这些是我尝试过的一些例子:
library(tidyverse)
library(zoo)
df.desired <- df %>%
group_by(id) %>%
arrange(year)%>%
mutate(pop_imputated = pop)%>%
fill(pop_imputated)%>%
ungroup()
df.desired <- df %>%
group_by(id) %>%
arrange(year)%>%
mutate(pop_imputated = zoo::na.locf(pop))%>%
fill(pop_imputated)%>%
ungroup()
有什么想法吗?
非常感谢!
希望这就是您要找的。我用一组中最后一个非 NA
值填充了所有 NA
值。
library(dplyr)
df %>%
group_by(id) %>%
mutate(across(pop, ~ coalesce(.x, last(.x[!is.na(.x)]))))
# A tibble: 14 x 3
# Groups: id [5]
id year pop
<chr> <int> <int>
1 E1 2000 NA
2 E2 2000 125
3 E2 2001 125
4 E2 2003 120
5 E2 2005 125
6 E3 1999 115
7 E3 2001 300
8 E3 2003 300
9 E4 2004 10
10 E4 2005 9
11 E4 2008 9
12 E4 2009 9
13 E5 2002 12
14 E5 2003 80
您是否尝试过更改 tidyr::fill
函数的 .direction
属性?您可以使用 "downup"
(先向下,然后向上),反之亦然 "updown"
library(dplyr)
library(tidyr)
df %>%
group_by(id) %>%
mutate(pop_imputated = pop) %>%
fill(pop_imputated, .direction = "downup") %>%
ungroup()
# A tibble: 14 x 4
id year pop pop_imputated
<chr> <int> <int> <int>
1 E1 2000 NA NA
2 E2 2000 NA 120
3 E2 2001 NA 120
4 E2 2003 120 120
5 E2 2005 125 125
6 E3 1999 115 115
7 E3 2001 300 300
8 E3 2003 NA 300
9 E4 2004 10 10
10 E4 2005 NA 10
11 E4 2008 NA 10
12 E4 2009 9 9
13 E5 2002 12 12
14 E5 2003 80 80
它看起来与您想要的输出相似
库 runner
有一个内置的 function fill_run
也可以使用
df %>%
group_by(id) %>%
mutate(pop = runner::fill_run(pop, run_for_first = T))
#> Warning in runner::fill_run(pop, run_for_first = T): All x values are NA
#> # A tibble: 14 x 3
#> # Groups: id [5]
#> id year pop
#> <chr> <int> <int>
#> 1 E1 2000 NA
#> 2 E2 2000 120
#> 3 E2 2001 120
#> 4 E2 2003 120
#> 5 E2 2005 125
#> 6 E3 1999 115
#> 7 E3 2001 300
#> 8 E3 2003 300
#> 9 E4 2004 10
#> 10 E4 2005 10
#> 11 E4 2008 10
#> 12 E4 2009 9
#> 13 E5 2002 12
#> 14 E5 2003 80
由 reprex package (v2.0.0)
创建于 2021-05-13
另一种解决方案使用nalocf
(不适用上次观察结转);因为它是自上而下运行的,我们首先需要重新 arrange
数据框,所以第一个 pop
值是非 NA
:
library(zoo)
df %>%
arrange(desc(id)) %>%
mutate(pop = na.locf(pop))
id year pop
13 E5 2002 12
14 E5 2003 80
9 E4 2004 10
10 E4 2005 10
11 E4 2008 10
12 E4 2009 9
6 E3 1999 115
7 E3 2001 300
8 E3 2003 300
2 E2 2000 300
3 E2 2001 300
4 E2 2003 120
5 E2 2005 125
1 E1 2000 125
我们当然可以恢复原来的顺序:
library(zoo)
df %>%
arrange(desc(id)) %>%
mutate(pop = na.locf(pop)) %>%
arrange(id)
这是一个与您的预期输出完全匹配的答案:它将向上或向下估算最近的非缺失值。
这里是代码,使用了你的例子的加香料版本:
library(tidyverse)
df = structure(list(id = c("E1", "E2", "E2", "E2", "E2", "E3", "E3", "E3", "E4", "E4", "E4", "E4", "E4", "E4", "E4", "E4", "E5", "E5"),
year = c(2000L, 2000L, 2001L, 2003L, 2005L, 1999L, 2001L, 2003L, 2004L, 2005L, 2006L, 2007L, 2008L, 2009L, 2018L, 2019L, 2002L, 2003L),
pop = c(NA, NA, NA, 120L, 125L, 115L, 300L, NA, 10L, NA, NA, NA, NA, 9L, NA, 8L, 12L, 80L),
pop_exp = c(NA, 120L, 120L, 120L, 125L, 115L, 300L, 300L, 10L, 10L, 10L, 9L, 9L, 9L, 9L, 8L, 12L, 80L)),
class = "data.frame", row.names = c(NA, -18L))
fill_nearest = function(x){
keys=which(!is.na(x))
if(length(keys)==0) return(NA)
b = map_dbl(seq.int(x), ~keys[which.min(abs(.x-keys))])
x[b]
}
df %>%
group_by(id) %>%
arrange(id, year) %>%
mutate(pop_imputated = fill_nearest(pop)) %>%
ungroup()
#> # A tibble: 18 x 5
#> id year pop pop_exp pop_imputated
#> <chr> <int> <int> <int> <int>
#> 1 E1 2000 NA NA NA
#> 2 E2 2000 NA 120 120
#> 3 E2 2001 NA 120 120
#> 4 E2 2003 120 120 120
#> 5 E2 2005 125 125 125
#> 6 E3 1999 115 115 115
#> 7 E3 2001 300 300 300
#> 8 E3 2003 NA 300 300
#> 9 E4 2004 10 10 10
#> 10 E4 2005 NA 10 10
#> 11 E4 2006 NA 10 10
#> 12 E4 2007 NA 9 9
#> 13 E4 2008 NA 9 9
#> 14 E4 2009 9 9 9
#> 15 E4 2018 NA 9 9
#> 16 E4 2019 8 8 8
#> 17 E5 2002 12 12 12
#> 18 E5 2003 80 80 80
由 reprex package (v2.0.0)
于 2021-05-13 创建
因为我必须使用 purrr
循环,所以在庞大的数据集中它可能会有点慢。
编辑: 我建议在 tidyr::fill()
中添加此选项:https://github.com/tidyverse/tidyr/issues/1119。该问题还包含此函数的调整版本,以使用 year
列作为计算值之间“距离”的参考。例如,您宁愿将第 15 行设置为 8 而不是 9,因为年份更接近。
由于 na.approx
接受 approx
参数(参见 ?approx
和 ?na.approx
)我们可以使用 na.approx
与 method = "constant"
和 rule = 2
.如果您想要问题中显示的输出,也可以将数据排序回原始顺序。
library(dplyr)
library(zoo)
df %>%
group_by(id) %>%
arrange(year)%>%
mutate(pop_imputated = na.approx(pop, method = "const", rule = 2, na.rm = FALSE)) %>%
ungroup() %>%
arrange(id, year)
给予:
# A tibble: 14 x 4
id year pop pop_imputated
<chr> <int> <int> <dbl>
1 E1 2000 NA NA
2 E2 2000 NA 120
3 E2 2001 NA 120
4 E2 2003 120 120
5 E2 2005 125 125
6 E3 1999 115 115
7 E3 2001 300 300
8 E3 2003 NA 300
9 E4 2004 10 10
10 E4 2005 NA 10
11 E4 2008 NA 10
12 E4 2009 9 9
13 E5 2002 12 12
14 E5 2003 80 80
备注
Lines <- " id year pop
1 E1 2000 NA
2 E2 2000 NA
3 E2 2001 NA
4 E2 2003 120
5 E2 2005 125
6 E3 1999 115
7 E3 2001 300
8 E3 2003 NA
9 E4 2004 10
10 E4 2005 NA
11 E4 2008 NA
12 E4 2009 9
13 E5 2002 12
14 E5 2003 80"
df <- read.table(text = Lines)
我正在尝试用 R 中同一组中的其他非 NA 值填充列中的 NA 值。 所以我的数据看起来像这样:
df
id year pop
1 E1 2000 NA
2 E2 2000 NA
3 E2 2001 NA
4 E2 2003 120
5 E2 2005 125
6 E3 1999 115
7 E3 2001 300
8 E3 2003 NA
9 E4 2004 10
10 E4 2005 NA
11 E4 2008 NA
12 E4 2009 9
13 E5 2002 12
14 E5 2003 80
并且我希望 NA 值在同一组 id
中具有 pop
的最后一个非 NA 值或下一个非 NA 值。看起来像这样:
df.desired
id year pop
1 E1 2000 NA
2 E2 2000 120
3 E2 2001 120
4 E2 2003 120
5 E2 2005 125
6 E3 1999 115
7 E3 2001 300
8 E3 2003 300
9 E4 2004 10
10 E4 2005 10
11 E4 2008 9
12 E4 2009 9
13 E5 2002 12
14 E5 2003 80
我在 zoo::na.locf()
和 dplyr::fill()
上尝试了不同的方法,但我一直有两个主要问题:1. 我收到错误,因为整个组只有 NA(比如这里的 id == "E1"
)和 2. 我只能选择最后一个或 naxt 非 NA 值。
这些是我尝试过的一些例子:
library(tidyverse)
library(zoo)
df.desired <- df %>%
group_by(id) %>%
arrange(year)%>%
mutate(pop_imputated = pop)%>%
fill(pop_imputated)%>%
ungroup()
df.desired <- df %>%
group_by(id) %>%
arrange(year)%>%
mutate(pop_imputated = zoo::na.locf(pop))%>%
fill(pop_imputated)%>%
ungroup()
有什么想法吗? 非常感谢!
希望这就是您要找的。我用一组中最后一个非 NA
值填充了所有 NA
值。
library(dplyr)
df %>%
group_by(id) %>%
mutate(across(pop, ~ coalesce(.x, last(.x[!is.na(.x)]))))
# A tibble: 14 x 3
# Groups: id [5]
id year pop
<chr> <int> <int>
1 E1 2000 NA
2 E2 2000 125
3 E2 2001 125
4 E2 2003 120
5 E2 2005 125
6 E3 1999 115
7 E3 2001 300
8 E3 2003 300
9 E4 2004 10
10 E4 2005 9
11 E4 2008 9
12 E4 2009 9
13 E5 2002 12
14 E5 2003 80
您是否尝试过更改 tidyr::fill
函数的 .direction
属性?您可以使用 "downup"
(先向下,然后向上),反之亦然 "updown"
library(dplyr)
library(tidyr)
df %>%
group_by(id) %>%
mutate(pop_imputated = pop) %>%
fill(pop_imputated, .direction = "downup") %>%
ungroup()
# A tibble: 14 x 4
id year pop pop_imputated
<chr> <int> <int> <int>
1 E1 2000 NA NA
2 E2 2000 NA 120
3 E2 2001 NA 120
4 E2 2003 120 120
5 E2 2005 125 125
6 E3 1999 115 115
7 E3 2001 300 300
8 E3 2003 NA 300
9 E4 2004 10 10
10 E4 2005 NA 10
11 E4 2008 NA 10
12 E4 2009 9 9
13 E5 2002 12 12
14 E5 2003 80 80
它看起来与您想要的输出相似
库 runner
有一个内置的 function fill_run
也可以使用
df %>%
group_by(id) %>%
mutate(pop = runner::fill_run(pop, run_for_first = T))
#> Warning in runner::fill_run(pop, run_for_first = T): All x values are NA
#> # A tibble: 14 x 3
#> # Groups: id [5]
#> id year pop
#> <chr> <int> <int>
#> 1 E1 2000 NA
#> 2 E2 2000 120
#> 3 E2 2001 120
#> 4 E2 2003 120
#> 5 E2 2005 125
#> 6 E3 1999 115
#> 7 E3 2001 300
#> 8 E3 2003 300
#> 9 E4 2004 10
#> 10 E4 2005 10
#> 11 E4 2008 10
#> 12 E4 2009 9
#> 13 E5 2002 12
#> 14 E5 2003 80
由 reprex package (v2.0.0)
创建于 2021-05-13另一种解决方案使用nalocf
(不适用上次观察结转);因为它是自上而下运行的,我们首先需要重新 arrange
数据框,所以第一个 pop
值是非 NA
:
library(zoo)
df %>%
arrange(desc(id)) %>%
mutate(pop = na.locf(pop))
id year pop
13 E5 2002 12
14 E5 2003 80
9 E4 2004 10
10 E4 2005 10
11 E4 2008 10
12 E4 2009 9
6 E3 1999 115
7 E3 2001 300
8 E3 2003 300
2 E2 2000 300
3 E2 2001 300
4 E2 2003 120
5 E2 2005 125
1 E1 2000 125
我们当然可以恢复原来的顺序:
library(zoo)
df %>%
arrange(desc(id)) %>%
mutate(pop = na.locf(pop)) %>%
arrange(id)
这是一个与您的预期输出完全匹配的答案:它将向上或向下估算最近的非缺失值。
这里是代码,使用了你的例子的加香料版本:
library(tidyverse)
df = structure(list(id = c("E1", "E2", "E2", "E2", "E2", "E3", "E3", "E3", "E4", "E4", "E4", "E4", "E4", "E4", "E4", "E4", "E5", "E5"),
year = c(2000L, 2000L, 2001L, 2003L, 2005L, 1999L, 2001L, 2003L, 2004L, 2005L, 2006L, 2007L, 2008L, 2009L, 2018L, 2019L, 2002L, 2003L),
pop = c(NA, NA, NA, 120L, 125L, 115L, 300L, NA, 10L, NA, NA, NA, NA, 9L, NA, 8L, 12L, 80L),
pop_exp = c(NA, 120L, 120L, 120L, 125L, 115L, 300L, 300L, 10L, 10L, 10L, 9L, 9L, 9L, 9L, 8L, 12L, 80L)),
class = "data.frame", row.names = c(NA, -18L))
fill_nearest = function(x){
keys=which(!is.na(x))
if(length(keys)==0) return(NA)
b = map_dbl(seq.int(x), ~keys[which.min(abs(.x-keys))])
x[b]
}
df %>%
group_by(id) %>%
arrange(id, year) %>%
mutate(pop_imputated = fill_nearest(pop)) %>%
ungroup()
#> # A tibble: 18 x 5
#> id year pop pop_exp pop_imputated
#> <chr> <int> <int> <int> <int>
#> 1 E1 2000 NA NA NA
#> 2 E2 2000 NA 120 120
#> 3 E2 2001 NA 120 120
#> 4 E2 2003 120 120 120
#> 5 E2 2005 125 125 125
#> 6 E3 1999 115 115 115
#> 7 E3 2001 300 300 300
#> 8 E3 2003 NA 300 300
#> 9 E4 2004 10 10 10
#> 10 E4 2005 NA 10 10
#> 11 E4 2006 NA 10 10
#> 12 E4 2007 NA 9 9
#> 13 E4 2008 NA 9 9
#> 14 E4 2009 9 9 9
#> 15 E4 2018 NA 9 9
#> 16 E4 2019 8 8 8
#> 17 E5 2002 12 12 12
#> 18 E5 2003 80 80 80
由 reprex package (v2.0.0)
于 2021-05-13 创建因为我必须使用 purrr
循环,所以在庞大的数据集中它可能会有点慢。
编辑: 我建议在 tidyr::fill()
中添加此选项:https://github.com/tidyverse/tidyr/issues/1119。该问题还包含此函数的调整版本,以使用 year
列作为计算值之间“距离”的参考。例如,您宁愿将第 15 行设置为 8 而不是 9,因为年份更接近。
由于 na.approx
接受 approx
参数(参见 ?approx
和 ?na.approx
)我们可以使用 na.approx
与 method = "constant"
和 rule = 2
.如果您想要问题中显示的输出,也可以将数据排序回原始顺序。
library(dplyr)
library(zoo)
df %>%
group_by(id) %>%
arrange(year)%>%
mutate(pop_imputated = na.approx(pop, method = "const", rule = 2, na.rm = FALSE)) %>%
ungroup() %>%
arrange(id, year)
给予:
# A tibble: 14 x 4
id year pop pop_imputated
<chr> <int> <int> <dbl>
1 E1 2000 NA NA
2 E2 2000 NA 120
3 E2 2001 NA 120
4 E2 2003 120 120
5 E2 2005 125 125
6 E3 1999 115 115
7 E3 2001 300 300
8 E3 2003 NA 300
9 E4 2004 10 10
10 E4 2005 NA 10
11 E4 2008 NA 10
12 E4 2009 9 9
13 E5 2002 12 12
14 E5 2003 80 80
备注
Lines <- " id year pop
1 E1 2000 NA
2 E2 2000 NA
3 E2 2001 NA
4 E2 2003 120
5 E2 2005 125
6 E3 1999 115
7 E3 2001 300
8 E3 2003 NA
9 E4 2004 10
10 E4 2005 NA
11 E4 2008 NA
12 E4 2009 9
13 E5 2002 12
14 E5 2003 80"
df <- read.table(text = Lines)