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是头)。让我们假设