Python 如何解析非结构化的类表数据?

Python 如何解析非结构化的类表数据?,python,parsing,text,machine-learning,text-parsing,Python,Parsing,Text,Machine Learning,Text Parsing,我有一个文本文件,其中保存了一些操作结果。数据以人类可读的格式显示(如表格)。如何解析这些数据,以便使用这些数据形成一个数据结构,如字典 非结构化数据的示例如下所示 =============================================================== Title =============================================================== Header Header Header Header

我有一个
文本文件
,其中保存了一些操作结果。数据以人类可读的格式显示(如表格)。如何解析这些数据,以便使用这些数据形成一个数据结构,如
字典

非结构化数据的示例如下所示

===============================================================
Title
===============================================================
Header     Header Header Header  Header       Header
1          2      3      4       5            6                   
---------------------------------------------------------------
1          Yes    No     6       0001 0002    True    
2          No     Yes    7       0003 0004    False    
3          Yes    No     6       0001 0001    True    
4          Yes    No     6       0001 0004    False    
4          No     No     4       0004 0004    True    
5          Yes    No     2       0001 0001    True    
6          Yes    No     1       0001 0001    False    
7          No     No     2       0004 0004    True
上面示例中显示的数据不是
制表符分隔的
逗号分隔的
。它总是有一个
标题
,相应地,沿着
列可能/可能没有值,如
外观

我尝试过使用基本的解析技术,如
regex
条件检查
,但我需要一种更健壮的方法来解析这些数据,因为上面显示的示例并不是数据呈现的唯一格式

更新1:除了所示示例之外,还有许多情况,例如添加更多列,单个单元格具有多个实例(但在下一行中直观显示,而它属于前一行)

有任何
python
库可以解决这个问题吗

机器学习
技术能在不解析的情况下帮助解决这个问题吗?如果是,会是什么类型的问题(分类、回归、聚类)


更新2:另一个可能的示例,它涉及一个具有多个实例的单个单元格(但在下一行中直观显示,而它属于前一行)

假设您的示例是“sample.txt”

import pandas as pd

df = pd.read_table('sample.txt', skiprows=[0, 1, 2, 3, 5], delimiter='\s\s+')

print(df)
print(df.shape)

   1    2    3  4          5      6
0  1  Yes   No  6  0001 0002   True
1  2   No  Yes  7  0003 0004  False
2  3  Yes   No  6  0001 0001   True
3  4  Yes   No  6  0001 0004  False
4  4   No   No  4  0004 0004   True
5  5  Yes   No  2  0001 0001   True
6  6  Yes   No  1  0001 0001  False
7  7   No   No  2  0004 0004   True
(8, 6)
当然,您可以更改数据类型。请检查吨的
pd。请阅读表()。此外,还有xlsx、csv、html、sql、json、hdf,甚至剪贴板等


欢迎来到…

我不知道你想对标题做什么,因此我将继续跳过所有6行…空格不一致,因此你需要首先使记录之间的空格一致,否则很难逐行阅读。 你可以做这样的事情

import re

def read_file():
    with open('unstructured-data.txt', 'r') as f:
         for line in f.readlines()[6:]:
             line = re.sub(" +", " ", line)
             print(line)
             record = line.split(" ")
             print(record)
read_file()
1 Yes No 6 0001 0002 True

['1', 'Yes', 'No', '6', '0001', '0002', 'True', '\n']
2 No Yes 7 0003 0004 False 

['2', 'No', 'Yes', '7', '0003', '0004', 'False', '\n']
3 Yes No 6 0001 0001 True 

['3', 'Yes', 'No', '6', '0001', '0001', 'True', '\n']
4 Yes No 6 0001 0004 False 

['4', 'Yes', 'No', '6', '0001', '0004', 'False', '\n']
4 No No 4 0004 0004 True 

['4', 'No', 'No', '4', '0004', '0004', 'True', '\n']
5 Yes No 2 0001 0001 True 

['5', 'Yes', 'No', '2', '0001', '0001', 'True', '\n']
6 Yes No 1 0001 0001 False 

['6', 'Yes', 'No', '1', '0001', '0001', 'False', '\n']
7 No No 2 0004 0004 True

['7', 'No', 'No', '2', '0004', '0004', 'True\n']
这会给你类似的东西

import re

def read_file():
    with open('unstructured-data.txt', 'r') as f:
         for line in f.readlines()[6:]:
             line = re.sub(" +", " ", line)
             print(line)
             record = line.split(" ")
             print(record)
read_file()
1 Yes No 6 0001 0002 True

['1', 'Yes', 'No', '6', '0001', '0002', 'True', '\n']
2 No Yes 7 0003 0004 False 

['2', 'No', 'Yes', '7', '0003', '0004', 'False', '\n']
3 Yes No 6 0001 0001 True 

['3', 'Yes', 'No', '6', '0001', '0001', 'True', '\n']
4 Yes No 6 0001 0004 False 

['4', 'Yes', 'No', '6', '0001', '0004', 'False', '\n']
4 No No 4 0004 0004 True 

['4', 'No', 'No', '4', '0004', '0004', 'True', '\n']
5 Yes No 2 0001 0001 True 

