R:根据列前缀和后缀有条件地替换值
R: Conditionally replacing values based on column pre-fixes and suffixes
我有两个数据框。数据框 A 有许多 observations/rows、每个观察的 ID 和许多附加列。对于观察值 X 的子集,一组列的值为 missing/NA。数据框 B 包含 X 中观察值的一个子集(可以使用 ID 在数据框之间进行匹配)和与数据框 A 具有相同名称的变量,但包含用 [= 替换列集中缺失值的值21=].
我下面的代码(使用连接操作)仅添加列而不是替换缺失值。对于 B 中的每个附加变量(让我们将它们命名为 W),结果 table 产生 W.x 和 W.y.
library(dplyr)
foo <- data.frame(id = seq(1:6), x = c(NA, NA, NA, 1, 3, 8), z = seq_along(10:15))
bar <- data.frame(id = seq(1:2), x = c(10, 9))
dplyr::left_join(x = foo, y = bar, by = "id")
我正在尝试根据 ID 使用 B 中的值替换 A 中的缺失值,但这样做非常有效,因为我有很多列和很多行。我的目标是:
id x z
1 1 10 1
2 2 9 2
3 3 NA 3
4 4 1 4
5 5 3 5
6 6 8 6
一个想法是在加入后使用 ifelse(),但是为所有变量键入 ifelse() 函数是不可行的。有没有一种方法可以在没有数据库连接的情况下简单地做到这一点,或者是否有一种方法可以在所有以 .x 结尾的列中应用一个函数,如果 .x 中的值丢失,则用 .y 中的值替换 .x 中的值?
如果您不介意冗长的 baseR 方法,那么您可以使用 merge()
和仔细的数据框子集轻松完成此操作。
df <- merge(foo, bar, by="id", all.x=TRUE)
names(df) <- c("id", "x", "z", "y")
df$x[is.na(df$x)] <- df$y[is.na(df$x)]
df <- df[c("id", "x", "z")]
> df
id x z
1 1 10 1
2 2 9 2
3 3 NA 3
4 4 1 4
5 5 3 5
6 6 8 6
编辑
使用@alistaire 的示例数据框更新答案。
我们可以使用 mapply
扩展下面给出的相同答案,以便它可以处理 foo
和 bar
的多列。
找出两个数据帧之间的公共列并对它们进行排序,使它们的顺序相同。
vars <- sort(intersect(names(foo), names(bar))[-1])
foo[vars] <- mapply(function(x, y) {
ind = is.na(x)
replace(x, ind, y[match(foo$id[ind], bar$id)])
}, foo[vars], bar[vars])
foo
# id x y z
#1 1 10 1 1
#2 2 9 2 2
#3 3 NA 3 3
#4 4 1 4 4
#5 5 3 5 5
#6 6 8 6 6
原答案
我认为这符合您的要求:
foo[-1] <- sapply(foo[-1], function(x) {
ind = is.na(x)
replace(x, ind, bar$x[match(foo$id[ind], bar$id)])
})
foo
# id x z
#1 1 10 1
#2 2 9 2
#3 3 NA 3
#4 4 1 4
#5 5 3 5
#6 6 8 6
对于每一列(id
除外),我们在 foo
中找到缺失值并将其替换为 bar
中的相应值。
您可以在非分组列的交集上迭代 dplyr::coalesce
。它并不优雅,但应该可以很好地扩展:
library(tidyverse)
foo <- data.frame(id = seq(1:6),
x = c(NA, NA, NA, 1, 3, 8),
y = 1:6, # add extra shared variable
z = seq_along(10:15))
bar <- data.frame(id = seq(1:2),
y = c(1L, NA),
x = c(10, 9))
# names of non-grouping variables in both
vars <- intersect(names(foo), names(bar))[-1]
foobar <- left_join(foo, bar, by = 'id')
foobar <- vars %>%
map(paste0, c('.x', '.y')) %>% # make list of columns to coalesce
map(~foobar[.x]) %>% # for each set, subset foobar to a two-column data.frame
invoke_map(.f = coalesce) %>% # ...and coalesce it into a vector
set_names(vars) %>% # add names to list elements
bind_cols(foobar) %>% # bind into data.frame and cbind to foobar
select(union(names(foo), names(bar))) # drop duplicated columns
foobar
#> # A tibble: 6 x 4
#> id x y z
#> <int> <dbl> <int> <int>
#> 1 1 10 1 1
#> 2 2 9 2 2
#> 3 3 NA 3 3
#> 4 4 1 4 4
#> 5 5 3 5 5
#> 6 6 8 6 6
另一种尝试,本质上应该只是一个赋值操作。再次使用@alistaire 的数据:
vars <- c("x","y")
foo[vars] <- Map(pmax, foo[vars], bar[match(foo$id, bar$id), vars], na.rm=TRUE)
foo
# id x y z
#1 1 10 1 1
#2 2 9 2 2
#3 3 NA 3 3
#4 4 1 4 4
#5 5 3 5 5
#6 6 8 6 6
我有两个数据框。数据框 A 有许多 observations/rows、每个观察的 ID 和许多附加列。对于观察值 X 的子集,一组列的值为 missing/NA。数据框 B 包含 X 中观察值的一个子集(可以使用 ID 在数据框之间进行匹配)和与数据框 A 具有相同名称的变量,但包含用 [= 替换列集中缺失值的值21=].
我下面的代码(使用连接操作)仅添加列而不是替换缺失值。对于 B 中的每个附加变量(让我们将它们命名为 W),结果 table 产生 W.x 和 W.y.
library(dplyr)
foo <- data.frame(id = seq(1:6), x = c(NA, NA, NA, 1, 3, 8), z = seq_along(10:15))
bar <- data.frame(id = seq(1:2), x = c(10, 9))
dplyr::left_join(x = foo, y = bar, by = "id")
我正在尝试根据 ID 使用 B 中的值替换 A 中的缺失值,但这样做非常有效,因为我有很多列和很多行。我的目标是:
id x z
1 1 10 1
2 2 9 2
3 3 NA 3
4 4 1 4
5 5 3 5
6 6 8 6
一个想法是在加入后使用 ifelse(),但是为所有变量键入 ifelse() 函数是不可行的。有没有一种方法可以在没有数据库连接的情况下简单地做到这一点,或者是否有一种方法可以在所有以 .x 结尾的列中应用一个函数,如果 .x 中的值丢失,则用 .y 中的值替换 .x 中的值?
如果您不介意冗长的 baseR 方法,那么您可以使用 merge()
和仔细的数据框子集轻松完成此操作。
df <- merge(foo, bar, by="id", all.x=TRUE)
names(df) <- c("id", "x", "z", "y")
df$x[is.na(df$x)] <- df$y[is.na(df$x)]
df <- df[c("id", "x", "z")]
> df
id x z
1 1 10 1
2 2 9 2
3 3 NA 3
4 4 1 4
5 5 3 5
6 6 8 6
编辑
使用@alistaire 的示例数据框更新答案。
我们可以使用 mapply
扩展下面给出的相同答案,以便它可以处理 foo
和 bar
的多列。
找出两个数据帧之间的公共列并对它们进行排序,使它们的顺序相同。
vars <- sort(intersect(names(foo), names(bar))[-1])
foo[vars] <- mapply(function(x, y) {
ind = is.na(x)
replace(x, ind, y[match(foo$id[ind], bar$id)])
}, foo[vars], bar[vars])
foo
# id x y z
#1 1 10 1 1
#2 2 9 2 2
#3 3 NA 3 3
#4 4 1 4 4
#5 5 3 5 5
#6 6 8 6 6
原答案
我认为这符合您的要求:
foo[-1] <- sapply(foo[-1], function(x) {
ind = is.na(x)
replace(x, ind, bar$x[match(foo$id[ind], bar$id)])
})
foo
# id x z
#1 1 10 1
#2 2 9 2
#3 3 NA 3
#4 4 1 4
#5 5 3 5
#6 6 8 6
对于每一列(id
除外),我们在 foo
中找到缺失值并将其替换为 bar
中的相应值。
您可以在非分组列的交集上迭代 dplyr::coalesce
。它并不优雅,但应该可以很好地扩展:
library(tidyverse)
foo <- data.frame(id = seq(1:6),
x = c(NA, NA, NA, 1, 3, 8),
y = 1:6, # add extra shared variable
z = seq_along(10:15))
bar <- data.frame(id = seq(1:2),
y = c(1L, NA),
x = c(10, 9))
# names of non-grouping variables in both
vars <- intersect(names(foo), names(bar))[-1]
foobar <- left_join(foo, bar, by = 'id')
foobar <- vars %>%
map(paste0, c('.x', '.y')) %>% # make list of columns to coalesce
map(~foobar[.x]) %>% # for each set, subset foobar to a two-column data.frame
invoke_map(.f = coalesce) %>% # ...and coalesce it into a vector
set_names(vars) %>% # add names to list elements
bind_cols(foobar) %>% # bind into data.frame and cbind to foobar
select(union(names(foo), names(bar))) # drop duplicated columns
foobar
#> # A tibble: 6 x 4
#> id x y z
#> <int> <dbl> <int> <int>
#> 1 1 10 1 1
#> 2 2 9 2 2
#> 3 3 NA 3 3
#> 4 4 1 4 4
#> 5 5 3 5 5
#> 6 6 8 6 6
另一种尝试,本质上应该只是一个赋值操作。再次使用@alistaire 的数据:
vars <- c("x","y")
foo[vars] <- Map(pmax, foo[vars], bar[match(foo$id, bar$id), vars], na.rm=TRUE)
foo
# id x y z
#1 1 10 1 1
#2 2 9 2 2
#3 3 NA 3 3
#4 4 1 4 4
#5 5 3 5 5
#6 6 8 6 6