产品战略专家梁宁确认出席AICon北京站,分享AI时代下的商业逻辑与产品需求 了解详情
写点什么

使用 R 和 Amazon Web Services 进行文档分析

  • 2020-04-05
  • 本文字数:4353 字

    阅读完需:约 14 分钟

使用 R 和 Amazon Web Services 进行文档分析

在我们以前的博文中,我们讨论了 R 的基本知识和 AWS 上 R 的常见工作负载对。在这个两篇系列文章的第二篇中,我们将更加深入的探讨如何使用 AWS 服务构建文档处理应用程序。我们将介绍如何将 AWS 与 R 结合使用来创建数据管道,以便从 PDF 中提取数据供以后处理。


在本示例中,我们从 Amazon Simple Storage Service (Amazon S3) 中存储的 PDF 开始,使用 Amazon Textract 提取文本和表格形式的信息,然后将数据上传到 PostgreSQL Amazon Relational Database Service (Amazon RDS) 数据库。我们将使用 Paws AWS 开发工具包从 R 运行时中访问所有这些服务。下图显示了它的工作原理。



对研究人员来说,很难从 PDF 和图像中提取大量有价值的数据来进行分析。例如,SEC Form 10-K 年度财务报告、报纸文章的扫描件、历史文档、FOIA 回应等等。分析它们中的数据在逻辑上是不切实际的,但现在,使用更好的机器学习技术,我们可以开始将它们用作研究的数据源。


在本文的示例中,我们使用的是联邦储备银行制作的包含美国经济历史预测的 PDF 文档,称为 Greenbook 预测(或 Greenbook 数据集)。这些 PDF 由文本组成,中间穿插着表格和图形,额外增加了难度。Greenbook 预测由费城联邦储备银行提供


在本文中,我们假设您已经有包含 PDF 和 Amazon RDS 数据库的现有 S3 存储桶。虽然您可以从 R 内创建这些 AWS 资源,但我们还是建议您使用专为预置基础设施而设计的工具,例如 AWS CloudFormationAWS 管理控制台或 Terraform。


我们还假设您已经配置本地凭证来访问 Amazon Textract。您可以通过导入环境变量并将它们存储在凭证文件中,或者在 EC2 实例或者附加了具有适当权限的 AWS Identity and Access Management (IAM) 角色的容器中运行 R 来实现此配置。如果没有,您必须明确提供凭证;您可以在以前的文章中查看相关文档,并在 Paws 文档中查看明确的说明。

提取文本和表格

众所周知,从 PDF 中提取数据很难。最早的 Greenbook 预测 PDF 是 20 世纪 60 年代编制的原始报告页面的图片。较新的报告使用 PDF 版面语言,但即便如此,PDF 中也没有底层结构,只有位于页面上各个点的字符。


为了从这些 PDF 中获取有用的数据,用户必须使用光学字符识别将文本图片转换为字符(需要时),然后根据这些字符在页面上的位置推断句子、段落和语篇结构。Greenbook 预测中还包含表格。在此,我们需要识别表格的位置,然后根据页面上的单词或数字的位置和间隔来重建表格的行和列。


为执行此操作,我们使用 AWS 托管的 AI 服务 Amazon Textract 从图片和 PDF 中获取数据。借助适用于 R 的 Paws 开发工具包,我们可以使用操作 start_document_text_detection 获取 PDF 文档的文本,并且可使用操作 start_document_analysis 获取文档的表格和表单。


这些操作属于异步操作,这表示,它们将初始化文本检测和文档分析作业,从而返回特定作业的标识符,我们可以对此标识符进行轮询以检查完成状态。作业完成后,我们可以通过传入作业 ID,分别使用第二个操作 get_document_text_detectionget_document_analysis 检索结果。


我们使用以下代码获取单个文档的表格数据。我们告知 Amazon Textract 文档在 S3 存储桶中的位置,Amazon Textract 则会将即将开始的文档分析作业的 ID 返回给我们。然后 Textract 在后台读取文件并执行分析。同时,我们可以继续检查作业是否完成,然后在作业完成后,立即获取结果。


Bash


