Python Pandas,将DataFrame写入定宽文件(to_fwf?)

25
我发现Pandas有read_fwf,但是它是否有类似于DataFrame.to_fwf的东西呢?我正在寻找对字段宽度、数字精度和字符串对齐方式的支持。似乎DataFrame.to_csv没有此功能。numpy.savetxt提供了这个功能,但我不想这样做:
numpy.savetxt('myfile.txt', mydataframe.to_records(), fmt='some format')

那看起来不太对。感谢您的想法。


5
请查看 to_string 方法,看看它是否可以实现你想要的功能。 - zach
这看起来很接近。如果任何两个浮点或字符串列具有不同的格式,则似乎我必须为每个列提供一个格式化程序函数。它可以解决问题,但看起来有些笨重。我希望我错过了什么。谢谢! - jkmacc
1
pandas的df.to_csv方法有一个*sep=" "*参数,可以将逗号更改为其他任何字符,比如空格或空字符串。结合该方法的格式化程序即可实现。 - Joop
1
@Joop 实际上,使用空字符串作为分隔符的 df.to_csv() 方法会导致错误 TypeError: delimiter must be set - pbreach
1
true。将空字符串传递给方法会造成混乱,请忽略我的空字符串引用。也许尝试使用Pandas的“to_string”方法会有所帮助。如果有格式化参数,那就很好。 - Joop
7个回答

27

在pandas中有人实现此功能之前,您可以使用tabulate软件包:

import pandas as pd
from tabulate import tabulate

def to_fwf(df, fname):
    content = tabulate(df.values.tolist(), list(df.columns), tablefmt="plain")
    open(fname, "w").write(content)

pd.DataFrame.to_fwf = to_fwf

9

对于每一列的自定义格式,您可以设置整行的格式。fmt参数为每一行提供格式。

with open('output.dat') as ofile:
     fmt = '%.0f %02.0f %4.1f %3.0f %4.0f %4.1f %4.0f %4.1f %4.0f'
     np.savetxt(ofile, df.values, fmt=fmt)

8

pandas.DataFrame.to_string()足以胜任。唯一的技巧在于如何管理索引。

# Write
# df.reset_index(inplace=True)  # uncomment if the index matters
df.to_string(filepath, index=False)

# Read
df = pd.read_fwf(filepath)
# df.set_index(index_names, inplace=True)  # uncomment if the index matters

如果索引是没有名称的 pandas.Indexreset_index() 应该将其分配给列 "index"。如果它是没有名称的 pandas.MultiIndex,它应该被分配到列 ["level_0", "level_1", ...]

1
请注意,Dataframe.to_string() 没有选项可以删除输出列之间的空格。 - Jaime M.
@JaimeM。很抱歉,我不明白它与问题有什么关系。 - Alexandre Huat
1
Dataframe.to_string() 无法在列之间不加空格地输出字符串,因此无法生成固定宽度的文件行。例如,当列长度为1个字符且左对齐时,to_string() 将输出:x yyy...,但您需要的是 xyyy... - Jaime M.
1
固定宽度格式不使用列分隔符。因为每个列都有固定的宽度,所以您知道每个列的开始和结束位置。在值和限制列之间使用空格填充,因此您可以使用 str.replace() - Jaime M.
检查这个答案以获取固定宽度格式的优势概述。 - Jaime M.
显示剩余3条评论

7

Python, Pandas : 将DataFrame的内容写入文本文件

上面的问题答案帮助了我。虽然不是最好的方法,但在没有 to_fwf 的情况下这也可以解决我的问题...

np.savetxt(r'c:\data\np.txt', df.values, fmt='%d')

或者

np.savetxt(r'c:\data\np.txt', df.values, fmt='%10.5f')

在我看来,这比tabulate更好,因为pandas包含了numpy,所以不需要额外的库。 - maxymoo

4

我相信你已经找到了解决这个问题的方法,但是对于其他好奇的人... 如果你把DF写入一个列表中,你可以通过给出“格式化字符串”的方式将其写入文件。.format(list indices) 例如:

