【问题标题】:R, stringr, mutate (I think) - multiple partial string replacements in multiple stringsR,stringr,mutate(我认为) - 多个字符串中的多个部分字符串替换
【发布时间】:2020-12-14 12:34:45
【问题描述】:

我是文本挖掘、R 和 tidy 方法的新手,我正在寻找善意的建议来克服从 pdf 文件中读取的预处理文本字符串的障碍。具体问题是对多个字符串进行多个字符串替换。

我有来自 2 个来源的数据:

  1. PDF 报告:我使用 map 和 pdf_text 函数将 pdf 报告的目录读取到数据框中,该数据框创建了一个包含 3 列的小标题:page_string、文件名和页码。有 1,191 个条目,page_string 包含一个字符串,即一页 pdf 文本。
  2. 专业单词和替换的CSV文件:我使用了read_CSV函数来导入这个。生成的 df 有 2 列,包含 77 个条目:target_vocab(例如 social worker)和 replace_token(例如 social_worker)。

我的目标是修改主数据框中的当前字符串,在标记化之前将与 target_vocab 中的专业词匹配的字符串替换为 replace_token 中的相关复合标记。

字符串示例 - 字符串替换前后:

  1. “社会工作者和早期帮助人员与多机构合作伙伴合作,制定由分配的社会工作者领导的有需要的儿童计划”。
  2. “Social_workers 和 early_help 工作人员与多机构合作伙伴合作,制定由分配的 social_worker 领导的 CIN 计划”。

希望很清楚,我希望将“社会工作者”、“早期帮助”、“多机构”、“有需要的孩子”和“社会工作者”替换为复合标记。

我的代码:

#a bank of pdf reports and "professional_words.csv" in current working directory

library(tidyverse)
library(pdftools)
#> Using poppler version 0.73.0
library(tidytext)
library(stringr)

pdf_filenames <- list.files(pattern = "pdf$")

words_df <- read_csv("professional_words.csv", skip = 1, col_names = c("target_vocab", "replace_token"))

pattern_vector <- words_df$target_vocab
replacement_vector <- words_df$replace_token 

pdf_pages_df <- map_df(pdf_filenames, ~ tibble(page_string = pdf_text(.x)) %>%
         mutate(filename = .x, pagenumber = row_number()) %>%
           mutate(page_string = str_replace_all(page_string,pattern_vector,replace_vector))) 

在 map 函数中不起作用的位是:

mutate(page_string = str_replace_all(page_string,pattern_vector,replace_vector)))

我尝试了各种变体,包括 gsub、将其从管道中分离为单独的 map 函数等。但我的知识有限,我没有修复它。

我一直收到警告:

