na 在特定值后填充
Na fill after a specific value
我想在 1 之后使用 NA.fill,但在 -1 之后保留 NA。有没有简单的解决方案?
Old
New
1
1
NA
1
NA
1
NA
1
-1
-1
NA
NA
NA
NA
1
1
NA
1
NA
1
可重现的示例数据
dat <- read.table(text = "
Old New
1 1
NA 1
NA 1
NA 1
-1 -1
NA NA
NA NA
1 1
NA 1
NA 1", header = TRUE)
编辑:我在列中只有 1 和 -1。谢谢大家,答案很有帮助。我的 'New' 专栏现在正是我想要的。
与cumsum:
df$Old[as.logical(cumsum(replace(df$Old, is.na(df$Old), 0)))] <- 1
你可以使用循环
x = c(1,NA,NA,NA,-1,NA,NA,1,NA,NA)
for (i in seq_along(x)[-1]) {
if (!is.na(x[i-1]) & x[i-1] == 1 & is.na(x[i])) x[i] = 1
}
# [1] 1 1 1 1 -1 NA NA 1 1 1
这是一种使用 rle
的方法,提供或接受 hack。
r <- rle(ifelse(is.na(dat$Old), -Inf, dat$Old))
r$values[is.infinite(r$values)] <- NA_integer_
r
# Run Length Encoding
# lengths: int [1:6] 1 3 1 2 1 2
# values : num [1:6] 1 NA -1 NA 1 NA
ind <- is.na(r$values[-1]) & r$values[-length(r$values)] == 1
ind
# [1] TRUE FALSE FALSE FALSE TRUE
r$values[c(FALSE, ind)] <- r$values[c(ind, FALSE)]
inverse.rle(r)
# [1] 1 1 1 1 -1 NA NA 1 1 1
备注:
rle
将所有缺失值(即 NA
)视为 不相等 ,这违背了我们预期使用的 运行 长度编码;我通过首先将 NA
转换为 -Inf
(有点随意,我假设极不可能出现在真实数据中)、运行 和 rle
,然后转换回 NA
is.na(r$values[-1]) & r$values[-length(r$values)] == 1
判断一个值是否为NA
且前一个值为1
;
- 我们使用该值(如
ind
)来确定要替换哪些值 (c(F, ind)
) 以及用哪些值替换它们 (c(ind, F)
);
inverse.rle
做了它应该做的事情:重新生成矢量,但现在 1-following-NA
值更改为 1
,没有其他更改
如果逻辑改为 “填充 NA,除非先前的值不是 -1”(如果还有非 1
值应该填充)通过将 ind
计算从 == 1
更改为 != -1
.
使用data.table:
library(data.table)
setDT(dat)[, x := fifelse(is.na(Old) & head(Old, 1) == 1, head(Old, 1), Old),
by = cumsum(!is.na(Old)) ]
df
# Old New x
# 1: 1 1 1
# 2: NA 1 1
# 3: NA 1 1
# 4: NA 1 1
# 5: -1 -1 -1
# 6: NA NA NA
# 7: NA NA NA
# 8: 1 1 1
# 9: NA 1 1
# 10: NA 1 1
您可以通过 fill
和 ifelse
library(tidyverse)
dat <- structure(list(Old = c(1L, NA, NA, NA, -1L, NA, NA, 1L, NA, NA
)), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"
))
dat %>%
mutate(New = Old) %>%
fill(New) %>%
mutate(New = ifelse(New == -1, Old, New)) %>%
select(Old, New)
结果:
# A tibble: 10 x 2
Old New
<int> <int>
1 1 1
2 NA 1
3 NA 1
4 NA 1
5 -1 -1
6 NA NA
7 NA NA
8 1 1
9 NA 1
10 NA 1
我认为 也可能有帮助。
类似于@Otto Kässi 使用 zoo::na.locf
-
的逻辑
transform(dat, New = zoo::na.locf(Old)) |>
transform(New = ifelse(New == -1, Old, New))
# Old New
#1 1 1
#2 NA 1
#3 NA 1
#4 NA 1
#5 -1 -1
#6 NA NA
#7 NA NA
#8 1 1
#9 NA 1
#10 NA 1
与purrr::reduce
:
library(tidyverse)
reduce(2:nrow(dat), function(x,y) {
if (is.na(x$Old[y]) & !is.na(x$Old[y-1]) & x$Old[y-1] == 1) x$Old[y] <- 1; x},
.init=dat)
#> Old New
#> 1 1 1
#> 2 1 1
#> 3 1 1
#> 4 1 1
#> 5 -1 -1
#> 6 NA NA
#> 7 NA NA
#> 8 1 1
#> 9 1 1
#> 10 1 1
我想在 1 之后使用 NA.fill,但在 -1 之后保留 NA。有没有简单的解决方案?
Old | New |
---|---|
1 | 1 |
NA | 1 |
NA | 1 |
NA | 1 |
-1 | -1 |
NA | NA |
NA | NA |
1 | 1 |
NA | 1 |
NA | 1 |
可重现的示例数据
dat <- read.table(text = "
Old New
1 1
NA 1
NA 1
NA 1
-1 -1
NA NA
NA NA
1 1
NA 1
NA 1", header = TRUE)
编辑:我在列中只有 1 和 -1。谢谢大家,答案很有帮助。我的 'New' 专栏现在正是我想要的。
与cumsum:
df$Old[as.logical(cumsum(replace(df$Old, is.na(df$Old), 0)))] <- 1
你可以使用循环
x = c(1,NA,NA,NA,-1,NA,NA,1,NA,NA)
for (i in seq_along(x)[-1]) {
if (!is.na(x[i-1]) & x[i-1] == 1 & is.na(x[i])) x[i] = 1
}
# [1] 1 1 1 1 -1 NA NA 1 1 1
这是一种使用 rle
的方法,提供或接受 hack。
r <- rle(ifelse(is.na(dat$Old), -Inf, dat$Old))
r$values[is.infinite(r$values)] <- NA_integer_
r
# Run Length Encoding
# lengths: int [1:6] 1 3 1 2 1 2
# values : num [1:6] 1 NA -1 NA 1 NA
ind <- is.na(r$values[-1]) & r$values[-length(r$values)] == 1
ind
# [1] TRUE FALSE FALSE FALSE TRUE
r$values[c(FALSE, ind)] <- r$values[c(ind, FALSE)]
inverse.rle(r)
# [1] 1 1 1 1 -1 NA NA 1 1 1
备注:
rle
将所有缺失值(即NA
)视为 不相等 ,这违背了我们预期使用的 运行 长度编码;我通过首先将NA
转换为-Inf
(有点随意,我假设极不可能出现在真实数据中)、运行 和rle
,然后转换回NA
is.na(r$values[-1]) & r$values[-length(r$values)] == 1
判断一个值是否为NA
且前一个值为1
;- 我们使用该值(如
ind
)来确定要替换哪些值 (c(F, ind)
) 以及用哪些值替换它们 (c(ind, F)
); inverse.rle
做了它应该做的事情:重新生成矢量,但现在 1-following-NA
值更改为1
,没有其他更改
如果逻辑改为 “填充 NA,除非先前的值不是 -1”(如果还有非 1
值应该填充)通过将 ind
计算从 == 1
更改为 != -1
.
使用data.table:
library(data.table)
setDT(dat)[, x := fifelse(is.na(Old) & head(Old, 1) == 1, head(Old, 1), Old),
by = cumsum(!is.na(Old)) ]
df
# Old New x
# 1: 1 1 1
# 2: NA 1 1
# 3: NA 1 1
# 4: NA 1 1
# 5: -1 -1 -1
# 6: NA NA NA
# 7: NA NA NA
# 8: 1 1 1
# 9: NA 1 1
# 10: NA 1 1
您可以通过 fill
和 ifelse
library(tidyverse)
dat <- structure(list(Old = c(1L, NA, NA, NA, -1L, NA, NA, 1L, NA, NA
)), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"
))
dat %>%
mutate(New = Old) %>%
fill(New) %>%
mutate(New = ifelse(New == -1, Old, New)) %>%
select(Old, New)
结果:
# A tibble: 10 x 2
Old New
<int> <int>
1 1 1
2 NA 1
3 NA 1
4 NA 1
5 -1 -1
6 NA NA
7 NA NA
8 1 1
9 NA 1
10 NA 1
我认为
类似于@Otto Kässi 使用 zoo::na.locf
-
transform(dat, New = zoo::na.locf(Old)) |>
transform(New = ifelse(New == -1, Old, New))
# Old New
#1 1 1
#2 NA 1
#3 NA 1
#4 NA 1
#5 -1 -1
#6 NA NA
#7 NA NA
#8 1 1
#9 NA 1
#10 NA 1
与purrr::reduce
:
library(tidyverse)
reduce(2:nrow(dat), function(x,y) {
if (is.na(x$Old[y]) & !is.na(x$Old[y-1]) & x$Old[y-1] == 1) x$Old[y] <- 1; x},
.init=dat)
#> Old New
#> 1 1 1
#> 2 1 1
#> 3 1 1
#> 4 1 1
#> 5 -1 -1
#> 6 NA NA
#> 7 NA NA
#> 8 1 1
#> 9 1 1
#> 10 1 1