Замена строки во фрейме данных на основе другого фрейма данных

#r #string #dataframe #replace #str-replace

Вопрос:

Проблема

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

Вот образец моих данных:

 structure(list(text = c("@Rod comentem aqui utilizando  #BrequeDosApps #AmanhaTemBrequedosApps  nNão pode ser só as tags sozinhas pq vira spam!!", 
"@Roderick #BrequeDosApps ✊🏿", "@Rodson E ai pessoal vamos levantar a hastag #BrequeDosApps"
), screen_names = c("@Rod", "@Roderick", "@Rodson")), spec = structure(list(
    cols = list(text = structure(list(), class = c("collector_character", 
    "collector")), screen_names = structure(list(), class = c("collector_character", 
    "collector"))), default = structure(list(), class = c("collector_guess", 
    "collector")), delim = ","), class = "col_spec"), problems = <pointer: 0x7f9cd0ae72e0>, row.names = c(NA, 
-3L), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"))
 

Я создал фрейм данных с двумя столбцами: 1) все твиты обрабатывают «@имя пользователя» 2) все подстановки для анонимизации. Я должен заменить все дескрипторы из самого текста и из столбца screen_name. Вот образец моей таблицы подстановок:

 structure(list(screen_names = c("@Rod", "@Roderick", "@Rodson"
), new_names = c("@7cdb6a2e", "@766b33e3", "@1c90c952")), row.names = c(NA, 
-3L), class = c("tbl_df", "tbl", "data.frame"))
 

Решение (не работает)

Я пытался stri_replace_all_fixed . Фактические команды были

 sample_tweets2$screen_names <- stringi::stri_replace_all_fixed(str = sample_tweets2$screen_names, pattern = df.substitute$screen_names,replacement = df.substitute$new_names, vectorize_all = FALSE)

sample_tweets2$text <- stringi::stri_replace_all_fixed(str = sample_tweets2$text, pattern = df.substitute$screen_names,replacement = df.substitute$new_names, vectorize_all = FALSE)
 

Проблема в том, что он заменяет все дескрипторы, @Rod* используя их в качестве regex шаблона, а не в точности на букву mach, поэтому строка дескриптора @Roderick заканчивается как @7cdb6a2eerick, а не как @766b33e3, как в моей исходной таблице подстановок. Вот пример:

 structure(list(text = c("@Rod comentem aqui utilizando  #BrequeDosApps #AmanhaTemBrequedosApps  nNão pode ser só as tags sozinhas pq vira spam!!", 
"@Roderick #BrequeDosApps ✊🏿", "@Rodson E ai pessoal vamos levantar a hastag #BrequeDosApps"
), screen_names = c("@7cdb6a2e", "@7cdb6a2eerick", "@7cdb6a2eson"
)), spec = structure(list(cols = list(text = structure(list(), class = c("collector_character", 
"collector")), screen_names = structure(list(), class = c("collector_character", 
"collector"))), default = structure(list(), class = c("collector_guess", 
"collector")), delim = ","), class = "col_spec"), problems = <pointer: 0x7f9cd0ae72e0>, row.names = c(NA, 
-3L), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"))
 

Некоторые осложнения:

  1. Иногда один и тот же дескриптор содержит более одного твита, поэтому он много раз присутствует в столбце имя экрана.
  2. Абсолютно необходимо сохранить текстовую колонку, потому что это основной источник для лингвистического анализа.
  3. Маркеры должны быть сохранены в тексте анонимно

Пожалуйста, мы будем признательны за любую помощь.

Комментарии:

1. Не могли бы вы merge(sampletweets2, df.substitute, by = "screen_names") объединить две таблицы, а затем удалить поля, которые вам не нужны, из результата?

2. Привет. Спасибо. Я отлично работаю для столбца screen_name, но как я должен работать с текстовым столбцом?

3. Возможно, вы могли бы использовать gsub() , чтобы удалить все слова, которые начинаются с @ ? например gsub("@\w *", "", sampletweets2$text)

4. Это очень хорошая идея, но дескрипторы должны быть сохранены в тексте анонимно для анализа.

5. Привет @RodLL, ты смог это понять?

Ответ №1:

Вы можете использовать setNames и str_replace_all таким образом:

 subs <- setNames(df2$new_names, df2$screen_names)
library(stringr)
str_replace_all(df1$screen_names, subs)
 

Данные:

 df1 <- structure(list(text = c("@Rod comentem aqui utilizando  #BrequeDosApps #AmanhaTemBrequedosApps  nNão pode ser só as tags sozinhas pq vira spam!!", 
                        "@Roderick #BrequeDosApps ✊🏿", "@Rodson E ai pessoal vamos levantar a hastag #BrequeDosApps"
), screen_names = c("@Rod", "@Roderick", "@Rodson")), spec = structure(list(
  cols = list(text = structure(list(), class = c("collector_character", 
                                                 "collector")), screen_names = structure(list(), class = c("collector_character", 
                                                                                                           "collector"))), default = structure(list(), class = c("collector_guess", 
                                                                                                                                                                 "collector")), delim = ","), class = "col_spec"), row.names = c(NA, -3L), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"))

df2 <-   structure(list(screen_names = c("@Rod", "@Roderick", "@Rodson"
  ), new_names = c("@7cdb6a2e", "@766b33e3", "@1c90c952")), row.names = c(NA, 
                                                                          -3L), class = c("tbl_df", "tbl", "data.frame"))
 

Ответ №2:

Это заменяет всю конфиденциальную информацию с screen_names ваших анонимных имен и text с ваших анонимных имен:

 df2 <- merge(df, lookup, by = "screen_names")
df2$text2 <- gsub("@\w  *", "df2$new_names",  df2$text)

# Drop sensitive information
df3 <- df2[,setdiff(names(df2), c("screen_names", "text")]
 

Данные:

 df <- data.frame(
  screen_names = c("@Rod", "@Roderick", "@Rodson"),
  text = c("@Rod comentem aqui utilizando  #BrequeDosApps #AmanhaTemBrequedosApps  nNão pode ser só as tags sozinhas pq vira spam!!", "@Roderick #BrequeDosApps", "@Rodson E ai pessoal vamos levantar a hastag #BrequeDosApps"))

lookup <- data.frame(
  screen_names = c("@Rod", "@Roderick", "@Rodson"),
  new_names = c("@7cdb6a2e", "@766b33e3", "@1c90c952"))