【发布时间】:2021-07-12 20:04:35
【问题描述】:
我正在尝试使用 Pandas 将一堆文本文件转换为数据框。
感谢 Stack Overflow 令人惊叹的社区,我几乎得到了想要的输出(OP:Python Text File to Data Frame with Specific Pattern)。
基本上我需要使用 Pandas 将具有特定模式(但有时缺少数据)的文本转换为数据框。
这是一个例子:
Number 01600 London Register 4314
Some random text...
************************************* B ***************************************
1 SHARE: 73/1284
John Smith
BORN: 1960-01-01 ADDR: Streetname 3/2 1000
f 4222/2001
h 1334/2000
i 5774/2000
4 SHARE: 58/1284
Boris Morgan
BORN: ADDR: Streetname 4 2000
5 SHARE: 23/1284
James Klein
BORN: ADDR:
c 4222/1988 Supporting Text
f 4222/2000 Extra Text
************************************* C ***************************************
More random text...
从上面的示例中,我需要将 ***B*** 和 ***C*** 之间的文本转换为具有以下输出的数据框:
| Number | Register | City | Id | Share | Name | Born | Address | c | f | h | i |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 01600 | 4314 | London | 1 | 73/1284 | John Smith | 1960-01-01 | Streetname 3/2 1000 | NaN | 4222/2001 | 1334/2000 | 5774/2000 |
| 01600 | 4314 | London | 4 | 58/1284 | Boris Morgan | NaN | Streetname 4 2000 | NaN | NaN | NaN | NaN |
| 01600 | 4314 | London | 5 | 23/1284 | James Klein | NaN | NaN | 4222/1988 Supporting Text | 4222/2000 Extra Text | NaN | NaN |
一些模式:
-
组的第一行包含单词 SHARE;这个词之前是
Id,之后是Share。 -
第二行包含人名(应完全提取到
Name变量中)。 -
第三行包含生日 (BORN) 和地址 (ADDR)。有时会丢失此信息 - 在这些情况下,变量
Born和Address应该是 NaN。 -
当它存在时,第四行及以后(持续到到达下一组)以小写字母开头。这些行中的每一行都应该被提取到一个以小写字母开头的变量中,直到段落的结尾。
以下代码适用于出生日期和地址可用,并且第四行及以后仅包含一块信息时(在前面的示例中,来自 John Smith 的 SHARE: 73/1284 有 f、h 和 i 行 -全部都只有一个信息块,并且来自 James Klein 的 SHARE: 23/1284 包含多个块)。
import pandas as pd
text = '''Number 01600 London Register 4314
Some random text...
************************************* B ***************************************
1 SHARE: 73/1284
John Smith
BORN: 1960-01-01 ADDR: Streetname 3/2 1000
f 4222/2001
h 1334/2000
i 5774/2000
4 SHARE: 58/1284
Boris Morgan
BORN: ADDR: Streetname 4 2000
5 SHARE: 23/1284
James Klein
BORN: ADDR:
c 4222/1988 Supporting Text
f 4222/2000 Extra Text
************************************* C ***************************************
More random text...'''
text = [i.strip() for i in text.splitlines()] # create a list of lines
data = []
# extract metadata from first line
number = text[0].split()[1]
city = text[0].split()[2]
register = text[0].split()[4]
# create a list of the index numbers of the lines where new items start
indices = [text.index(i) for i in text if 'SHARE' in i]
# split the list by the retrieved indexes to get a list of lists of items
items = [text[i:j] for i, j in zip([0]+indices, indices+[None])][1:]
for i in items:
d = {'Number': number, 'Register': register, 'City': city, 'Id': int(i[0].split()[0]), 'Share': i[0].split(': ')[1], 'Name': i[1], 'Born': i[2].split()[1], }
items = list(s.split() for s in i[3:])
merged_items = []
for i in items:
if len(i[0]) == 1 and i[0].isalpha():
merged_items.append(i)
else:
merged_items[-1][-1] = merged_items[-1][-1] + i[0]
d.update({name: value for name,value in merged_items})
data.append(d)
#load the list of dicts as a dataframe
df = pd.DataFrame(data)
有人知道如何解决这些问题吗?提前致谢。
【问题讨论】: