Convertire i galleggianti in in panda?


230

Ho lavorato con i dati importati da un CSV. Panda ha cambiato alcune colonne in virgola mobile, quindi ora i numeri in queste colonne vengono visualizzati come punti mobili! Tuttavia, ho bisogno che vengano visualizzati come numeri interi o, senza virgola. C'è un modo per convertirli in numeri interi o non visualizzare la virgola?


22
È possibile modificare il tipo (purché non vi siano valori mancanti)df.col = df.col.astype(int)
EdChum

Questa domanda è composta da due domande contemporaneamente e il titolo di questa domanda ne riflette solo una.
Monica Heddneck,

Per un popolo che colpisce quanto sopra e lo trova utile nel concetto ma non funziona per te, questa è la versione che ha funzionato per me in Python 3.7.5 con df = df.astype(int)
Panda

Risposte:


217

Per modificare l'output float, procedere come segue:

df= pd.DataFrame(range(5), columns=['a'])
df.a = df.a.astype(float)
df

Out[33]:

          a
0 0.0000000
1 1.0000000
2 2.0000000
3 3.0000000
4 4.0000000

pd.options.display.float_format = '{:,.0f}'.format
df

Out[35]:

   a
0  0
1  1
2  2
3  3
4  4

16
Grazie! Ho modificato questo nel mio to_csv: fin.to_csv ('my_table.csv', float_format = '%. F'). Ha funzionato!
MJP,

4
Nell'ultima versione di Panda è necessario aggiungere copy = False agli argomenti di astype per evitare un avvertimento
g.stevo

È necessario farlo df.a = df.a.astype(float)? Questo crea una copia (non copysei sicuro di come astype()viene utilizzato il parametro )? Ad ogni modo aggiornare il tipo "sul posto"?
Mr_and_Mrs_D

1
@EdChum, c'è un modo per impedire ai Panda di convertire i tipi per cominciare? Ad esempio, prova a DF.({'200': {'#': 354, '%': 0.9971830985915493}, '302': {'#': 1, '%': 0.0028169014084507044}}) notare che # viene convertito in float e sono righe, non colonne. perché ognuno è un Seriesche può memorizzare solo un singolo tipo uniforme?
alancalvitti,

@alancalvitti qual è la tua intenzione qui per preservare i valori o il dtype? Se è dtypeallora è necessario creare quelle colonne in dtype objectmodo da consentire il misto, altrimenti il ​​mio consiglio sarebbe di usare solo float e quando si fanno i confronti usarenp.isclose
EdChum

180

Utilizzare la pandas.DataFrame.astype(<type>)funzione per manipolare i tipi di colonna.

>>> df = pd.DataFrame(np.random.rand(3,4), columns=list("ABCD"))
>>> df
          A         B         C         D
0  0.542447  0.949988  0.669239  0.879887
1  0.068542  0.757775  0.891903  0.384542
2  0.021274  0.587504  0.180426  0.574300
>>> df[list("ABCD")] = df[list("ABCD")].astype(int)
>>> df
   A  B  C  D
0  0  0  0  0
1  0  0  0  0
2  0  0  0  0

MODIFICARE:

Per gestire i valori mancanti:

>>> df
          A         B     C         D
0  0.475103  0.355453  0.66  0.869336
1  0.260395  0.200287   NaN  0.617024
2  0.517692  0.735613  0.18  0.657106
>>> df[list("ABCD")] = df[list("ABCD")].fillna(0.0).astype(int)
>>> df
   A  B  C  D
0  0  0  0  0
1  0  0  0  0
2  0  0  0  0

3
Ho provato il tuo approccio e mi dà un ValueError: impossibile convertire NA in numero intero
MJP

6
@MJP Non puoi convertire le serie da float a intero se ci sono valori mancanti vedi pandas.pydata.org/pandas-docs/stable/… , devi usare float
EdChum

2
I valori non mancano, ma la colonna non specifica un valore per ogni riga di proposito. C'è un modo per ottenere una soluzione alternativa? Dato che quei valori sono ID chiave esterna, ho bisogno di ints.
MJP,

4
Ho fatto una modifica in cui tutte le NaN sono sostituite con una 0.0.
Ryan G,

3
O meglio ancora, se stai solo modificando un CSV, allora: df.to_csv ("path.csv", na_rep = "", float_format = "%. 0f", index = False) Ma questo modificherà tutti i float, quindi potrebbe essere meglio convertire la colonna FK in una stringa, eseguire la manipolazione e quindi salvare.
Ryan G,

44

Considerando il seguente frame di dati:

>>> df = pd.DataFrame(10*np.random.rand(3, 4), columns=list("ABCD"))
>>> print(df)
...           A         B         C         D
... 0  8.362940  0.354027  1.916283  6.226750
... 1  1.988232  9.003545  9.277504  8.522808
... 2  1.141432  4.935593  2.700118  7.739108

Utilizzando un elenco di nomi di colonna, modificare il tipo per più colonne con applymap():

>>> cols = ['A', 'B']
>>> df[cols] = df[cols].applymap(np.int64)
>>> print(df)
...    A  B         C         D
... 0  8  0  1.916283  6.226750
... 1  1  9  9.277504  8.522808
... 2  1  4  2.700118  7.739108

O per una singola colonna con apply():

>>> df['C'] = df['C'].apply(np.int64)
>>> print(df)
...    A  B  C         D
... 0  8  0  1  6.226750
... 1  1  9  9  8.522808
... 2  1  4  2  7.739108

5
Cosa succede se nel valore è presente una NaN?
Zhang18

