Python pandas: выводит dataframe в csv с целыми числами
У меня есть pandas.DataFrame
, который я хочу экспортировать в файл CSV. Однако pandas, кажется, записывает некоторые из значений как float
вместо типов int
. Я не мог найти, как изменить это поведение.
Создание фрейма данных:
df = pandas.DataFrame(columns=['a','b','c','d'], index=['x','y','z'], dtype=int)
x = pandas.Series([10,10,10], index=['a','b','d'], dtype=int)
y = pandas.Series([1,5,2,3], index=['a','b','c','d'], dtype=int)
z = pandas.Series([1,2,3,4], index=['a','b','c','d'], dtype=int)
df.loc['x']=x; df.loc['y']=y; df.loc['z']=z
Показать его:
>>> df
a b c d
x 10 10 NaN 10
y 1 5 2 3
z 1 2 3 4
Экспортировать его:
>>> df.to_csv('test.csv', sep='\t', na_rep='0', dtype=int)
>>> for l in open('test.csv'): print l.strip('\n')
a b c d
x 10.0 10.0 0 10.0
y 1 5 2 3
z 1 2 3 4
Почему десятки имеют нулевую точку?
Конечно, я мог бы просто вставить эту функцию в мой конвейер, чтобы переконвертировать весь CSV файл, но он кажется лишним:
def lines_as_integer(path):
handle = open(path)
yield handle.next()
for line in handle:
line = line.split()
label = line[0]
values = map(float, line[1:])
values = map(int, values)
yield label + '\t' + '\t'.join(map(str,values)) + '\n'
handle = open(path_table_int, 'w')
handle.writelines(lines_as_integer(path_table_float))
handle.close()
Ответы
Ответ 1
Ответ, который я искал, был небольшим изменением того, что @Jeff предложил в его ответе. Кредит принадлежит ему. Это то, что решило мою проблему в конце для справки:
import pandas
df = pandas.DataFrame(data, columns=['a','b','c','d'], index=['x','y','z'])
df = df.fillna(0)
df = df.astype(int)
df.to_csv('test.csv', sep='\t')
Ответ 2
Это "gotcha" в pandas (поддержка целочисленного NA), где целые столбцы с NaN преобразуются в float.
Этот компромисс сделан в основном по соображениям памяти и производительности, а также для того, чтобы результирующая серия оставалась "числовой". Одна из возможностей заключается в использовании массивов dtype=object
.
Ответ 3
Проблема заключается в том, что, поскольку вы назначаете вещи по строкам, но dtypes группируются по столбцам, поэтому вещи становятся отличными от object
dtype, что не очень хорошо, вы теряете всю эффективность. Таким образом, одним из способов является преобразование, которое будет принудительно использовать float/int dtype по мере необходимости.
Как мы ответили в другом вопросе, если вы сразу создадите фрейм (или построите столбец по столбцу), этот шаг не понадобится
In [23]: def convert(x):
....: try:
....: return x.astype(int)
....: except:
....: return x
....:
In [24]: df.apply(convert)
Out[24]:
a b c d
x 10 10 NaN 10
y 1 5 2 3
z 1 2 3 4
In [25]: df.apply(convert).dtypes
Out[25]:
a int64
b int64
c float64
d int64
dtype: object
In [26]: df.apply(convert).to_csv('test.csv')
In [27]: !cat test.csv
,a,b,c,d
x,10,10,,10
y,1,5,2.0,3
z,1,2,3.0,4
Ответ 4
Если вы хотите сохранить информацию NaN в экспортированном CSV файле, выполните следующие действия.
П.С.: В этом случае я концентрируюсь на столбце "С".
df[c] = df[c].fillna('') #filling Nan with empty string
df[c] = df[c].astype(str) #convert the column to string
>>> df
a b c d
x 10 10 10
y 1 5 2.0 3
z 1 2 3.0 4
df[c] = df[c].str.split('.') #split the float value into list based on '.'
>>> df
a b c d
x 10 10 [''] 10
y 1 5 ['2','0'] 3
z 1 2 ['3','0'] 4
df[c] = df[c].str[0] #select 1st element from the list
>>> df
a b c d
x 10 10 10
y 1 5 2 3
z 1 2 3 4
Теперь, если вы экспортируете фрейм данных в csv, столбец 'c' не будет иметь значений с плавающей запятой, и информация NaN будет сохранена.
Ответ 5
Вы можете использовать astype(), чтобы указать тип данных для каждого столбца
Например:
import pandas
df = pandas.DataFrame(data, columns=['a','b','c','d'], index=['x','y','z'])
df = df.astype({"a": int, "b": complex, "c" : float, "d" : int})
Ответ 6
В качестве обходного пути вы можете изменить свой DataFrame на массив Numpy:
np.savetxt(savepath, np.array(df).astype(np.int), fmt='%i', delimiter = ',', header= 'PassengerId,Survived', comments='')