将重复的“键=值”对的文件读入DataFrame

时间:2019-11-13 07:24:00

标签: python pandas dataframe

我有一个txt文件,其中包含这种格式的数据。前三行重复一遍又一遍。

name=1
grade=A
class=B
name=2
grade=D
class=A

我想以表格格式输出数据,例如:

name | grade | class
1    | A     | B
2    | D     | A

我正在努力设置标题并仅循环访问数据。到目前为止,我尝试过的是:

def myfile(filename):
    with open(file1) as f:
        for line in f:
            yield line.strip().split('=',1)

def pprint_df(dframe):
    print(tabulate(dframe, headers="keys", tablefmt="psql", showindex=False,))

#f = pd.DataFrame(myfile('file1')
df = pd.DataFrame(myfile('file1'))
pprint_df(df)

输出是

+-------+-----+
| 0     | 1   |
|-------+-----|
| name  | 1   |
| grade | A   |
| class | B   |
| name  | 2   |
| grade | D   |
| class | A   |
+-------+-----+

不是我真正想要的东西。

7 个答案:

答案 0 :(得分:9)

您可以使用熊猫读取文件并处理数据。您可以使用此:

import pandas as pd
df = pd.read_table(r'file.txt', header=None)
new = df[0].str.split("=", n=1, expand=True)
new['index'] = new.groupby(new[0])[0].cumcount()
new = new.pivot(index='index', columns=0, values=1)

new输出:

0     class grade name
index                 
0         B     A    1
1         A     D    2

答案 1 :(得分:7)

我知道您有足够的答案,但这是使用字典的另一种方法:

import pandas as pd
from collections import defaultdict
d = defaultdict(list)

with open("text_file.txt") as f:
    for line in f:
        (key, val) = line.split('=')
        d[key].append(val.replace('\n', ''))

df = pd.DataFrame(d)
print(df)

这将为您提供输出:

name grade class
0    1     A     B
1    2     D     A

只是换个角度来看。

答案 2 :(得分:3)

您还可以执行以下操作:以3块为单位读取文本文件file,构建一个嵌套列表,然后将其放入数据框:

from itertools import zip_longest
import pandas as pd

# taken from https://docs.python.org/3.7/library/itertools.html:
def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

data = [['name', 'grade', 'class']]
with open(file, 'r') as fobj:
    blocks = grouper(fobj, 3)
    for b in blocks:
        data.append([i.split('=')[-1].strip() for i in b])

df = pd.DataFrame(data[1:], columns=data[0])  

df将直接是

  name grade class
0    1     A     B
1    2     D     A

注释#1:尽管比纯pandas解决方案需要更多的代码行,但根据我的经验,由于使用的{{1} }从而减少了开销。

注释#2:通常,我认为最好以其他格式存储输入数据,例如pandasjson。这样会更容易阅读,例如使用csv文件的csv函数read_csv

答案 3 :(得分:3)

当您获得输出时,这就是我如何处理该问题:

首先根据列的可重复性创建唯一索引,

setDT(df1)
df1[, .N, names(df1)]
#    x y N
# 1: a a 1
# 2: b b 2
# 3: c c 3

然后我们使用df['idx'] = df.groupby(df['0'])['0'].cumcount() + 1 print(df) 0 1 idx 0 name 1 1 1 grade A 1 2 class B 1 3 name 2 2 4 grade D 2 5 class A 2 函数使用它来旋转数据框

crosstab

答案 4 :(得分:2)

此解决方案假定文本格式与您所描述的相同,但是您可以对其进行修改以使用其他单词来表示新行的开头。在此,我们假设新行以name字段开头。我在下面修改了您的myfile()函数,希望它能给您一些想法:)

def myfile(filename):
    d_list = []
    with open(filename) as f:
        d_line = {}
        for line in f:
            split_line = line.rstrip("\n").split('=')  # Strip \n characters and split field and value.
            if (split_line[0] == 'name'):
                if d_line:
                    d_list.append(d_line)  # Append if there is previous line in d_line.
                d_line = {split_line[0]: split_line[1]}  # Start a new dictionary to collect the next lines.
            else:
                d_line[split_line[0]] = split_line[1]  # Add the other 2 fields to the dictionary.
        d_list.append(d_line) # Append the last line.
    return pd.DataFrame(d_list)  # Turn the list of dictionaries into a DataFrame.

答案 5 :(得分:0)

您可以使用 Python的Dictionary模块和Pandas生成该输出。

import pandas as pd
from collections import defaultdict

text = '''name=1
          grade=A
          class=B
          name=2
          grade=D
          class=A'''
text = text.split()

new_dict = defaultdict(list) 
for i in text:
    temp = i.split('=')
    new_dict[temp[0]].append(temp[1])

df = pd.DataFrame(new_dict)

这种方法可能不是最有效的方法,但是它没有使用Pandas的任何高级功能。希望对您有所帮助。

输出:

    name    grade   class
0      1        A       B
1      2        D       A

答案 6 :(得分:0)

恕我直言,目前所有的答案看起来都太复杂了。我要做的是使用'='作为pd.read_csvsep参数来读取2列,然后pivot获得的DataFrame:

import pandas as pd

df = pd.read_csv('myfile', sep='=', header=None)
#        0  1
# 0   name  1
# 1  grade  A
# 2  class  B
# 3   name  2
# 4  grade  D
# 5  class  A

df = df.pivot(index=df.index // len(df[0].unique()), columns=0)
#       1           
# 0 class grade name
# 0     B     A    1
# 1     A     D    2

如果您不希望该多级列索引出现在结果中,则可以通过以下方式将其删除:

df.columns = df.columns.get_level_values(1)
# 0 class grade name
# 0     B     A    1
# 1     A     D    2