【问题标题】:Python Text File to Data Frame with Specific PatternPython文本文件到具有特定模式的数据框
【发布时间】:2021-07-05 21:14:08
【问题描述】:

我正在尝试使用 Pandas 将一堆文本文件转换为数据框。

每个文本文件都包含以两个相关信息开头的简单文本:NumberRegister 变量。

那么,文本文件有一些我们不应该考虑的随机文本。

最后,文本文件包含诸如股份编号、人名、出生日期、地址和一些以小写字母开头的附加行等信息。每个组都包含此类信息,并且模式始终相同:组的第一行由一个数字(此处为id)定义,然后是“SHARE”字样。

这是一个例子:

Number 01600 London                           Register  4314

Some random text...

 1 SHARE: 73/1284
   John Smith
   BORN: 1960-01-01 ADR: Streetname 3/2   1000
   f 4222/2001
   h 1334/2000
   i 5774/2000
 4 SHARE: 58/1284
   Boris Morgan
   BORN: 1965-01-01 ADR: Streetname 4   2000
   c 4222/1988
   f 4222/2000

我需要将文本转换为具有以下输出的数据框,其中每个组存储在一行中:

Number Register City Id Share Name Born c f h i
01600 4314 London 1 73/1284 John Smith 1960-01-01 NaN 4222/2001 1334/2000 5774/2000
01600 4314 London 4 58/1284 Boris Morgan 1965-01-01 4222/1988 4222/2000 NaN NaN

我最初的方法是首先导入文本文件并为每个案例应用正则表达式:

import pandas as pd
import re

df = open(r'Test.txt', 'r').read()

for line in re.findall('SHARE.*', df):
   print(line)

但可能有更好的方法。

非常感谢任何帮助。提前致谢。

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    这可以在没有使用列表理解和拆分字符串的正则表达式的情况下完成:

    import pandas as pd
    
    text = '''Number 01600 London                           Register  4314
    
    Some random text...
    
     1 SHARE: 73/1284
       John Smith
       BORN: 1960-01-01 ADR: Streetname 3/2   1000
       f 4222/2001
       h 1334/2000
       i 5774/2000
     4 SHARE: 58/1284
       Boris Morgan
       BORN: 1965-01-01 ADR: Streetname 4   2000
       c 4222/1988
       f 4222/2000'''
    
    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)
    

    输出:

    Number Register City Id Share Name Born f h i c
    0 01600 4314 London 1 73/1284 John Smith 1960-01-01 4222/2001 1334/2000 5774/2000 nan
    1 01600 4314 London 4 58/1284 Boris Morgan 1965-01-01 4222/2000 nan nan 4222/1988

    【讨论】:

    • 首先非常感谢您的回答。对于以字母开头的某些行(类似于我上面的示例,带有字母 cfhi)(代码:d.update({name: value for name,value in (s.split() for s in i[3:])}))我收到以下错误:“ValueError:too许多要解压的值(预期为 2)”。是否有可能忽略某些特定字母或增加每个字母的预期信息量?提前致谢!
    • 该行可能有多个以空格分隔的值。您可以将s.split() 替换为s.split(" ", 1)。这将仅在第一个空格上拆分。
    • 现在我终于明白为什么它不能完全工作了。 s.split(" ", 1) 非常有帮助 - 但似乎在某些情况下,该行被分成两部分。所以基本上我需要的是获取所有内容,直到下一行以小写字母开头(abh 等)。你知道怎么解决吗?由于上面的答案是正确的,我已经将其标记为正确。 :)
    • 啊,您发现了问题真是太好了。我已经用解决方案更新了答案。
    • 谢谢!不幸的是,建议的答案不起作用 - 我收到以下错误:“IndentationError:预期缩进块(,第 7 行)”。甚至尝试使用原始示例。
    猜你喜欢
    • 1970-01-01
    • 2022-11-14
    • 1970-01-01
    • 2016-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-30
    • 2020-05-03
    • 2013-06-20
    相关资源
    最近更新 更多