web-dev-qa-db-fra.com

Python pandas: sortie de la trame de données vers csv avec des entiers

J'ai un pandas.DataFrame que je souhaite exporter vers un fichier CSV. Cependant, pandas semble écrire certaines des valeurs en tant que types float au lieu de int. Je n'ai pas pu trouver comment changer ce comportement.

Construire un bloc de données:

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

Voir:

>>> df
    a   b    c   d
x  10  10  NaN  10
y   1   5    2   3
z   1   2    3   4

Exportez-le:

>>> 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

Pourquoi les dizaines ont-elles un point zéro?

Bien sûr, je pourrais simplement coller cette fonction dans mon pipeline pour reconvertir tout le fichier CSV, mais cela semble inutile:

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()
28
xApple

La réponse que je cherchais était une légère variation de ce que @Jeff proposait dans sa réponse. Le mérite lui revient. C'est ce qui a résolu mon problème à la fin pour référence:

    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')
12
xApple

Il s'agit d'un "gotcha" in pandas (Support for integer NA) , où les colonnes entières avec NaN sont converties en flottants.

Ce compromis est effectué en grande partie pour des raisons de mémoire et de performances, et aussi pour que la série résultante continue à être "numérique". Une possibilité consiste à utiliser dtype=object tableaux à la place.

11
Andy Hayden

Le problème est que puisque vous affectez des choses par lignes, mais que les dtypes sont regroupés par colonnes, les choses sont donc converties en object dtype, ce qui n'est pas une bonne chose, vous perdez toute efficacité. Donc, une façon consiste à convertir ce qui contraindra à float/int dtype selon les besoins.

Comme nous l'avons répondu dans une autre question, si vous construisez le cadre en une seule fois (ou construisez colonne par colonne) cette étape ne sera pas nécessaire

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
7
Jeff

Si vous souhaitez conserver les informations NaN dans le fichier csv que vous avez exporté, procédez comme suit. P.S: Je me concentre sur la colonne 'C' dans ce cas.

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

Maintenant, si vous exportez la trame de données vers csv, la colonne 'c' n'aura pas de valeurs flottantes et les informations NaN seront conservées.

3
Tad

Vous pouvez utiliser astype () pour spécifier le type de données pour chaque colonne

Par exemple:

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})
0
appsdownload