我有以下称为
result
的数据框。
手册.ID | 自动识别 | loc |
---|---|---|
NA | PYPPYP | L2 |
PIPpip | NA | L1 |
野蛮人 | NA | L5 |
NA | 皮皮 | L3 |
NA | 皮皮,BerBar | L3 |
我尝试用正确的标签替换同一标签的所有不同形式。例如,将所有 PIPPIP 和 PIPpip 替换为 Pippip 或将 Berbar 替换为 Barbar。为此,我根据名为
mutate
的所需文件使用带有 left_join
的 tesaurus
函数,该文件包含包含相同标签(tag_id)所有可能情况的列和包含正确标签(tag_ok)的列看起来像这样:
tag_id | tag_ok |
---|---|
PYPPYP | 皮皮 |
PIPpip | 皮皮 |
皮皮 | 皮皮 |
野蛮人 | 野蛮人 |
BerBar | 野蛮人 |
我使用以下代码。
library("plyr")
library("dplyr")
library("reshape")
library("data.table")
library("stringr")
library("tidyr")
library("openxlsx")
tesaurus <- read.xlsx("Requested_files/sp_tesaurus.xlsx", sheet = "tesaurus") %>%
select(-bat_sp)
result <- result %>%
left_join(tesaurus, by = c(MANUAL.ID = "tag_id")) %>%
mutate(MANUAL.ID = coalesce(tag_ok, MANUAL.ID)) %>%
select(-tag_ok) %>%
left_join(tesaurus, by = c(AUTO.ID = "tag_id")) %>%
mutate(AUTO.ID = coalesce(tag_ok, AUTO.ID)) %>%
select(-tag_ok)
此代码适用于 MANUAL.ID 列,但适用于 AUTO.ID 列,因为特殊情况:Pippip,BerBar(一种情况下有两个标签)
我该如何解决?
我们可以将
str_replace_all
与命名向量一起使用
library(dplyr)
library(stringr)
library(tibble)
df %>%
mutate(across(ends_with("ID"), ~ str_replace_all(.x, deframe(tesaurus))))
-输出
MANUAL.ID AUTO.ID loc
1 <NA> Pippip L2
2 Pippip <NA> L1
3 Barbar <NA> L5
4 <NA> Pippip L3
5 <NA> Pippip,Barbar L3
我们可以这样做: Note我认为在tesaurus
Barbar
中的tag_id应该是Berbar
:
注意 看看@akrun 的解决方案,它更优雅但一开始很难掌握。但是想法很巧妙,我们必须将双列数据框视为命名向量,第一列为名称,第二列为值,我们可以用 akrun 提供的更优雅的方式来实现它:
tesaurus <- structure(list(tag_id = c("PYPPYP", "PIPpip", "Pippip", "Berbar"
), tag_ok = c("Pippip", "Pippip", "Pippip", "Barbar")), class = "data.frame", row.names = c(NA,
-4L))
数据:
df <- structure(list(MANUAL.ID = c(NA, "PIPpip", "Barbar", NA, NA),
AUTO.ID = c("PYPPYP", NA, NA, "Pippip", "Pippip,BerBar"),
loc = c("L2", "L1", "L5", "L3", "L3")), class = "data.frame", row.names = c(NA,
-5L))
解决方案:
library(dplyr)
library(stringr)
library(tidyr)
df %>%
mutate(id = row_number()) %>%
separate_rows(everything()) %>%
mutate(across(-c(id, loc), ~ifelse(str_detect(., paste(tesaurus$tag_id, collapse = "|")),
tesaurus$tag_ok, .)
)) %>%
summarise(across(everything(), ~toString(., na.rm=TRUE)), .by = c(id, loc)) %>%
mutate(across(-c(id, loc), ~ifelse(str_detect(., "NA"), NA_character_, .))) %>%
select(contains("ID"), loc, -id)
MANUAL.ID AUTO.ID loc
<chr> <chr> <chr>
1 NA Pippip L2
2 Pippip NA L1
3 Barbar NA L5
4 NA Barbar L3
5 NA Pippip, BerBar L3