Pandas读取多级索引数据框(反向to_string())

3

我有一个文本文件,它看起来像这样:

test2.dat:

最初的回答:

               col1      col2
idx1 idx2                    
a    0     0.256788  0.862771
     1     0.409944  0.785159
     2     0.822773  0.955309
b    0     0.159213  0.628662
     1     0.463844  0.667742
     2     0.292325  0.768051

通过file.write(df.to_string)保存一个多索引pandas DataFrame创建了这个。

现在,我想要反转这个操作。但是,当我尝试时

Original Answer:"最初的回答"

pandas.read_csv(data, sep=r'\s+', index_col=[0, 1])

出现了错误,ParserError: Error tokenizing data. C error: Expected 2 fields in line 3, saw 4

以下是一个简单的 MWE:

import pandas
import numpy as np
from itertools import product
df1 = pandas.DataFrame(product(['a', 'b'], range(3)), columns=['idx1', 'idx2'])
df2 = pandas.DataFrame(np.random.rand(6, 2), columns=['col1', 'col2'])
df  = pandas.concat([df1, df2], axis=1)
df.set_index(['idx1','idx2'], inplace=True)
df.to_csv('test.dat', sep=' ')
with open('test2.dat', 'w') as file:
    file.write(df.to_string())

注意,通过pandas.to_csv()保存的test.dattest2.dat相比,几乎不能算作“人类可读”。

test.dat:

最初的回答
idx1 idx2 col1 col2
a 0 0.2567883353169065 0.862770538437793
a 1 0.40994403619942743 0.7851591115509821
a 2 0.8227727216889246 0.9553088749178045
b 0 0.1592133339255788 0.6286622783546136
b 1 0.4638439474864856 0.6677423709343185
b 2 0.2923252978245071 0.7680513714069206
2个回答

3
使用read_fwf函数,并通过列表推导式设置列名:
最初的回答
df = pd.read_fwf('file.csv', header=[0,1])
df.columns = [y for x in df.columns for y in x if not 'Unnamed' in y]

#replace missing values by first column
df.iloc[:, 0] = df.iloc[:, 0].ffill().astype(int)
#set first 2 columns to MultiIndex
df = df.set_index(df.columns[:2].tolist())
print (df)
             col1    col2
idx1 idx2                
1    1     0.1234  0.2345
     2     0.4567  0.2345
     3     0.1244  0.5332
2    1     0.4213  0.5233
     2     0.5423  0.5423
     3     0.5235  0.6233

感谢您的回答。这个格式是通过file.write(df.to_string())将完全相同的DataFrame保存而来的。之所以这样做,是因为我想以人类可读的形式保存数据。很遗憾的是,当使用多级索引时,pandas没有提供to_string的反向功能。 - Hyperplane
@Hyperplane - 不需要 df = df.to_csv(file),直接使用 read_csv 就可以了。 - jezrael
但是标准的CSV文件绝对不易读。我真的想使用空格作为分隔符,并享受to_string提供的美观垂直对齐。 - Hyperplane
@Hyperplane 添加了可能的解决方案,但是 pandas 的逆函数用于读取由 df.to_string() 创建的文件不存在。 - jezrael
看看我的修改。to_csv 对我来说并不是很好用,因为输出结果并不容易阅读(尤其是与 to_string 的输出相比)。不管怎样,感谢你的帮助! - Hyperplane
@Hyperplane - 添加了更好的解决方案。 - jezrael

0
我决定采用jezrael代码的一个小变化,它会自动处理索引的数量。 请注意,df.columns最初的形式为[(x1,y1), (x2,y2), ..., (xn, yn)],其中n是列数,xi是第一行标题中第i列的标签,yi是第二行标题的标签。
df = pandas.read_fwf(f, header=[0,1])
cols = [x for x,_ in df.columns if 'Unnamed' not in x]
idxs = [y for _,y in df.columns if 'Unnamed' not in y]
df.columns = idxs + cols
df[idxs] = df[idxs].ffill()
df.set_index(idxs, inplace=True)

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