['5', 'Yes', 'No', '2', '0001', '0001', 'True', '\n']
6 Yes No 1 0001 0001 False 

['6', 'Yes', 'No', '1', '0001', '0001', 'False', '\n']
7 No No 2 0004 0004 True

['7', 'No', 'No', '2', '0004', '0004', 'True\n']

尝试此操作,它应完全处理多行单元格:

import re

def splitLine(line, delimiters):
    output = []
    for start, end in delimiters:
        output.append(line[start:end].strip())
    return output

with open("path/to/the/file.ext", "r") as f:
    _ = f.readline()
    _ = f.readline()
    _ = f.readline()

    headers = [f.readline()]
    next = f.readline()
    while(next[0] != "-"):
        headers.append(next)
        next = f.readline()

    starts = []
    columnNames = set(headers[0].split())
    for each in columnNames:
        starts.extend([i for i in re.finditer(each, headers[0])])
    starts.sort()
    delimiters = list(zip(starts, starts[1:] + [-1]))

    if (len(columnNames) - 1):
        rowsPerEntry = len(headers)
    else:
        rowsPerEntry = 1

    headers = [splitLine(header, delimiters) for header in headers]
    keys = []
    for i in range(len(starts)):
        if ("Header" == headers[0][i]):
            keys.append(headers[1][i])
        else:
            keys.append([])
            for header in headers:
                keys[-1].append(header[i])

    entries = []
    rows = []
    for line in f:
        rows.append(splitLine(line, delimiters))
        if (rowsPerEntry == len(rows)):
            if (1 == rowsPerEntry):
                entries.append(dict(zip(keys, rows[0])))
            else:
                entries.append({})
                for i, key in enumerate(keys):
                    if (str == type(key)):
                       entries[-1][key] = rows[0][i]
                    else:
                       k = "Column " + str(i+1)
                       entries[-1][k] = dict.fromkeys(key)
                       for j, subkey in enumerate(key):
                           entries[-1][k][subkey] = rows[j][i]
            rows = []
解释 我们使用
re
模块在第4列中查找“Header”



splitLine(line,delimiters)
auxiliar函数返回由delimiters参数定义的列分隔的行数组。此参数是由两个元组组成的列表,其中第一个元组表示起始位置,第二个元组表示结束位置。

您需要逐行重新填充并跳过6行…使用split(“”)解析第一个数据行,以获得列表中的整行数据,如[1,yes,no,6001002,True]您知道每列的数据类型吗?多行中的单个单元格确实是一个问题。目前提供的解决方案无法正确处理您描述的情况。正确的解决方案必须在某种程度上考虑垂直对齐。我发布了一个考虑垂直对齐的解决方案,因为空格可能意味着与第5列中的列更改不同的内容。Is仍然无法处理多行单元格问题。为此,我需要一些更多的信息:例如,当找到多行单元格时,第一列是否总是空的?为什么每个需要读取文件的答案都建议使用诸如pandas之类的库?如果他只需要阅读一个文件,那么安装和导入pandas远比他实际需要的多。图书馆就是为了这个目的而存在的……而且大部分都是经过优化的……但我同意这需要学习图书馆本身,而不仅仅是python,它还增加了一个主要的开销,这不仅仅是为了读取file@Adirio因为他要求库提供健壮的解析和结构化。他已经尝试过ReGEX等。如果有更好的方法,请让我知道你的代码。我试着考虑他在评论中给我们的所有要点,给我一些时间。此解决方案还将“0001 0002”拆分为两个不同的值,而它们是一列
line.split()
在没有参数的情况下已经可以处理多个空格,它还可以为您处理换行符。正如他在随后的评论中所描述的,占据两行的单元格也不会被处理。@adrio.。在这种情况下,什么是不明智的选择?为什么不发布正确的答案?。他希望能够处理数据…我希望在你的下一个回答中你能为他描述一下…他还要求一个库…所以我认为熊猫是有效的你正在构建完整列表,而不是在不存储整个文件的情况下迭代行。我说清楚了吗?您可以在一次不加载lal的情况下对行进行迭代,这样,对于数百万行,进程就不会失去内存。@正如您在下面的答案中所评论的那样,这个内存效率如何?@Eliethesaiyan在第二个代码时钟后检查,它解释了原因。它基本上使用迭代器以避免完全加载文件。显然,您必须将其存储在一个大数组中,但至少您没有两个大数组(在您的情况下,您只有一个数组,因为您正在中间打印,而我正在存储,如果您存储,您将有两个大列表,而我只有一个,而在打印版本中,您将有一个,而我不需要任何)@再会…即使你逐行阅读,程序最终也会将整个内容加载到内存中,因为你正在“存储”…当然,除非,他看了一大块文件…打印只是为了给他看结果…他想用它做什么就做什么…再说一遍…你的论点根本不能说服我关于记忆的观点issue@Eliethesaiyan我们的解决方案不同之处在于我存储,你打印,对吗。他可以做任何他想做的事,没错,但是为了比较我们的答案,你知道我们需要做同样的事情。因此,假设我们有一个长度为N+6的文件(6是头)。让我们假设