R - 如何在 NA 中填写值,但仅当结束值与开始值相同时?
R - How to fill in values in NA, but only when ending value is the same as the beginning value?
我有以下示例数据:
示例 <- data.frame(col1 =c(1, NA, NA, 4, NA, NA, 6, NA, NA, NA, 6, 8, NA, 2, NA))
col1
1
NA
NA
4
NA
NA
6
NA
NA
NA
6
8
NA
2
NA
我想用上面的值填充 NA,但前提是 NA 介于 2 个相同的值之间。在这个例子中,从 1 到 4 的第一个 NA 间隙不应该用 1 填充。但是第一个6和第二个6之间的空隙应该用6来填补。所有其他值应保持 NA。
因此,之后它应该看起来像:
col1
1
NA
NA
4
NA
NA
6
6
6
6
6
8
NA
2
NA
但实际上我并没有只有15个观察值,而是超过50000个。因此我需要一个有效的解决方案,这比我想象的要难。我尝试使用填充功能,但无法想出解决方案。
一个dplyr
和zoo
选项可以是:
df %>%
mutate(cond = na.locf0(col1) == na.locf0(col1, fromLast = TRUE),
col1 = ifelse(cond, na.locf0(col1), col1)) %>%
select(-cond)
col1
1 1
2 NA
3 NA
4 4
5 NA
6 NA
7 6
8 6
9 6
10 6
11 6
12 8
13 NA
14 2
15 NA
这是一个 dply 解决方案:
首先,我以 tibble 格式创建数据:
df <- tibble(
x = c(1, NA_real_, NA_real_,
4, NA_real_, NA_real_,
6, NA_real_, NA_real_, NA_real_,
6, 8, NA_real_, 2, NA_real_)
)
接下来,我创建两个分组变量,这将有助于识别第一个和最后一个非 NA 值。
然后我将这些参考值保存到 ref_start
和 ref_end
。
最后我覆盖了 x
:
的值
df %>%
mutate(gr1 = cumsum(!is.na(x))) %>%
group_by(gr1) %>%
mutate(ref_start = first(x)) %>%
ungroup() %>%
mutate(gr2 = lag(gr1, default = 1)) %>%
group_by(gr2) %>%
mutate(ref_end = last(x)) %>%
ungroup() %>%
mutate(x = if_else(is.na(x) & ref_start == ref_end, ref_start, x))
# A tibble: 15 x 1
x
<dbl>
1 1
2 NA
3 NA
4 4
5 NA
6 NA
7 6
8 6
9 6
10 6
11 6
12 8
13 NA
14 2
15 NA
df <- data.frame(col1 =c(1, NA, NA, 4, NA, NA, 6, NA, NA, NA, 6, 8, NA, 2, NA))
library(data.table)
library(magrittr)
setDT(df)[!is.na(col1), n := .N, by = col1] %>%
.[, n := nafill(n, type = "locf")] %>%
.[n == 2, col1 := nafill(col1, type = "locf")] %>%
.[, n := NULL] %>%
.[]
#> col1
#> 1: 1
#> 2: NA
#> 3: NA
#> 4: 4
#> 5: NA
#> 6: NA
#> 7: 6
#> 8: 6
#> 9: 6
#> 10: 6
#> 11: 6
#> 12: 8
#> 13: NA
#> 14: 2
#> 15: NA
由 reprex package (v2.0.1)
于 2021 年 10 月 11 日创建
这是使用 dplyr
和 tidyr
的 tidyverse
方法:
逻辑:
- 创建一个
id
列
- 删除所有 na 行
- 如果下一个值相同则标记
right_join
与第一个 Example
df
fill
向下flag
对应col1.y
mutate
与 ifelse
library(dplyr)
library(tidyr)
Example <- Example %>%
mutate(id=row_number())
Example %>%
na.omit() %>%
mutate(flag = ifelse(col1==lead(col1), TRUE, FALSE)) %>%
right_join(Example, by="id") %>%
arrange(id) %>%
fill(col1.y, .direction="down") %>%
fill(flag, .direction="down") %>%
mutate(col1.x = ifelse(flag==TRUE, col1.y, col1.x), .keep="unused") %>%
select(col1 = col1.x)
输出:
col1
1 1
2 NA
3 NA
4 4
5 NA
6 NA
7 6
8 6
9 6
10 6
11 6
12 8
13 NA
14 2
15 NA
我有以下示例数据:
示例 <- data.frame(col1 =c(1, NA, NA, 4, NA, NA, 6, NA, NA, NA, 6, 8, NA, 2, NA))
col1 |
---|
1 |
NA |
NA |
4 |
NA |
NA |
6 |
NA |
NA |
NA |
6 |
8 |
NA |
2 |
NA |
我想用上面的值填充 NA,但前提是 NA 介于 2 个相同的值之间。在这个例子中,从 1 到 4 的第一个 NA 间隙不应该用 1 填充。但是第一个6和第二个6之间的空隙应该用6来填补。所有其他值应保持 NA。 因此,之后它应该看起来像:
col1 |
---|
1 |
NA |
NA |
4 |
NA |
NA |
6 |
6 |
6 |
6 |
6 |
8 |
NA |
2 |
NA |
但实际上我并没有只有15个观察值,而是超过50000个。因此我需要一个有效的解决方案,这比我想象的要难。我尝试使用填充功能,但无法想出解决方案。
一个dplyr
和zoo
选项可以是:
df %>%
mutate(cond = na.locf0(col1) == na.locf0(col1, fromLast = TRUE),
col1 = ifelse(cond, na.locf0(col1), col1)) %>%
select(-cond)
col1
1 1
2 NA
3 NA
4 4
5 NA
6 NA
7 6
8 6
9 6
10 6
11 6
12 8
13 NA
14 2
15 NA
这是一个 dply 解决方案:
首先,我以 tibble 格式创建数据:
df <- tibble(
x = c(1, NA_real_, NA_real_,
4, NA_real_, NA_real_,
6, NA_real_, NA_real_, NA_real_,
6, 8, NA_real_, 2, NA_real_)
)
接下来,我创建两个分组变量,这将有助于识别第一个和最后一个非 NA 值。
然后我将这些参考值保存到 ref_start
和 ref_end
。
最后我覆盖了 x
:
df %>%
mutate(gr1 = cumsum(!is.na(x))) %>%
group_by(gr1) %>%
mutate(ref_start = first(x)) %>%
ungroup() %>%
mutate(gr2 = lag(gr1, default = 1)) %>%
group_by(gr2) %>%
mutate(ref_end = last(x)) %>%
ungroup() %>%
mutate(x = if_else(is.na(x) & ref_start == ref_end, ref_start, x))
# A tibble: 15 x 1
x
<dbl>
1 1
2 NA
3 NA
4 4
5 NA
6 NA
7 6
8 6
9 6
10 6
11 6
12 8
13 NA
14 2
15 NA
df <- data.frame(col1 =c(1, NA, NA, 4, NA, NA, 6, NA, NA, NA, 6, 8, NA, 2, NA))
library(data.table)
library(magrittr)
setDT(df)[!is.na(col1), n := .N, by = col1] %>%
.[, n := nafill(n, type = "locf")] %>%
.[n == 2, col1 := nafill(col1, type = "locf")] %>%
.[, n := NULL] %>%
.[]
#> col1
#> 1: 1
#> 2: NA
#> 3: NA
#> 4: 4
#> 5: NA
#> 6: NA
#> 7: 6
#> 8: 6
#> 9: 6
#> 10: 6
#> 11: 6
#> 12: 8
#> 13: NA
#> 14: 2
#> 15: NA
由 reprex package (v2.0.1)
于 2021 年 10 月 11 日创建这是使用 dplyr
和 tidyr
的 tidyverse
方法:
逻辑:
- 创建一个
id
列 - 删除所有 na 行
- 如果下一个值相同则标记
right_join
与第一个Example
dffill
向下flag
对应col1.y
mutate
与ifelse
library(dplyr)
library(tidyr)
Example <- Example %>%
mutate(id=row_number())
Example %>%
na.omit() %>%
mutate(flag = ifelse(col1==lead(col1), TRUE, FALSE)) %>%
right_join(Example, by="id") %>%
arrange(id) %>%
fill(col1.y, .direction="down") %>%
fill(flag, .direction="down") %>%
mutate(col1.x = ifelse(flag==TRUE, col1.y, col1.x), .keep="unused") %>%
select(col1 = col1.x)
输出:
col1
1 1
2 NA
3 NA
4 4
5 NA
6 NA
7 6
8 6
9 6
10 6
11 6
12 8
13 NA
14 2
15 NA