将一列中的内容替换为另一列 R
Replace content in one column with another column R
我正在处理一些调查数据,我想用另一个调查项目替换一个调查 item/column 的内容,同时保留原始单元格内容。例如 - 如果 Q2_1.x 缺失(缺失编码为“-99”或编码为 character_NA),将 Q2_1.x 替换为 Q2_1.y。
这是我的数据示例:
ibrary(dplyr)
library(magrittr)
ibrary(readr)
org_dat <- read_table('ID Q2_1.x Q2_2.x Q2_1.y Q2_2.y Q14_1.x Q14_1.y Q15
1 Yes NA NA NA Sometimes NA NA
2 -99 NA No NA NA Always Yes
3 Yes NA Yes NA NA NA NA
4 -99 NA NA No NA Yes No
5 NA -99 NA NA NA Always NA
6 -99 NA NA No NA NA NA') %>% mutate_all(as.character)
这是我想要的输出:
dat_out <- read_table('ID Q2_1 Q2_2 Q14_1 Q15
1 Yes NA Sometimes NA
2 No NA Always Yes
3 Yes NA NA NA
4 -99 No Yes No
5 NA -99 Always NA
6 -99 No NA NA')
当前解
我知道我可以单独替换这些列中的每一列,但我有很多列要处理,我想使用一种聪明的 dplyr/grepl 方法来解决这个问题!有任何想法吗?我总是用 Q*.y 替换 Q*.x。
org_dat %>% mutate(Q2_1.x = case_when(!is.na(Q2_1.y) &
Q2_1.x == '-99'| is.na(Q2_1.x) ~ Q2_1.y,
TRUE ~ Q2_1.x)) %>%
mutate(Q2_2.x = case_when(!is.na(Q2_2.y) &
Q2_2.x == '-99'| is.na(Q2_2.x) ~ Q2_2.y,
TRUE ~ Q2_2.x)) %>%
mutate(Q14_1.x = case_when(!is.na(Q14_1.y) &
Q14_1.x == '-99'| is.na(Q14_1.x) ~ Q14_1.y,
TRUE ~ Q14_1.x)) %>%
rename(Q2_1 = Q2_1.x,
Q2_2 = Q2_2.x,
Q14_1 = Q14_1.x) %>%
select(-matches("x|y"))
更短的方法。只需去掉所有变量名的 ".x"
后缀,然后转换名称不是 "ID"
或不以 ".y"
结尾的变量。对于这些变量中的每一个,get0
具有 ".y"
后缀的对应项并按如下方式进行替换。请注意,如果没有带有 ".y"
后缀的对应项,则 get0
returns NULL
和 idx
将折叠为 integer(0)
。结果,返回变量 as-is.
library(dplyr)
ord_dat %>%
rename_with(~sub("\.x", "", .), ends_with(".x")) %>%
transmute(ID, across(!ID & !ends_with(".y"), ~{
.y <- get0(paste0(cur_column(), ".y"))
idx <- which(.x %in% c("-99", NA) & !is.na(.y))
replace(.x, idx, .y[idx])
}))
这是一个 tidyverse 方法。我们会
pivot_longer
数据集分为四列:ID
、Q
(问题)、x
、y
、
- 在
x
显示 NA
或 "-99"
但 y
显示非 NA
值的位置替换 x
中的任何值.
- 删除列
y
和 pivot_wider
名称来自 Q
且值来自 x
. 的数据集
步骤并不复杂,但确实需要对功能进行精细控制。这使得代码有点长:
library(dplyr)
library(tidyr)
ord_dat %>%
pivot_longer(
-ID,
names_to = c("Q", ".value"),
names_pattern = "([^\.]*)\.?([^\.]*)",
names_transform = list(.value = ~replace(., . == "", "x"))
) %>%
mutate(x = {
idx <- which(x %in% c("-99", NA) & !is.na(y))
replace(x, idx, y[idx])
}, y = NULL) %>%
pivot_wider(names_from = Q, values_from = x)
输出
# A tibble: 6 x 5
ID Q2_1 Q2_2 Q14_1 Q15
<chr> <chr> <chr> <chr> <chr>
1 1 Yes NA Sometimes NA
2 2 No NA Always Yes
3 3 Yes NA NA NA
4 4 -99 No Yes No
5 5 NA -99 Always NA
6 6 -99 No NA NA
这里答案的关键是首先用 na_if
将 user-defined NA 翻译成真正的 nas,然后 coalesce
和成对的列。
library(dplyr)
library(stringr)
org_dat %>%
na_if(-99) %>%
mutate(across(ends_with('.x'),
~coalesce(.x, get(deparse(substitute(.x)) %>%
str_replace('\.x', '.y'))))) %>%
select(-ends_with('.y')) %>%
rename_with(~str_remove(.x, '\..$'))
# A tibble: 6 × 5
ID Q2_1 Q2_2 Q14_1 Q15
<chr> <chr> <chr> <chr> <chr>
1 1 Yes NA Sometimes NA
2 2 No NA Always Yes
3 3 Yes NA NA NA
4 4 NA No Yes No
5 5 NA NA Always NA
6 6 NA No NA NA
编辑
原始答案没有提供实际所需的输出,因为它用 NA 替换了所有 user-defined NA (-99)。
如果OP想保留这些用户定义的NA,我们可以这样做:
首先,将所有列更改为字符。
其次,将 data.frame 拆分为由前缀“Q{number}_{number}”与 split.default
配对的数据帧。
最后,modify
所有具有两列('x' 和 'y' 对)的列表元素 modify_if
和 coalesce
。
library(dplyr)
library(purrr)
org_dat %>%
mutate(across(everything(), as.character)) %>%
split.default(sub('\..$', '', names(org_dat))) %>%
modify_if(.p=~ncol(.x)==2, .f = ~coalesce(.x[[1]], .x[[2]])) %>%
bind_cols() %>%
select(ID, Q2_1, Q2_2, Q14_1, Q15)
# A tibble: 6 × 5
ID Q2_1 Q2_2 Q14_1 Q15
<chr> <chr> <chr> <chr> <chr>
1 1 Yes NA Sometimes NA
2 2 -99 NA Always Yes
3 3 Yes NA NA NA
4 4 -99 No Yes No
5 5 NA -99 Always NA
6 6 -99 No NA NA
我正在处理一些调查数据,我想用另一个调查项目替换一个调查 item/column 的内容,同时保留原始单元格内容。例如 - 如果 Q2_1.x 缺失(缺失编码为“-99”或编码为 character_NA),将 Q2_1.x 替换为 Q2_1.y。
这是我的数据示例:
ibrary(dplyr)
library(magrittr)
ibrary(readr)
org_dat <- read_table('ID Q2_1.x Q2_2.x Q2_1.y Q2_2.y Q14_1.x Q14_1.y Q15
1 Yes NA NA NA Sometimes NA NA
2 -99 NA No NA NA Always Yes
3 Yes NA Yes NA NA NA NA
4 -99 NA NA No NA Yes No
5 NA -99 NA NA NA Always NA
6 -99 NA NA No NA NA NA') %>% mutate_all(as.character)
这是我想要的输出:
dat_out <- read_table('ID Q2_1 Q2_2 Q14_1 Q15
1 Yes NA Sometimes NA
2 No NA Always Yes
3 Yes NA NA NA
4 -99 No Yes No
5 NA -99 Always NA
6 -99 No NA NA')
当前解 我知道我可以单独替换这些列中的每一列,但我有很多列要处理,我想使用一种聪明的 dplyr/grepl 方法来解决这个问题!有任何想法吗?我总是用 Q*.y 替换 Q*.x。
org_dat %>% mutate(Q2_1.x = case_when(!is.na(Q2_1.y) &
Q2_1.x == '-99'| is.na(Q2_1.x) ~ Q2_1.y,
TRUE ~ Q2_1.x)) %>%
mutate(Q2_2.x = case_when(!is.na(Q2_2.y) &
Q2_2.x == '-99'| is.na(Q2_2.x) ~ Q2_2.y,
TRUE ~ Q2_2.x)) %>%
mutate(Q14_1.x = case_when(!is.na(Q14_1.y) &
Q14_1.x == '-99'| is.na(Q14_1.x) ~ Q14_1.y,
TRUE ~ Q14_1.x)) %>%
rename(Q2_1 = Q2_1.x,
Q2_2 = Q2_2.x,
Q14_1 = Q14_1.x) %>%
select(-matches("x|y"))
更短的方法。只需去掉所有变量名的 ".x"
后缀,然后转换名称不是 "ID"
或不以 ".y"
结尾的变量。对于这些变量中的每一个,get0
具有 ".y"
后缀的对应项并按如下方式进行替换。请注意,如果没有带有 ".y"
后缀的对应项,则 get0
returns NULL
和 idx
将折叠为 integer(0)
。结果,返回变量 as-is.
library(dplyr)
ord_dat %>%
rename_with(~sub("\.x", "", .), ends_with(".x")) %>%
transmute(ID, across(!ID & !ends_with(".y"), ~{
.y <- get0(paste0(cur_column(), ".y"))
idx <- which(.x %in% c("-99", NA) & !is.na(.y))
replace(.x, idx, .y[idx])
}))
这是一个 tidyverse 方法。我们会
pivot_longer
数据集分为四列:ID
、Q
(问题)、x
、y
、- 在
x
显示NA
或"-99"
但y
显示非NA
值的位置替换x
中的任何值. - 删除列
y
和pivot_wider
名称来自Q
且值来自x
. 的数据集
步骤并不复杂,但确实需要对功能进行精细控制。这使得代码有点长:
library(dplyr)
library(tidyr)
ord_dat %>%
pivot_longer(
-ID,
names_to = c("Q", ".value"),
names_pattern = "([^\.]*)\.?([^\.]*)",
names_transform = list(.value = ~replace(., . == "", "x"))
) %>%
mutate(x = {
idx <- which(x %in% c("-99", NA) & !is.na(y))
replace(x, idx, y[idx])
}, y = NULL) %>%
pivot_wider(names_from = Q, values_from = x)
输出
# A tibble: 6 x 5
ID Q2_1 Q2_2 Q14_1 Q15
<chr> <chr> <chr> <chr> <chr>
1 1 Yes NA Sometimes NA
2 2 No NA Always Yes
3 3 Yes NA NA NA
4 4 -99 No Yes No
5 5 NA -99 Always NA
6 6 -99 No NA NA
这里答案的关键是首先用 na_if
将 user-defined NA 翻译成真正的 nas,然后 coalesce
和成对的列。
library(dplyr)
library(stringr)
org_dat %>%
na_if(-99) %>%
mutate(across(ends_with('.x'),
~coalesce(.x, get(deparse(substitute(.x)) %>%
str_replace('\.x', '.y'))))) %>%
select(-ends_with('.y')) %>%
rename_with(~str_remove(.x, '\..$'))
# A tibble: 6 × 5
ID Q2_1 Q2_2 Q14_1 Q15
<chr> <chr> <chr> <chr> <chr>
1 1 Yes NA Sometimes NA
2 2 No NA Always Yes
3 3 Yes NA NA NA
4 4 NA No Yes No
5 5 NA NA Always NA
6 6 NA No NA NA
编辑
原始答案没有提供实际所需的输出,因为它用 NA 替换了所有 user-defined NA (-99)。
如果OP想保留这些用户定义的NA,我们可以这样做:
首先,将所有列更改为字符。
其次,将 data.frame 拆分为由前缀“Q{number}_{number}”与 split.default
配对的数据帧。
最后,modify
所有具有两列('x' 和 'y' 对)的列表元素 modify_if
和 coalesce
。
library(dplyr)
library(purrr)
org_dat %>%
mutate(across(everything(), as.character)) %>%
split.default(sub('\..$', '', names(org_dat))) %>%
modify_if(.p=~ncol(.x)==2, .f = ~coalesce(.x[[1]], .x[[2]])) %>%
bind_cols() %>%
select(ID, Q2_1, Q2_2, Q14_1, Q15)
# A tibble: 6 × 5
ID Q2_1 Q2_2 Q14_1 Q15
<chr> <chr> <chr> <chr> <chr>
1 1 Yes NA Sometimes NA
2 2 -99 NA Always Yes
3 3 Yes NA NA NA
4 4 -99 No Yes No
5 5 NA -99 Always NA
6 6 -99 No NA NA