使用分隔符从列表中提取数据

3
我有一组10个Python列表,格式如下:
[ABC*DEF*123>~123*999*HHH]
[PQR*RST*567>~AWS*999*POI]
[XYZ*TGT*234>~2352*245*HFT]
[STU*DEF*789>~654*345*QQQ]

我正在尝试从上面的列表中提取数据,使最终输出为一个数据框,并期望以下输出:
123,999,HHH
AWS,999,POI
2352,245,HFT
654,345,QQQ

以下是我目前所做的:
allFiles = Path where all the txt files are stored
list_ = []
for file_ in allFiles:
    with open(file_) as fp:
        lines1 = fp.read().split('\n')
        b = [i.split('~', 1)[1] for i in lines1]
        print(b)

上述内容向我提供了以下列表:
[123*999*HHH]
[AWS*999*POI]
[2352*245*HFT]
[654*345*QQQ]

我无法使用分隔符 (*) 将上述数据拆分为不同的列并保存到数据框中。
4个回答

6

您可以首先创建一个数据框,将字符串列表作为行,并使用str.split~拆分每个字符串。然后,您可以选择仅选取第二项后面的内容并再次进行拆分,这次使用*,同时设置expand=True

l1 = ['ABC*DEF*123>~123*999*HHH']
l2 = ['PQR*RST*567>~AWS*999*POI']
l3 = ['XYZ*TGT*234>~2352*245*HFT']
l4 = ['STU*DEF*789>~654*345*QQQ']

df = pd.DataFrame([l1,l2,l3,l4], columns=['col1'])
df.col1.str.split('~').str[1].str.split('*', expand=True)

     0    1    2
0   123  999  HHH
1   AWS  999  POI
2  2352  245  HFT
3   654  345  QQQ

更新

如果要从多个文件中获取列表并执行上述操作:

l = []
for file_ in allFiles:
    f = open(file_, 'r')
    l.extend([line.rstrip('\n') for line in f.readlines()])

然后像之前一样操作:

df = pd.DataFrame(l, columns=['col1'])
df.col1.str.split('~').str[1].str.split('*', expand=True)

谢谢您的回复,但是列表的数量并不固定。它会动态变化。我该如何使上述工作不需要定义列表的数量呢?谢谢。 - scott martin
@scottmartin 你的列表是如何保存的?在一个更大的列表中吗? - yatu
每个我读取的文件都会存储为一个列表。如我在初始帖子中所示,我有'n'个列表,这是我从文件夹读取文件的结果(其中n是文件夹中文件的数量)。希望我已经在这里回答了你的问题。 - scott martin

1

既然您已经有了列表,一个简单的函数就可以在分隔符(*)处进行拆分。

l1 = ["123*999*HHH"]
l2 = ["AWS*999*POI"]
l3 = ["2352*245*HFT"]
l4 = ["654*345*QQQ"]

def split_delim(l):
    for i in l:
        l = i.split('*')
    return l

l1 = split_delim(l1)
l2 = split_delim(l2)
l3 = split_delim(l3)
df = pd.DataFrame({'l1':l1, 'l2':l2, 'l3':l3})
df
    l1      l2      l3
0   123     AWS     2352
1   999     999     245
2   HHH     POI     HFT

一种更为通用的解决方案,不受列表数量限制。这将在形成数据框之前执行所有的拆分操作。
#allFiles = Path where all the txt files are stored

def split_delim(Files):  
    list_ = []
    for file_ in Files:
        with open(file_) as fp:
            lines1 = fp.read().split('\n')
            b = [i.split('~', 1)[1] for i in lines1]
            for i in b:
                l = i.split('*')
                list_.append(l)                
    return list_

list_new = split_delim(allFiles)

df = pd.DataFrame(list_new, columns=['col1'])

1
使用read_csv函数,分隔符为~,并使用参数name,然后为DataFrame的第二列添加Series.str.split
import pandas as pd

temp=u"""ABC*DEF*123>~123*999*HHH
PQR*RST*567>~AWS*999*POI
XYZ*TGT*234>~2352*245*HFT
STU*DEF*789>~654*345*QQQ"""
#after testing replace 'pd.compat.StringIO(temp)' to 'filename.csv'
df = pd.read_csv(pd.compat.StringIO(temp), sep="~", names=['a','b'])

df = df['b'].str.split('*', expand=True)
print (df)
      0    1    2
0   123  999  HHH
1   AWS  999  POI
2  2352  245  HFT
3   654  345  QQQ

如果想使用您的解决方案,请添加另一个split
list_ = []
for file_ in allFiles:
with open(file_) as fp:
    lines1 = fp.read().split('\n')
    b = [i.split('~', 1)[1].split('*') for i in lines1]
    list_.append(b)

df = pd.DataFrame([y for x in list_ for y in x])
print(df)

谢谢。我添加了另一行代码,将列表保存到数据框中,但只有最后一个列表/文件被保存。df = pd.DataFrame(b)请问你能帮忙吗?谢谢。 - scott martin
1
@scottmartin - 你现在可以检查一下吗? - jezrael
只是另一个帮助请求。在执行上述拆分操作后,我有几行具有像0001〜ABC这样的值。您能否请教如何修改上面分享的最新更新代码,以便我可以应用此附加的split('〜')方法。 - scott martin
@scottmartin - 更好的做法是创建一个新问题。 - jezrael

0

你必须明确指定分隔符,例如

print('ABC*DEF*123>~123*999*HHH'.split('~')[1].split('*'))

输出:

['123', '999', 'HHH']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接