df=df.fillna('')
outF = 'output.txt'      
dbOut = open(temp, 'w')
v = df.values.T.tolist()        
for i in range(0,dfRows):       
    dbOut.write(( \
    '{:7.2f}{:>6.2f}{:>2.0f}{:>4.0f}{:>5.0f}{:6.2f}{:6.2f}{:6.2f}{:6.1f {:>15}{:>60}'\
    .format(v[0][i],v[1][i],v[2][i],v[3][i],v[4][i],v[5][i],v[6][i],v[7][i],v[8][i],\
    v[9][i],v[10][i]) ))
    dbOut.write("\n")
dbOut.close

请确保每个索引与正确的格式匹配 :)

希望这能帮到你!


1

我找到了一个非常简单的解决方案!(Python)。在代码片段中,我正在尝试将DataFrame写入位置文件。"finalDataFrame.values.tolist()"将返回一个列表,其中DataFrame的每一行都被转换为另一个列表,例如[['Camry',2019,'Toyota'],['Mustang','2016','Ford']]。之后,通过for循环和if语句来设置其固定长度。其余部分很明显!

 with open (FilePath,'w') as f:
    for i in finalDataFrame.values.tolist():
        widths=(0,0,0,0,0,0,0)
        if i[2] == 'nan':
            i[2]=''
            for h in range(7):
                i[2]= i[2] + ' '
        else:
            x=7-len(str(i[2]))
            a=''
            for k in range(x):
               a=a+' '
            i[2]=str(i[2])+a

        if i[3] == '':
            i[3]=''
            for h in range(25):
                i[3]=i[3]+' '
        else:
            x = 25 - len(i[3])
            print(x)
            a = ''
            for k in range(x):
                a = a + ' '
            print(a)
            i[3] = i[3] + a


        i[4] = str(i[4])[:10]

        q="".join("%*s" % i for i in zip(widths, i))
        f.write(q+'\n')

0

根据他人的答案,这是我编写的代码片段,不是编码和性能最佳的:

import pandas as pd
import pickle
import numpy as np
from tabulate import tabulate


left_align_gen = lambda length, value: eval(r"'{:<<<length>>}'.format('''<<value>>'''[0:<<length>>])".replace('<<length>>', str(length)).replace('<<value>>', str(value)))
right_align_gen = lambda length, value: eval(r"'{:><<length>>}'.format('''<<value>>'''[0:<<length>>])".replace('<<length>>', str(length)).replace('<<value>>', str(value)))

# df = pd.read_pickle("dummy.pkl")
with open("df.pkl", 'rb') as f:
    df = pickle.load(f)

# field width defines here, width of each field
widths=(22, 255, 14, 255, 14, 255, 255, 255, 255, 255, 255, 22, 255, 22, 255, 255, 255, 22, 14, 14, 255, 255, 255, 2, )

# format datetime
df['CREATED_DATE'] = df['CREATED_DATE'].apply(lambda x: x.to_pydatetime().strftime('%Y%m%d%H%M%S'))
df['LAST_MODIFIED_DATE'] = df['LAST_MODIFIED_DATE'].apply(lambda x: x.to_pydatetime().strftime('%Y%m%d%H%M%S'))
df['TERMS_ACCEPTED_DATE'] = df['TERMS_ACCEPTED_DATE'].apply(lambda x: x.to_pydatetime().strftime('%Y%m%d%H%M%S'))
df['PRIVACY_ACCEPTED_DATE'] = df['PRIVACY_ACCEPTED_DATE'].apply(lambda x: x.to_pydatetime().strftime('%Y%m%d%H%M%S'))


# print(type(df.iloc[0]['CREATED_DATE']))
# print(df.iloc[0])
record_line_list = []
# for row in df.iloc[:10].itertuples():
for row in [tuple(x) for x in df.to_records(index=False)]:
    record_line_list.append("".join(left_align_gen(length, value) for length, value in zip(widths, row)))

with open('output.txt', 'w') as f:
    f.write('\n'.join(record_line_list))

Github要点


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