【问题标题】:How to convert data from pdf files into data frames如何将pdf文件中的数据转换成数据框
【发布时间】:2014-08-06 08:07:04
【问题描述】:

我正在尝试将数据从大量 PDF 文件转换为 R 中的数据框。我一直在使用 read.fwf() 将 PDF 文件转换为 .txt 文件,但问题是宽度所有的 .txt 文件都不相同。有没有办法确定列的宽度,或者有没有办法使用 read.fwf() 以外的函数?

我有大量文件要转换,而且它们都有不同的开头格式,因此查找每个文件的特定列宽变得非常乏味。有没有更有效的方法将数据从 PDF 文件转换为 R 中的数据框?

【问题讨论】:

  • 你能展示一个 PDF 的例子吗?
  • 我不确定您的意思:PDF 是一种编码文件,如果不先转换为某种纯文本文件,您将无法读取其内容。如果您已经这样做了(您发布的示例是不是),那么read.table 将在空格处分隔。
  • 这完全取决于您的输入文件的规则性。如果你能想出一个规则来找到你的表,你可能会让 R 读取它。即使它不是固定宽度,如果列之间至少有两个或三个空格,您也可以将它们转换为制表符并将其读取为分隔符。
  • 嗨,在标记之前花点时间阅读标记摘录。 dataframes 用于熊猫,而您需要 data.frame 在这里。下次小心点。请参阅此元帖子。 Warn [r] users from adding [dataframes] tag instead of [data.frame] tag

标签: r pdf dataframe text-files column-width


【解决方案1】:

这是使用正则表达式的一种可能解决方案。您使用 tm 包中的 readPDF 函数将 PDF 文件转换为文本,将每一行作为文本字符串提供给您。然后使用正则表达式将数据划分为适当的列字段以转换为数据框。

我已将其打包成一个函数,以便您可以读取和解析所有 PDF 文件,并在一次操作中将它们组合成一个数据框。如果您的其他文件具有您发布的文件中不存在的格式特性,那么您需要进行一些调整以使其正常工作。

该代码还会检查一些简单的数据格式问题,并将“错误”行保存在单独的文本文件中,以供以后检查和处理。同样,如果您的其他文件有不同的格式变化,您可能需要对此进行调整。

# Use text-mining package to extract text from PDF files    
library(tm)

# Function to read a PDF file and turn it into a data frame
PDFtoDF = function(file) {
  ## Extract PDF text. Each line of PDF becomes one element of the string vector dat.
  dat = readPDF(control=list(text="-layout"))(elem=list(uri=file), 
                                              language="en", id="id1") 
  dat = c(as.character(dat))

  ## Keep only those strings that contain the data we want. 
  ## These are the ones that begin with a number.
  dat = dat[grep("^ {0,2}[0-9]{1,3}", dat)]

  ## Create separators so we can turn strings into a data frame. We'll use the 
  ## pipe "|" as a separator.

  # Add pipe after first number (the row number in the PDF file)
  dat = gsub("^ ?([0-9]{1,3}) ?", "\\1|", dat)

  # Replace each instance of 2 or more spaces in a row with a pipe separator. This 
  # works because the company names have a single space between words, while data
  # fields generally have more than one space between them. 
  # (We just need to first add an extra space in a few cases where there's only one
  # space between two data fields.)
  dat = gsub("(, HVOL )","\\1 ", dat)
  dat = gsub(" {2,100}", "|", dat)

  ## Check for data format problems
  # Identify rows without the right number of fields (there should 
  # be six pipe characters per row) and save them to a file for 
  # later inspection and processing (in this case row 11 of the PDF file is excluded))
  excludeRows = lapply(gregexpr("\\|", dat), function(x) length(x)) != 6
  write(dat[excludeRows], "rowsToCheck.txt", append=TRUE)

  # Remove the excluded rows from the string vector
  dat = dat[!excludeRows]

  ## Convert string vector to data frame 
  dat = read.table(text=dat, sep="|", quote="", stringsAsFactors=FALSE)
  names(dat) = c("RowNum", "Reference Entity", "Sub-Index", "CLIP", 
                  "Reference Obligation", "CUSIP/ISIN", "Weighting")
  return(dat)
}

# Create vector of names of files to read
files = list.files(pattern="CDX.*\\.pdf")

# Read each file, convert it to a data frame, then rbind into single data frame
df = do.call("rbind", lapply(files, PDFtoDF))

# Sample of data frame output from your sample file
df
    RowNum    Reference Entity    Sub-Index      CLIP           Reference Obligation   CUSIP/ISIN Weighting
1        1         ACE Limited          FIN 0A4848AC9     ACE-INAHldgs 8.875 15Aug29    00440EAC1     0.008
2        2           Aetna Inc.         FIN 0A8985AC5     AET 6.625 15Jun36 BondCall    00817YAF5     0.008
3        3           Alcoa Inc.  INDU, HVOL 014B98AD5                AA 5.72 23Feb19    013817AP6     0.008

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-19
    • 1970-01-01
    相关资源
    最近更新 更多