textract <- paws::textract()
analyze_document <- function(bucket, file) {
# Start analyzing the PDF. resp <- textract$start_document_analysis( DocumentLocation = list( S3Object = list(Bucket = bucket, Name = file) ), FeatureTypes = "TABLES" )
# Check that the analysis is done and get the result. count <- 0 while (count < 30 && (!exists("result") || result$JobStatus == "IN_PROGRESS")) { Sys.sleep(1) result <- textract$get_document_analysis( JobId = resp$JobId ) count <- count + 1 } return(result)}
analysis <- analyze_document("my-bucket", "GS-1966-01-11.pdf")
复制代码


这是一个简化的示例;事实上,我们可能会同时开始所有的文档分析作业,然后再收集所有结果,因为作业可能并行运行。此外,分析结果可能会太大,无法一次性全部发送,您可能需要单独获取额外的部分;文本结尾处提供的完整的源代码列表可处理此情况。


我们从 Textract 文档分析作业中重获的结果将分为多个数据块。对于包含表格的文档,有些数据块为 TABLE 数据块,表的单元格在 CELL 数据块中,而单元格的内容在 WORD 数据块中。您可以在 Textract 表格文档中阅读关于它们的运行方式的更多信息。


现在,我们需要将 Textract 结果转换为我们可以更轻松使用的形状。首先,我们来看看原始形式的表格,及如何通过 Textract 将该表格返回给我们。下面是 1966 年 1 月文档第三部分的表格。



下面是 Textract 分析返回的三个示例数据库:


1.这是此表格的数据块;您可以在下面看到,它的 BlockTypeTABLE,它来自第 3 页(在页面元素中),且在关系下拥有 256 个子数据库(单元格)。


Bash


# List of 13# $ BlockType      : chr "TABLE"# $ Confidence     : num 100# $ Text           : chr(0) # $ RowIndex       : int(0) # $ ColumnIndex    : int(0) # $ RowSpan        : int(0) # $ ColumnSpan     : int(0) # $ Geometry       :List of 2# .. <not shown># $ Id             : chr "c6841638-d3e0-414b-af12-b94ed34aac8a"# $ Relationships  :List of 1# ..$ :List of 2# .. ..$ Type: chr "CHILD"# .. ..$ Ids : chr [1:256] "e1866e80-0ef0-4bdd-a6fd-9508bb833c03" ...# $ EntityTypes    : list()# $ SelectionStatus: chr(0) # $ Page           : int 3
复制代码


2.这是表格第 1 行第 2 列的单元格,如 RowIndexColumnIndex 元素所示。此单元格有一个子数据块。


Bash


# List of 13# $ BlockType      : chr "CELL"# $ Confidence     : num 100# $ Text           : chr(0) # $ RowIndex       : int 1# $ ColumnIndex    : int 2# $ RowSpan        : int 1# $ ColumnSpan     : int 1# $ Geometry       :List of 2# .. <not shown># $ Id             : chr "132b0343-0172-4ddd-bf30-12f133f0f31d"# $ Relationships  :List of 1# ..$ :List of 2# .. ..$ Type: chr "CHILD"# .. ..$ Ids : chr "5734871f-5a7f-460e-a5f5-dd42bbc57a27"# ...
复制代码


3.最后是上述单元格中的单词数据块,其中包含文本 Year。``


Bash


# List of 13# $ BlockType      : chr "WORD"# $ Confidence     : num 99.8# $ Text           : chr "Year"# ...
复制代码


要重建表格,我们使用每个单元格的行和列编号合并表格中的所有单元格。下面的代码可执行此操作;它将返回文档中所有表格的列表,每个都以矩阵形式。该代码通过以下操作实现这一点:


  1. 逐个迭代每个表格的单元格

  2. 从单词数据块中提取每个单元格的内容

  3. 将单元格内容插入内存表矩阵中的适当行和列


Bash


get_tables <- function(analysis) {  tables <- list()  blocks <- analysis$Blocks  names(blocks) <- sapply(blocks, function(x) x$Id)
for (block in blocks) {
if (block$BlockType == "TABLE") { cells <- get_children(block, blocks) rows <- max(sapply(cells, function(x) x$RowIndex)) cols <- max(sapply(cells, function(x) x$ColumnIndex)) table <- matrix(nrow = rows, ncol = cols)
# 1.Go through a table's cells one-by-one for (cell in cells) {
# 2.Get the cell's contents words <- get_children(cell, blocks) text <- paste(sapply(words, function(x) x$Text), collapse = " ")
# 3.Insert the cell contents into the matrix row <- cell$RowIndex col <- cell$ColumnIndex table[row, col] <- text } tables <- c(tables, list(table)) } } return(tables)}
tables <- get_tables(analysis)
复制代码


请注意,上面的函数get_children 可获取数据块的子数据库;为了简洁起见,此处予以省略,但显示在本文结尾提供的源代码列表中。


此代码产生类似以下内容的矩阵,这非常好:



要在我们的所有 PDF 上运行这个相同过程,我们只需要从 S3 中获取 PDF 列表,我们可以使用 S3 list_objects 操作获取此列表。然后,我们可以循环处理所有可用的 PDF,并使 Textract 通过多个并行处理作业获取其文本和表格。

将数据上传到数据库

现在,我们已经处理好表格,接下来将它们上传到我们的 PostgreSQL 数据库中,以便稍后进行进一步的下游分析。


在 RDS 上运行的适当配置的 PostgreSQL 服务器支持通过 IAM 进行身份验证,从而无需存储密码。如果我们使用具有适当权限的 IAM 用户或角色,我们可以使用 IAM 身份验证令牌从 R 连接到我们的 PostgreSQL 数据库。Paws 软件包也支持此功能;在 AWS 开源计划的支持下开发的功能。


我们使用 build_auth_token 生成的令牌从 Paws 软件包连接到我们的数据库。


Bash


# Connect to the database using an IAM authentication token.rds <- paws::rds()token <- rds$build_auth_token("myhost:5432", "us-east-1", "david")con <- DBI::dbConnect(    RPostgres::Postgres(),    host = "myhost", port = 5432, dbname = "mydb",    user = "david", password = token)
复制代码


在此连接下,我们将结果上传到数据库中的表格。由于我们从文档中获取的表格不一定都拥有相同的形状,我们将它们上传为 JSON 数据。PostgreSQL 的其中一项功能为,它在本地允许我们将任何形状的数据存储在 JSON 列中。


Bash


# Create rows for each table to insert into the database.database_rows <- data.frame(  document = "GS-1966-01-11.pdf",  table_num = 1:length(tables),  data = sapply(tables, jsonlite::toJSON))
# Store the tables in the database.DBI::dbAppendTable(con, name = "tables", value = database_rows)
复制代码


现在,数据已在数据库中,我们可以轻松访问它,以便今后进行分析。

后续步骤

在此实现中,由于 R 默认为单线程,一次将处理一个文档(按顺序)。在较为复杂的实现中,我们可以使用 parallelfutures 软件包来并行处理这些文档,或者无需等待每个文档处理完成。由于复杂性增加,我们避免在本文中展示此情况。对于希望增加自动化的人,可以将 S3 文件上传设置为调用下游计算服务(Lambda、ECS)的事件触发器,这些计算服务可以执行此处引用的代码。


本文转载自 AWS 技术博客。


原文链接:https://amazonaws-china.com/cn/blogs/china/using-r-with-amazon-web-services-for-document-analysis/


2020-04-05 08:00531

评论

发布
暂无评论
发现更多内容

苹果手机怎么恢复备份?iOS备份恢复教程

茶色酒

苹果手机备份

imazing是什么软件?

茶色酒

imazing

Docker下,极速体验pinpoint1.6.3

程序员欣宸

Java 分布式 4月月更

想学习算法交易的工程师们,机会来啦~

非凸科技

rust 招聘 基金 量化交易 算法交易

[Day24]-[二叉树] 相同树

方勇(gopher)

LeetCode 二叉树 DFS BFS 数据结构算法

Spark SQL 字段血缘在 vivo 互联网的实践

vivo互联网技术

大数据 spark Sparksql 数据处理

18 张图,一文了解 8 种常见的数据结构

爱好编程进阶

Java 程序员 后端开发

字节跳动构建Data Catalog数据目录系统的实践

字节跳动数据平台

数据库 字节跳动 数据治理 数据目录

云原生训练营学习总结

arctec

丙午篇 「準佛」 《「內元宇宙」聯載》

因田木

陰陽五行

聊聊Kotlin中的lambda

北洋

kotlin Andriod 4月月更

13W字!2021最新发布互联网大厂高频面试技术点!

爱好编程进阶

Java 程序员 后端开发

imazingAPP软件怎么安装到苹果手机电脑上面?

茶色酒

imazing

什么是瀑布开发?适用于哪些场景?有哪些瀑布开发管理系统?

爱吃小舅的鱼

别再用老版云效Projex项目协作了,该升级了

阿里云云效

阿里云 项目管理 研发团队 项目协作 项目协作工具

ThinkPHP6+swoole+easywechat使用教程

CRMEB

一种很爽的学习方法,被我Get到了!

博文视点Broadview

20 数据存储服务器集群的伸缩性设计

爱好编程进阶

Java 程序员 后端开发

2021最新Java学习路线,自学者的福利

爱好编程进阶

Java 程序员 后端开发

微服务与领域驱动设计,架构实践总结

架构 微服务 领域驱动设计 软件架构

华为云大咖带你玩转云原生基础设施之K8s

坚果

4月月更

自己动手写 Docker 系列 -- 6.5 启动时给容器配置网络

Go Docker 4月月更

C语言总结_数组全方位练习

DS小龙哥

4月月更

大数据培训Spark SQL底层执行流程

@零度

Sparksql 大数据开发

微信小程序开发系列 (四) :微信小程序的页面跳转路由设计

汪子熙

微信小程序 微信 前端开发 微信开发 4月月更

基于语义感知SBST的API场景测试智能生成

华为云开发者联盟

测试 语义感知 SBST 动态修正 ODG图

2021最新一次Java面试,快手三面一轮游,如今已拿意向书

爱好编程进阶

Java 程序员 后端开发

云原生训练营 -Week10

jjn0703

云原生训练营

Go 语言入门很简单:正则表达式

宇宙之一粟

正则表达式 Go 语言 4月月更

《Mybatis 手撸专栏》第6章:数据源池化技术实现

小傅哥

Java 面试 小傅哥 mybatis 源码学习

小平邦彦:树懒style的世界一流数学家

图灵教育

数学 数学史 数学家

使用 R 和 Amazon Web Services 进行文档分析_文化 & 方法_亚马逊云科技 (Amazon Web Services)_InfoQ精选文章