Sostituzione di Pandas o Numpy Nan con None da utilizzare con MysqlDB


128

Sto cercando di scrivere un dataframe Pandas (o posso usare un array numpy) su un database mysql usando MysqlDB. MysqlDB non sembra capire "nan" e il mio database restituisce un errore dicendo che nan non è nell'elenco dei campi. Devo trovare un modo per convertire "nan" in un NoneType.

Qualche idea?


2
Non c'è ambiente si può cambiare in Pandas per farla tornare Noneper NULLinvece di nan?
Nathan Hinchey

Risposte:


195

@bogatron ha ragione, puoi usarlo where, vale la pena notare che puoi farlo in modo nativo nei panda:

df1 = df.where(pd.notnull(df), None)

Nota: questo cambia il dtype di tutte le colonne in object.

Esempio:

In [1]: df = pd.DataFrame([1, np.nan])

In [2]: df
Out[2]: 
    0
0   1
1 NaN

In [3]: df1 = df.where(pd.notnull(df), None)

In [4]: df1
Out[4]: 
      0
0     1
1  None

Nota: cosa non puoi fare rifusione dei DataFrame dtypeper consentire tutti i tipi di dati, utilizzando astype, e quindi il fillnametodo DataFrame :

df1 = df.astype(object).replace(np.nan, 'None')

Sfortunatamente né questo, né l'utilizzo replace, funziona con Nonevedere questo problema (chiuso) .


Per inciso, vale la pena notare che per la maggior parte dei casi d'uso non è necessario sostituire NaN con Nessuno, vedere questa domanda sulla differenza tra NaN e Nessuno nei panda .

Tuttavia, in questo caso specifico sembra che tu lo faccia (almeno al momento di questa risposta).



1
FWIW..questo cambierà anche il dtype delle colonne in oggetto, probabilmente non ti interessa però
Jeff

@ Jeff Grazie per il collegamento, stranamente non sono riuscito a trovarlo prima! Ho pensato che doveva cambiare il dtype per consentire Nessuno, sicuramente degno di nota!
Andy Hayden

utile da usare prima dell'inserimento con Django per evitare che np.nanvenga convertito in stringa"nan"
shadi

Avvertimento utile. Senso per scorrere solo le colonne che sono già dtypedi objecte fanno per quelle e gestiscono altri tipi diverso come necessario. Idealmente, fillna(None)sarebbe fantastico.
Vishal

83
df = df.replace({np.nan: None})

Il merito va a questo ragazzo qui su questo problema di GitHub .


4
questa è la risposta migliore che puoi usare df.replace({np.nan: None})come oggetto temporaneo
Matt

17

Puoi sostituire nancon Nonenel tuo array numpy:

>>> x = np.array([1, np.nan, 3])
>>> y = np.where(np.isnan(x), None, x)
>>> print y
[1.0 None 3.0]
>>> print type(y[1])
<type 'NoneType'>

2
L'unica potenziale preoccupazione è il cambiamento di dtype, x.dtypeis dtype('float64'), while y.dtypeis dtype('object').
Jaime

10

Dopo essere inciampato, questo ha funzionato per me:

df = df.astype(object).where(pd.notnull(df),None)

4

Solo un'aggiunta alla risposta di @Andy Hayden:

Poiché DataFrame.maskè il gemello opposto di DataFrame.where, hanno esattamente la stessa firma ma con significato opposto:

  • DataFrame.whereè utile per sostituire i valori in cui la condizione è False .
  • DataFrame.maskviene utilizzato per sostituire i valori in cui la condizione è vera .

Quindi, in questa domanda, l'utilizzo df.mask(df.isna(), other=None, inplace=True)potrebbe essere più intuitivo.


2

Un'altra aggiunta: fare attenzione quando si sostituiscono i multipli e si riconverte il tipo di colonna da oggetto a mobile . Se vuoi essere certo che il tuo Nonenon ritorni a np.NaN's applica il suggerimento di @ andy-hayden con l'utilizzo pd.where. Illustrazione di come la sostituzione può ancora andare "storta":

In [1]: import pandas as pd

In [2]: import numpy as np

In [3]: df = pd.DataFrame({"a": [1, np.NAN, np.inf]})

In [4]: df
Out[4]:
     a
0  1.0
1  NaN
2  inf

In [5]: df.replace({np.NAN: None})
Out[5]:
      a
0     1
1  None
2   inf

In [6]: df.replace({np.NAN: None, np.inf: None})
Out[6]:
     a
0  1.0
1  NaN
2  NaN

In [7]: df.where((pd.notnull(df)), None).replace({np.inf: None})
Out[7]:
     a
0  1.0
1  NaN
2  NaN

Grazie per aver aggiunto questo. Rivedendo la documentazione, ancora non riesco a capire questo comportamento. Ad ogni modo, questo può essere aggirato concatenandone un altro.replace({np.nan: None})
EliadL

1
Sì, potresti finire aggiungendone un altro replace({np.nan: None}). Il mio commento è stato aggiunto per sottolineare la potenziale insidia durante la sostituzione np.nandi. Quanto sopra mi ha sicuramente fatto impazzire per un po '!
gaatjeniksaan

1

Abbastanza vecchio, eppure mi sono imbattuto nello stesso problema. Prova a farlo:

df['col_replaced'] = df['col_with_npnans'].apply(lambda x: None if np.isnan(x) else x)

non funziona se il tipo di dati della colonna è numerico perché Nessuno viene riconvertito in nan (panda 0.23)
shadi
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.