У меня есть следующий фрейм данных под названием result
.
Я пытаюсь заменить все разные формы одного и того же тега правильным. Например, замените все PIPPIP и PIPpip на Pippip или Berbar на Barbar. Для этого я использую функцию mutate
с left_join
на основе требуемого файла с именем tesaurus
, в котором есть столбец со всеми возможными случаями одного и того же тега (tag_id) и столбец с правильным (tag_ok), который выглядит следующим образом:
Я использую следующий код.
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 (в одном случае два тега)
Как я могу это исправить?
Мы могли бы сделать это так:
Примечание. Я думаю, что в тезаурусе Barbar
в tag_id должно быть Berbar
:
tesaurus <- structure(list(tag_id = c("PYPPYP", "PIPpip", "Pippip", "Barbar",
"BerBar"), tag_ok = c("Pippip", "Pippip", "Pippip", "Barbar",
"Barbar")), class = "data.frame", row.names = c(NA, -5L))
данные:
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()) %>%
group_by(id) %>%
mutate(row = row_number()) %>%
ungroup() %>%
mutate(across(-c(loc, id, row), ~ifelse(str_detect(., paste(tesaurus$tag_id, collapse = "|")),
tesaurus$tag_ok, .)
)) %>%
arrange(id, -row) %>%
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 Pippip NA L5
4 NA Barbar L3
5 NA Pippip, Barbar L3
но таким образом результат в 5-й строке (столбец AUTO.ID) - это просто Пиппип, а ожидаемый должен быть Пиппип, Барбар
Нет, для столбца 5-й строки AUTO.ID ожидаемый результат должен быть Pippip, Barbar, а не Pippip, BarBar.
Хорошо, я только что обновил tesaurus
. Код работает!
Мы могли бы использовать 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
это решение заменяет все столбцы aAUTO.ID и MANUAL.ID на NA
Это не совсем подходит для всех ваших случаев, но я считаю, что стоит упомянуть
str_to_title()
из пакетаstringr
, который правильно изменит все слова на заглавные (заглавные только в первом символе). Если бы у нас не было дополнительных замен, таких какPYPPYP > Pippip
, мы могли бы даже избавиться от необходимости в таблице поиска.