Замена подстроки во фрейме данных на основе справочной таблицы

В качестве входных данных я получил большой фрейм данных в 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, основываясь на других вопросах о переполнении стека, но безрезультатно.

Фактический фрейм данных и справочная таблица намного больше, поэтому было бы полезно масштабируемое решение.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
71
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Разделите данные точкой с запятой, объедините их с таблицей поиска и сверните имена в строку, разделенную точкой с запятой.

Предполагая, что фрейм данных называется 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))

Это решение также очень краткое и быстрое, чем ответ с использованием замены строки. Если между подстроками есть фиксированный разделитель («;» в моем примере), это кажется лучшим решением.

Moehrengulasch 17.07.2024 15:36

Это то, что вы ищите?.

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 

Принято, поскольку это кажется наиболее кратким и общим решением. Это медленнее, чем решение на основе соединения , приведенное ниже, но не требует фиксированного разделителя между подстроками.

Moehrengulasch 17.07.2024 15:34

Об этом тоже стоит помнить: stackoverflow.com/questions/77198098/…

user63230 22.07.2024 11:50

Используйте 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"))

Другие вопросы по теме