具有双层表头的pandas数据框并导出为csv
我有一个数据表
df = pd.DataFrame(columns = ["AA", "BB", "CC"])
df.loc[0]= ["a", "b", "c1"]
df.loc[1]= ["a", "b", "c2"]
df.loc[2]= ["a", "b", "c3"]
我需要在表头上添加第二行
df.columns = pd.MultiIndex.from_tuples(zip(df.columns, ["DD", "EE", "FF"]))
现在我的数据表是这样的
AA BB CC
DD EE FF
0 a b c1
1 a b c2
2 a b c3
但是当我把这个数据表写入CSV文件时
df.to_csv("test.csv", index = False)
我发现多了一行,不是我预期的那样
AA,BB,CC
DD,EE,FF
,,
a,b,c1
a,b,c2
a,b,c3
4 个回答
2
在@DSM的解决方案基础上:
如果你需要(就像我一样)把同样的技巧应用到导出到excel,主要需要的改变(除了与to_excel方法的预期差异)就是要去掉用于列标签的多重索引...
这是因为.to_excel不支持写出一个列有多重索引但没有索引的数据框(如果在.to_excel方法中设置index=False),而.to_csv是可以的。
总之,下面就是它的样子:
>>> writer = pd.ExcelWriter("noblankrows.xlsx")
>>> headers = pd.DataFrame(df.columns.tolist()).T
>>> headers.to_excel(
writer, header=False, index=False)
>>> df.columns = pd.Index(range(len(df.columns))) # that's what I was referring to...
>>> df.to_excel(
writer, header=False, index=False, startrow=len(headers))
>>> writer.save()
>>> pd.read_excel("noblankrows.xlsx").to_csv(sys.stdout, index=False)
AA,BB,CC
DD,EE,FF
a,b,c1
a,b,c2
a,b,c3
3
使用 df.to_csv("test.csv", index = False, tupleize_cols=True)
这个命令,可以把结果保存成一个CSV文件,内容如下:
"('AA', 'DD')","('BB', 'EE')","('CC', 'FF')"
a,b,c1
a,b,c2
a,b,c3
如果你想把这个CSV文件再读回来,可以用:
df2=pd.read_csv("test.csv", tupleize_cols=True)
df2.columns=pd.MultiIndex.from_tuples(eval(','.join(df2.columns)))
如果你想得到你想要的确切输出,可以使用:
with open('test.csv', 'a') as f:
pd.DataFrame(np.asanyarray(df.columns.tolist())).T.to_csv(f, index = False, header=False)
df.to_csv(f, index = False, header=False)
4
我觉得这是to_csv
里的一个bug。如果你想找解决办法,这里有几个方法。
要重新读取这个csv文件,可以指定表头行*:
In [11]: csv = "AA,BB,CC
DD,EE,FF
,,
a,b,c1
a,b,c2
a,b,c3"
In [12]: pd.read_csv(StringIO(csv), header=[0, 1])
Out[12]:
AA BB CC
DD EE FF
0 a b c1
1 a b c2
2 a b c3
*奇怪的是,这似乎会忽略空行。
如果要写入数据,可以先写表头,然后再追加数据:
with open('test.csv', 'w') as f:
f.write('\n'.join([','.join(h) for h in zip(*df.columns)]) + '\n')
df.to_csv('test.csv', mode='a', index=False, header=False)
注意这里的to_csv
部分是针对多重索引列的:
In [21]: '\n'.join([','.join(h) for h in zip(*df.columns)]) + '\n'
Out[21]: 'AA,BB,CC\nDD,EE,FF\n'
8
这虽然是个不太优雅的解决办法,但如果你现在就需要让某个东西能用,你可以把它分成两个部分来写:
>>> pd.DataFrame(df.columns.tolist()).T.to_csv("noblankrows.csv", mode="w", header=False, index=False)
>>> df.to_csv("noblankrows.csv", mode="a", header=False, index=False)
>>> !cat noblankrows.csv
AA,BB,CC
DD,EE,FF
a,b,c1
a,b,c2
a,b,c3