3
@ Zhang18 Ho provato questa soluzione e in caso di NaN hai questo errore:ValueError: ('cannot convert float NaN to integer', u'occurred at index <column_name>')
enri

2
@enri: può provare il seguente codice -df['C'] = df['C'].dropna().apply(np.int64)
vsdaking

12

Questa è una soluzione rapida nel caso in cui desideri convertire più colonne del tuo pandas.DataFrameda float a numero intero considerando anche il caso in cui puoi avere valori NaN.

cols = ['col_1', 'col_2', 'col_3', 'col_4']
for col in cols:
   df[col] = df[col].apply(lambda x: int(x) if x == x else "")

Ho provato con else x)e else None), ma il risultato ha ancora il numero float, quindi l'ho usato else "".


applicherà ""a tutti i valori incol
Raheel

Applicherà una stringa vuota ("") a tutti i valori mancanti, se è quello che è richiesto, ma il resto dei valori sarà intero.
Krzysztof Słowiński

Grazie per questo. Funzionava quando .astype () e .apply (np.int64) no.
Alison S,

Questo sembra disordinato, e non vedo alcun motivo per usarlo sopra le molte alternative disponibili.
AMC

8

Espandendo su @Ryan G menzionato l'uso del pandas.DataFrame.astype(<type>)metodo, si può usare l' errors=ignoreargomento per convertire solo quelle colonne che non producono un errore, il che semplifica notevolmente la sintassi. Ovviamente, bisogna prestare attenzione quando si ignorano gli errori, ma per questo compito è molto utile.

>>> df = pd.DataFrame(np.random.rand(3, 4), columns=list('ABCD'))
>>> df *= 10
>>> print(df)
...           A       B       C       D
... 0   2.16861 8.34139 1.83434 6.91706
... 1   5.85938 9.71712 5.53371 4.26542
... 2   0.50112 4.06725 1.99795 4.75698

>>> df['E'] = list('XYZ')
>>> df.astype(int, errors='ignore')
>>> print(df)
...     A   B   C   D   E
... 0   2   8   1   6   X
... 1   5   9   5   4   Y
... 2   0   4   1   4   Z

Dai documenti pandas.DataFrame.astype :

errori: {'raise', 'ignore'}, predefinito 'raise'

Controllare la raccolta di eccezioni su dati non validi per il tipo fornito.

  • rilancio: consente di sollevare eccezioni
  • ignora: elimina le eccezioni. In caso di errore, restituire l'oggetto originale

Novità nella versione 0.20.0.


7
>>> import pandas as pd
>>> right = pd.DataFrame({'C': [1.002, 2.003], 'D': [1.009, 4.55], 'key': ['K0', 'K1']})
>>> print(right)
           C      D key
    0  1.002  1.009  K0
    1  2.003  4.550  K1
>>> right['C'] = right.C.astype(int)
>>> print(right)
       C      D key
    0  1  1.009  K0
    1  2  4.550  K1

5

Per convertire tutte le colonne float in int

>>> df = pd.DataFrame(np.random.rand(5, 4) * 10, columns=list('PQRS'))
>>> print(df)
...     P           Q           R           S
... 0   4.395994    0.844292    8.543430    1.933934
... 1   0.311974    9.519054    6.171577    3.859993
... 2   2.056797    0.836150    5.270513    3.224497
... 3   3.919300    8.562298    6.852941    1.415992
... 4   9.958550    9.013425    8.703142    3.588733

>>> float_col = df.select_dtypes(include=['float64']) # This will select float columns only
>>> # list(float_col.columns.values)
>>> for col in float_col.columns.values:
...     df[col] = df[col].astype('int64')
>>> print(df)
...     P   Q   R   S
... 0   4   0   8   1
... 1   0   9   6   3
... 2   2   0   5   3
... 3   3   8   6   1
... 4   9   9   8   3

0

Ecco una semplice funzione che downcast galleggia nel tipo intero più piccolo possibile che non perde alcuna informazione. Per esempio,

  • 100.0 può essere convertito da float a intero, ma 99.9 no (senza perdere informazioni per arrotondamento o troncamento)

  • Inoltre, 1.0 può essere downcastizzato fino in fondo int8senza perdere informazioni, ma il tipo intero più piccolo per 100_000.0 èint32

Esempi di codice:

import numpy as np
import pandas as pd

def float_to_int( s ):
    if ( s.astype(np.int64) == s ).all():
        return pd.to_numeric( s, downcast='integer' )
    else:
        return s

# small integers are downcast into 8-bit integers
float_to_int( np.array([1.0,2.0]) )
Out[1]:array([1, 2], dtype=int8)

# larger integers are downcast into larger integer types
float_to_int( np.array([100_000.,200_000.]) )
Out[2]: array([100000, 200000], dtype=int32)

# if there are values to the right of the decimal
# point, no conversion is made
float_to_int( np.array([1.1,2.2]) )
Out[3]: array([ 1.1,  2.2])

0

Le colonne che devono essere convertite in int possono essere menzionate in un dizionario anche come di seguito

df = df.astype({'col1': 'int', 'col2': 'int', 'col3': 'int'})

-5
>>> df_18['cyl'].value_counts()
... 4.0     365
... 6.0     246
... 8.0     153

>>> df_18['cyl'] = df_18['cyl'].astype(int)
>>> df_18['cyl'].value_counts()
... 4     365
... 6     246
... 8     153

1
astype(int)è stato già menzionato più volte. Questa risposta non aggiunge nulla di nuovo.
Georgy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.