大量 docx 文件建议的数据争论!

数据挖掘 Python 类似文件 数据争吵
2021-09-30 16:30:31

我正在寻找一些关于我试图解决的数据争论问题的建议。我花了一周的时间采取不同的方法,但似乎没有什么是完美的。仅供参考,这是我的第一个大型(无论如何对我而言)数据科学项目,所以我真的需要一些智慧来了解处理它的最佳方法。

本质上,我有一组(200 多个)半结构化的 docx 文件。半结构化是指我想要的信息被组织成表格(它是一个表格,不同的表格包含不同的信息要填写),但不幸的是这些表格的格式不一致。有时,人们在向其中输入数据后,他们会不小心按退格键将表格粘在一起。或者有时他们不小心把桌子弄碎了,例如。

我的第一次尝试使用 python-docx 使用 document.tables[0] 等提取数据。然后我可以将其拉入每个文档的大 python 字典中。它非常整洁,但遇到了一个障碍——上面的表格格式问题。

然后我再次使用 python-docx 并尝试使用每个表的标题作为标记(使用正则表达式选择它们)来确定子数据集何时开始或结束,并遍历文档中的所有文本。这种工作,并且更灵活,但是从表格外部拾取大量文本,这使得管理和清理变得困难。

无论如何,我对经验丰富的数据科学家如何解决这个问题很感兴趣。

最终目标是将这些文档之一中的数据提取到 SQL 数据库中。

如果您对此问题感兴趣,请告诉我,我可以将我正在使用的模板文档和一些示例发送给您。如果它有帮助,我还可以发布我到目前为止编写的代码(因为它很长,所以没有这样做)。

2个回答

docx 文件的一个大问题是它们有大量与格式相关的内容,大多数人在抓取 docx 文件时发现这些内容是不敬的。因此,一种方法是将 docx 文件转换为更友好的文件,例如排除所有不相关位的 json,然后使用现有框架(如JSON schema进行模式匹配和jmespath进行数据提取)。有一个名为simple -docx的 python 包,用于将 Docx 文件转换为 JSON,还有一个玩具网站,您可以在其中试用。(免责声明:我是两者的作者)

这个问题已经在这里坐了很长一段时间,但我会给出答案,因为几周前我遇到了一个非常相似的问题。

我有多个不同的文件(.docx, .pdf)位于不同的文件夹中。更复杂的是,这些.docx文件分为三组:SS.docxss.docxplain .docx我的信息.docx在每份文件的一个表格中一目了然。

我很努力地写了一个 Python 提取算法,现在我将引导你完成:

import os
import pandas as pd
import docx
from docx.api import Document

#fixed variable
location = 'C:\\Data_analysis\\N_TRACKING'

然后我添加了一个函数,该函数从 list 开始遍历完整的文件树location 并将所有文件名及其路径存储在 list 中targets_in_dir

#the function 

def find_docx(location):
    all_files = []    # Will contain found files

    # Walk top-down through directory tree
    for (root, dirs, files) in os.walk(location, topdown=True):
   
        for f in files:
            f = f.lower()              # Make conditional case insensitive
            if f.endswith('.pdf'):
                continue               # Skipping pdf
            if f.endswith('ss.docx'):
                continue              # Skipping ss.docx or SS.docx
            if f.endswith('.docx'):
                # Desired docx (undesired docx has been filtered out by previous conditional)
                all_files.append(os.path.join(root, f))
                
    return all_files

endswith函数在这里非常有用,因为它将字符串的结尾(这里是我的列表元素)与括号中的字符串进行比较。本质上,我跳过了我不想要的所有内容,只添加了我想要all_files的函数返回的内容。我将该函数应用于该位置并将我的结果存储在targets_in_dir.

#main
targets_in_dir = find_docx(location) 

然后我在提取循环中喂它

error_log =[]
empty =[]
processed_files =[]


final_df= pd.DataFrame(empty)
for idx, c in enumerate(targets_in_dir):
    try:
        document = Document(c)
        table = document.tables[6]
        processed_files.append(c)
    except: 
        error_log.append(c)
        
    data = []
                
    keys = None
    for i, row in enumerate(table.rows):
        text = (cell.text for cell in row.cells)

        if i == 0:
            keys = tuple(text)
            continue
        row_data = dict(zip(keys, text))
        data.append(row_data)
                 
    df = pd.DataFrame(data)
    df['report'] = str(c)
    final_df = final_df.append(df)

我在python-docx这里使用库,它直接允许我选择表作为对象。奇怪的是,由于某种文档错误,我不得不pip install python-docx并且只能将其导入,因为迭代许多文件通常会失败。docx这就是try: except:循环的用途

错误存储在error_log. 算法经过的文件processed_files. final_df是一个空数据框,我将在其中附加我的结果。

请注意,我从这一行的所有这些文档中指定了我想要的表格(编号 6):

 table = document.tables[6]

然后,代码使用第一行作为字典的键并在其上映射内容来遍历表的行。然后我通过线路添加跟踪信息(总是知道你的数据来自哪里!)

 df['report'] = str(c)

并将结果数据框化并从一开始就将其添加到我的空df中。然后你可以开始清理数据,因为人类往往很混乱!