在 stri_replace_all_regex(string, pattern, fix_replacement(replacement), : 更长的对象长度不是 短物体长度的倍数

使用这种代码变体,我也遇到了错误:

mutate() 输入 page_string 存在问题。 x 输入 page_string 不能回收到 10 号。ℹ 输入 page_stringstr_replace_all(page_string, pattern = pattern_vector, replacement = replace_vector)。 ℹ 输入 page_string 的大小必须是 10 或 1,而不是 77。

我的感觉是地图或列表功能会帮助我,但我似乎在兜圈子,我还没有找到帮助我解决问题的 Stack Overflow 响应。

【问题讨论】:

    标签: r tidyverse stringr dplyr readr


    【解决方案1】:

    str_replace_all 来自stringr,有一种方法可以满足您的需求。不提供patternreplacement,而是将命名向量传递给pattern。像pattern = c("social worker" = social_worker", "early help" = "early_help", "multi agency" = "multi_agency") 这样的东西。我将从一个简单的示例开始,然后向您展示如何让R 从您的words_df 构建该命名向量。

    # Simple example
    library(stringr)
    string <- "The quick brown fox"
    str_replace_all(string, pattern = c("brown" = "green", "fox" = "badger"))
    [1] "The quick green badger"
    

    下面是你如何处理一些看起来像你的假数据,让R 构建命名的替换向量。

    # Making the fake data
    words_df <- data.frame(target = c("fox", "brown", "quick"),
                           replacement = c("badger", "green", "versatile"))
    
    strings_df <- data.frame(page_string = c("The quick brown fox",
                                             "The sad yellow fox",
                                             "The quick old dog",
                                             "The lazy brown dog",
                                             "The quick happy fox"))
    
    # Making the named replacement vector from words_df
    replacements <- c(words_df$replacement)
    names(replacements) <- c(words_df$target)
    
    # Doing the replacement
    library(dplyr)
    strings_df %>% 
      mutate(new_string = str_replace_all(page_string, 
                                          pattern = replacements))
    
    # The output
              page_string                 new_string
    1 The quick brown fox The versatile green badger
    2  The sad yellow fox      The sad yellow badger
    3   The quick old dog      The versatile old dog
    4  The lazy brown dog         The lazy green dog
    5 The quick happy fox The versatile happy badger
    

    【讨论】:

    • 非常有帮助。为了我的学习,你能告诉我 names() 是如何工作的吗?当我检查命名向量替换时,我只看到替换词并且目标词不可见。它虽然有效!
    • 如果您使用names(object),它将返回对象的名称(例如,data.frame 中的列名)。如果您使用names(object) &lt;- ,它会将对象的名称设置为您指定的任何名称。
    【解决方案2】:

    str_replace_all 不能这样工作。如果您为patternreplacement 提供向量,则第一个模式/替换将应用于string 的第一个元素,依此类推。请参阅以下示例:

    library(stringr)
    
    fruits <- c("one apple two", "two pears", "three bananas")
    pattern_v <- c("one", "two", "three")
    replace_v <- c("1", "2", "3")
    str_replace_all(fruits, pattern_v, replace_v)
    #> [1] "1 apple two" "2 pears"     "3 bananas"
    

    reprex package (v0.3.0) 于 2020 年 8 月 25 日创建

    请注意,“two”只会在string 的第二个元素中替换为“2”。因此,如果pattern/replacement 向量与string 的长度(或倍数)不同,则它不起作用:

    pattern_v <- c("one", "two")
    replace_v <- c("1", "2")
    str_replace_all(fruits, pattern_v, replace_v)
    [1] "1 apple two"   "2 pears"       "three bananas"
    warning:
    In stri_replace_all_regex(string, pattern, fix_replacement(replacement),  :
      longer object length is not a multiple of shorter object length
    

    为了规避这个问题,你可以为pattern传递一个命名向量:

    str_replace_all(fruits, c("one" = "1", "two" = "2", "three" = "3"))
    [1] "1 apple 2" "2 pears"   "3 bananas"
    

    Ben 的回答提供了一种如何轻松创建矢量的好方法:

    pattern_new <- c("one", "two", "three")
    names(pattern_new) <- c("1", "2", "3")
    str_replace_all(fruits, pattern_new)
    [1] "one apple two" "two pears"     "three bananas"
    

    【讨论】:

    • 我不确定 names() 是如何工作的,但确实如此,这很有帮助。我会将完成的代码发布给其他正在苦苦挣扎的人。
    【解决方案3】:

    由于快速响应,问题得以解决,这里是为那些将来可能会遇到困难的人解决我的问题的工作代码:

    professional_terms <- c(words_df$replace_token)
    names(professional_terms) <- c(words_df$target_words) 
    pdf_pages_df <- map_df(pdf_filenames, ~ tibble(page_string = pdf_text(.x)) %>%
    mutate(filename = .x, pagenumber = row_number(), page_string = str_replace_all(page_string,pattern = professional_terms)))
    

    【讨论】:

      猜你喜欢
      • 2015-03-15
      • 1970-01-01
      • 1970-01-01
      • 2016-09-10
      • 2013-03-14
      • 1970-01-01
      相关资源
      最近更新 更多