#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. Не могли бы вы
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"))