В качестве входных данных я получил большой фрейм данных в R со списками строк разной длины, ссылающихся на определенные коды, например:
glt.code glt.phylogeny
1 adha1238 adha1238
2 adiv1239 adiv1239
3 adiw1235 adiw1235
4 aerr1238 jikr1238;jikr1238;aerr1238
Я хотел бы заменить коды в столбце glt.phylogeny
на основе их названий в этой справочной таблице:
code name level
1 adha1238 Adhari language
2 adiv1239 Kotia-Adivasi Oriya-Desiya language
3 adiw1235 Adiwasi Garasia language
4 aerr1238 Aer language
5 jikr1238 Jikrio Aer dialect
Мой желаемый результат выглядит так:
glt.code glt.phylogeny.names
1 adha1238 Adhari
2 adiv1239 Kotia-Adivasi Oriya-Desiya
3 adiw1235 Adiwasi Garasia
4 aerr1238 Jikrio Aer;Jikrio Aer;Aer
Я хотел бы найти конвейерное (dplyr) решение, заменяющее все подстроки в столбце фрейма данных на основе справочной таблицы. Я экспериментировал с использованием str_replace_all
и stri_replace_all_fixed
, основываясь на других вопросах о переполнении стека, но безрезультатно.
Фактический фрейм данных и справочная таблица намного больше, поэтому было бы полезно масштабируемое решение.
Разделите данные точкой с запятой, объедините их с таблицей поиска и сверните имена в строку, разделенную точкой с запятой.
Предполагая, что фрейм данных называется df1
и df2
, вы можете сделать:
library(dplyr)
library(tidyr)
df1 %>%
separate_longer_delim(glt.phylogeny, ";") %>%
left_join(df2, join_by(glt.phylogeny == code)) %>%
summarise(name = paste0(name, collapse = ";"), .by = glt.code)
# glt.code name
#1 adha1238 Adhari
#2 adiv1239 Kotia-Adivasi Oriya-Desiya
#3 adiw1235 Adiwasi Garasia
#4 aerr1238 Jikrio Aer;Jikrio Aer;Aer
данные
df1 <- structure(list(glt.code = c("adha1238", "adiv1239", "adiw1235",
"aerr1238"), glt.phylogeny = c("adha1238", "adiv1239", "adiw1235",
"jikr1238;jikr1238;aerr1238")), class = "data.frame", row.names = c(NA, -4L))
df2 <- structure(list(code = c("adha1238", "adiv1239", "adiw1235", "aerr1238",
"jikr1238"), name = c("Adhari", "Kotia-Adivasi Oriya-Desiya",
"Adiwasi Garasia", "Aer", "Jikrio Aer"), level = c("language",
"language", "language", "language", "dialect")),
class = "data.frame", row.names = c(NA, -5L))
Это то, что вы ищите?.
library(dplyr)
library(stringr)
df1 <- tibble(
glt.code = c("adha1238", "adiv1239", "adiw1235", "aerr1238"),
glt.phylogeny = c("adha1238", "adiv1239", "adiw1235", "jikr1238;jikr1238;aerr1238")
)
df2 <- tibble(
code = c("adha1238", "adiv1239", "adiw1235", "aerr1238", "jikr1238"),
name = c("Adhari", "Kotia-Adivasi Oriya-Desiya", "Adivasi Garasia", "Aer", "Jikrio Aer")
)
# Function to replace codes with names
replace_codes_with_names <- function(codes, lookup_table) {
codes_list <- str_split(codes, ";")[[1]]
names_list <- lookup_table$name[match(codes_list, lookup_table$code)]
paste(names_list, collapse = ";")
}
# desired output
desired_output <- df1 %>%
rowwise() %>%
mutate(glt.phylogeny.names = replace_codes_with_names(glt.phylogeny, df2)) %>%
ungroup()
Я думаю, что это даст вам то, что вы хотите, используя str_replace_all
, извлекая именованный вектор из вашей таблицы поиска:
library(tidyverse)
# data
df <- tibble(
glt.code = c("adha1238", "adiv1239", "adiw1235", "aerr1238"),
glt.phylogeny = c("adha1238", "adiv1239", "adiw1235", "jikr1238;jikr1238;aerr1238")
)
df_look_up <- tibble(
code = c("adha1238", "adiv1239", "adiw1235", "aerr1238", "jikr1238"),
name = c("Adhari", "Kotia-Adivasi Oriya-Desiya", "Adivasi Garasia", "Aer", "Jikrio Aer"),
level = c("language",
"language", "language", "language", "dialect")
)
# create named vector
named_look_up_vector <- df_look_up %>%
pull(name, code)
# use str_replace_all
df %>%
mutate(glt.phylogeny = str_replace_all(glt.phylogeny, named_look_up_vector))
# # A tibble: 4 × 2
# glt.code glt.phylogeny
# <chr> <chr>
# 1 adha1238 Adhari
# 2 adiv1239 Kotia-Adivasi Oriya-Desiya
# 3 adiw1235 Adivasi Garasia
# 4 aerr1238 Jikrio Aer;Jikrio Aer;Aer
Принято, поскольку это кажется наиболее кратким и общим решением. Это медленнее, чем решение на основе соединения , приведенное ниже, но не требует фиксированного разделителя между подстроками.
Об этом тоже стоит помнить: stackoverflow.com/questions/77198098/…
Используйте purrr::map
на кодах strsplit
, затем match
имя с кодом.
library(dplyr)
df %>%
summarize(glt.phylogeny.names = purrr::map(strsplit(glt.phylogeny, ";"), ~
paste0(loup$name[match(.x, loup$code)], collapse = ";")), .by = glt.code)
выход
glt.code glt.phylogeny.names
1 adha1238 Adhari
2 adiv1239 Kotia-Adivasi Oriya-Desiya
3 adiw1235 Adiwasi Garasia
4 aerr1238 Jikrio Aer;Jikrio Aer;Aer
Если производительность является проблемой, попробуйте data.table
. Эквивалентный подход может быть
library(data.table)
setDT(df)
df[, .(glt.phylogeny.names = sapply(strsplit(glt.phylogeny, ";"), \(x)
paste0(loup$name[match(x, loup$code)], collapse = ";"))), by = glt.code]
glt.code glt.phylogeny.names
<char> <char>
1: adha1238 Adhari
2: adiv1239 Kotia-Adivasi Oriya-Desiya
3: adiw1235 Adiwasi Garasia
4: aerr1238 Jikrio Aer;Jikrio Aer;Aer
df <- structure(list(glt.code = c("adha1238", "adiv1239", "adiw1235",
"aerr1238"), glt.phylogeny = c("adha1238", "adiv1239", "adiw1235",
"jikr1238;jikr1238;aerr1238")), class = "data.frame", row.names = c("1",
"2", "3", "4"))
loup <- structure(list(code = c("adha1238", "adiv1239", "adiw1235",
"aerr1238", "jikr1238"), name = c("Adhari", "Kotia-Adivasi Oriya-Desiya",
"Adiwasi Garasia", "Aer", "Jikrio Aer"), level = c("language",
"language", "language", "language", "dialect")), class =
"data.frame", row.names = c("1", "2", "3", "4", "5"))
Это решение также очень краткое и быстрое, чем ответ с использованием замены строки. Если между подстроками есть фиксированный разделитель («;» в моем примере), это кажется лучшим решением.