如何解析非结构化的表格式数据?

时间:2017-04-05 07:47:04

标签: python parsing text machine-learning text-parsing

我有一个var entryPoint = (from U in Users join ud in UserDistricts on U.UserID equal ud.UserID join d in Districts on d.DistrictID equals ud.DistrictID where ud.UserID == U.UserID select new { DistrictId = ud.DistrictId, DistrictName= d.DistrictName, UserID= U.UserID }).ToList(); 来保存一些操作的结果。数据显示在text file(如表格)中。如何解析此数据,以便我可以使用此数据形成human-readable format等数据结构?

dictionaries的示例如下所示。

unstructured data

以上示例中显示的数据不是=============================================================== 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 tab-separated。它始终具有comma separated,并且相应地可能/可能不具有header外观的值。

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

更新1 :除了显示的示例之外还有很多情况,例如添加更多列,单个单元格有多个实例(但在下一行可视化显示,而它属于上一个行)。

是否有conditional checks库来解决此问题?

python技术可以在没有解析的情况下帮助解决这个问题吗?如果是,那将是什么类型的问题(分类,回归,聚类)?

machine learning

Update 2 :另一个例子,它可能看起来像一个单元格有多个实例(但在下一行可视化,但它属于前一行)。

3 个答案:

答案 0 :(得分:3)

假设你的例子是'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.read_table() params的吨数。此外,xlsx,csv,html,sql,json,hdf甚至剪贴板等都有method

欢迎来到pandas ...

答案 1 :(得分:0)

我不知道你想对标题做什么,所以我会继续跳过所有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']

答案 2 :(得分:0)

试试这个,它应该完全处理多行单元格:

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)辅助函数返回由delimiters参数定义的列拆分的行数组。此参数是2项元组的列表,其中第一项表示起始位置,第二项表示结束位置。