【问题标题】:Extracting multiple phrases from multiple PDF's simultaneously using R使用 R 同时从多个 PDF 中提取多个短语
【发布时间】:2020-01-31 18:29:23
【问题描述】:

我在一张表中有一个 pdf 路径列表,我正在尝试对列出的其余 pdf 重复以下命令。基本上我只是将pdf文件转换为文件第一页的文本,然后使用keyword_search命令对该页面中的某些短语进行搜索。我可以一次成功完成一个文件,但我有 281 个文件。我错过了什么??

一个 PDF 文件

    my.file<-"//.../cover-letter.pdf"
    my.page<-pdf_text(my.file)[1] %>% as.character()
    my.result<-keyword_search(my.page, keyword = c('reason','not being marketed', 'available for sale', 'withdrawn from sale', 'commercial distribution', 'target date'), ignore_case = TRUE)
    my.result$Cover_Letter<-my.file
    
    my.result<-select(my.result, -5)
    result<-merge(TotNoMark_clean, my.result, by = "Cover_Letter", all.x = TRUE)

多个 PDF 文件:尝试失败


DF<-as.data.frame(TotNoMark_clean)
file.names<-DF$Cover_Letter

for(i in 1:length(file.names)){
  {pdf_pages<-pdf_text(file.names[i])[1]
  pdf_result<-keyword_search(pdf_pages, keyword = c('reason','not being marketed', 'available for sale', 'withdrawn from sale', 'commercial distribution', 'target date'))
  pdf_result$Cover_Letter<-file.names[i]
  if (!nrow(pdf_result)) {next}
  }
  Result<<-pdf_result
}
Result<-select(Result, -5)
Result<-merge(DF, Result, by = "Cover_Letter", all.x = TRUE)

这是我收到的错误消息:

    "Error in `$<-.data.frame`(`*tmp*`, "Cover_Letter", value = "//cover-letters/***.pdf") : 
  replacement has 1 row, data has 0"

【问题讨论】:

    标签: r for-loop lapply pdftools


    【解决方案1】:

    目前,即使您使用范围运算符&lt;&lt;-,您的 Result 也不会仅保留过去的迭代,因为您不使用列表或在循环中增长对象(后者是不明智的)。实际上你确实需要&lt;&lt;-,因为for 循环不在本地而是在全局对象上运行。如果您的最后一项有空行,next 将导致 Result 为空。

    考虑构建一个数据帧列表,然后在外部循环中运行bind_rows 以获得最终输出:

    DF <- as.data.frame(TotNoMark_clean)
    # INITIALIZE EMPTY LIST
    Result_dfs <- vector(mode="list", length=nrow(DF))
    
    for(i in seq_along(DF$Cover_Letter)) {
      pdf_pages <- pdf_text(DF$Cover_Letter[i])[1]
      pdf_result <- keyword_search(pdf_pages, 
                                   keyword = c('reason','not being marketed', 'available for sale', 
                                               'withdrawn from sale', 'commercial distribution', 
                                               'target date'))
      pdf_result$Cover_Letter <- DF$Cover_Letter[i]
    
      # SAVE TO LIST REGARDLESS OF NROWs 
      Result_dfs[i] <- pdf_result
    }
    
    # BIND ALL DFs TOGETHER AND SELECT LAST FIVE COLS
    Result <- dplyr::select(dplyr::bind_rows(Result_dfs), -5)
    
    # MERGE TO ORIGINAL
    Result <- merge(DF, Result, by = "Cover_Letter", all.x = TRUE)
    

    或者,使用lapply 来避免初始化列表和分配列表项的簿记:

    DF <- as.data.frame(TotNoMark_clean)
    
    Result_dfs <- lapply(DF$Cover_Letter, function(f) {
        pdf_pages <- pdf_text(f)[1]
        pdf_result <- keyword_search(pdf_pages, 
                                     keyword = c('reason','not being marketed', 'available for sale', 
                                                 'withdrawn from sale', 'commercial distribution', 
                                                 'target date'))
        pdf_result$Cover_Letter <- f
        return(pdf_result)
    })
    
    # BIND ALL DFs TOGETHER AND SELECT LAST FIVE COLS
    Result <- dplyr::select(dplyr::bind_rows(Result_dfs), -5)
    
    # LEFT JOIN TO ORIGINAL
    Result <- dplyr::left_join(DF, Result, by="Cover_Letter")
    

    【讨论】:

    • 我最终和我的一个朋友一起解决了这个问题。但是,是的,这就是问题所在。感谢您抽出宝贵时间回复!
    • 为什么这个解决方案不起作用?请告知任何错误。它遵循您的单个 PDF 文件流程。
    • 昨天我自己解决了这个问题,但你建议我使用 bind_rows 函数是正确的。那是主要问题。因为我刚刚看到它,所以我没有机会尝试你的代码。我会尽可能地测试它,我会告诉你的!
    • 所以在您的第一个解决方案中,它仅识别 for 循环中的前 3 个项目,因此 i 的长度为 3。此外,当您在此行中初始化空列表时 '' 'Result_dfs
    • 嗯...没有 3 截断:seq_along(DF$Cover_Letter) 与您的 1:length(file.names) 相同,实际上是 1:length(DF$Cover_Letter)。至于最后一个问题,我认为您将列表的 length 与数据框的 nrow 混淆了。在此处的任一解决方案中,pdf_result任何 行的数据框,但每次迭代将是 一个 数据框分配给列表。确保与您的工作解决方案运行相同的数据,这些数据看起来非常相似但关键字不同,并且没有next 或循环中的增长对象。
    【解决方案2】:

    在我检查以确保适当的字段在正确的类中之后,这就是我最终要做的事情,并且这很有效:

    PhrasePull<-function(){
    DF<-as.data.frame(TotNoMark_clean)
    file.names<-DF$Cover_Letter
    Result<-data.frame()
    for(i in 1:length(file.names)){
        {pdf_pages<-pdf_text(file.names[i])[1]
        pdf_result<-keyword_search(pdf_pages, keyword = c('reason','not being marketed', 'has not marketed', 'will be able to market', 'will market', 'is not marketing', 'available for sale', 'withdrawn from sale', 'commercial marketing', 'commercial distribution', 'target date', 'will be available', 'marketing of this product has been started', 'commercially marketed', 'discontinued', 'launch.', 'not currently marketed', 'unable to market', 'listed in the active section of the Orange Book', 'not currently being manufactured or marketed'), ignore_case = TRUE)
        if (!nrow(pdf_result)) {next}
        pdf_result$Cover_Letter<-file.names[i]
        }
      Result <- bind_rows(Result, pdf_result)
      }
    output<<-merge(DF, Result, by = "Cover_Letter", all.x = TRUE)
    }
    

    【讨论】:

    • 你做了我提到的在 R 中不明智的做法:不要在循环中增长对象,例如 bind_rows。理想情况下,您可以按照我的建议,在 tibbles 列表上的循环外运行此 once。否则,它会导致低效、过多的内存复制。此外,避免范围运算符&lt;&lt;-,因为您隐式影响全局环境,因此难以调试。事实上,如果在本地作用域函数中,则不需要使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-02
    • 2013-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多