Python Pandas, запишите DataFrame в файл с фиксированной шириной (to_fwf?)

Я вижу, что у Pandas есть read_fwf, но есть ли что-то вроде DataFrame.to_fwf? Я ищу поддержку ширины поля, числовой точности и выравнивания строк. Кажется, DataFrame.to_csv этого не делает. numpy.savetxt делает, но я бы не хотел этого делать:

numpy.savetxt('myfile.txt', mydataframe.to_records(), fmt='some format')

Это кажется неправильным. Ваши идеи очень ценятся.


person jkmacc    schedule 10.05.2013    source источник
comment
взгляните на метод to_string, чтобы увидеть, можете ли вы делать то, что хотите.   -  person zach    schedule 13.05.2013
comment
Это выглядит близко. Кажется, мне пришлось бы указать функцию форматирования для каждого столбца, если бы любые два столбца с плавающей запятой или строкой имели разные форматы. Это бы сработало, просто выглядит немного громоздко. Я надеялся, что что-то упустил. Спасибо!   -  person jkmacc    schedule 13.05.2013
comment
pandas df.to_csv имеет параметр sep =, который изменяет запятую на что-либо еще, в данном случае пробел или пустую строку. Что в связке с форматером метода должно это делать.   -  person Joop    schedule 14.06.2013
comment
@Joop На самом деле с методом df.to_csv(), использующим пустую строку в качестве разделителя, возникает ошибка TypeError: delimiter must be set.   -  person pbreach    schedule 17.01.2015
comment
true .. передача пустой строки в метод приведет к беспорядку, игнорируйте мою ссылку на пустую строку. возможно, поможет метод pandas to_string. если есть параметр форматирования, это довольно хорошо   -  person Joop    schedule 02.02.2015


Ответы (7)


Пока кто-то не реализует это в 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
person Matt Kramer    schedule 13.03.2016
comment
Это сработало элегантно для меня. Намного разумнее возиться с форматированием строкового пространства вручную. - person DeusXMachina; 03.02.2017

Для пользовательского формата для каждого столбца вы можете установить формат для всей строки. Параметр 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)
person Amir Uteuov    schedule 14.09.2017

Python, Pandas: запись содержимого DataFrame в текстовый файл

Ответ на вопрос выше помог мне. Это не самое лучшее, но пока to_fwf не существует, это поможет мне...

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

or

np.savetxt(r'c:\data\np.txt', df.values, fmt='%10.5f')
person brandog    schedule 26.06.2016
comment
IMO, это лучше, чем tabulate, так как numpy включен в pandas, поэтому не требует дополнительной библиотеки. - person maxymoo; 09.03.2017

Я уверен, что вы нашли обходной путь для этой проблемы, но для всех, кому любопытно... Если вы записываете DF в список, вы можете записать его в файл, задав «формат как строку». список индексов), например:

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

Просто убедитесь, что каждый индекс соответствует правильному формату :)

Надеюсь, это поможет!

person leon yin    schedule 30.07.2015

pandas.DataFrame.to_string() — это все, что вам нужно. Единственный трюк заключается в том, как управлять индексом.

Игнорировать индекс

Если вас не волнует индекс:

# write
df.to_string(filepath, index=False)

# read
df = pd.read_fwf(filepath)

Индекс ручки

Если вы хотите получить pandas.Index или pandas.MultiIndex:

# write
df.reset_index().to_string(filepath, index=False)

# read
df = pd.read_fwf(filepath).set_index(index_names)

Если ваш Index не имеет имени при написании, reset_index() должен назначить его столбцу "index".

Если ваш MultiIndex не имеет имен, он должен быть назначен столбцам ["level_0", "level_1", ...].

person Alexandre Huat    schedule 15.09.2020

нашел очень простое решение! (Питон). В снятом коде я пытаюсь записать DataFrame в позиционный файл. «finalDataFrame.values.tolist()» вернет вам список, в котором каждая строка DataFrame превращается в другой список, просто [['Camry',2019,'Toyota'],['Mustang','2016', «Форд»]. после этого с помощью цикла 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')
person zubin patel    schedule 22.02.2019

Основываясь на ответах других, вот фрагмент, который я написал, не лучший в кодировании и производительности:

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

person Chen Du    schedule 25.09.2020