Remplacement de Pandas ou Numpy Nan par un None à utiliser avec MysqlDB

128

J'essaye d'écrire un dataframe Pandas (ou je peux utiliser un tableau numpy) dans une base de données mysql en utilisant MysqlDB. MysqlDB ne semble pas comprendre «nan» et ma base de données renvoie une erreur disant que nan n'est pas dans la liste des champs. J'ai besoin de trouver un moyen de convertir le «nan» en NoneType.

Des idées?

Rishi
la source
2
N'y a-t-il aucun paramètre que vous pouvez modifier dans Pandas pour le faire revenir Noneà la NULLplace nan?
Nathan Hinchey

Réponses:

195

@bogatron a raison, vous pouvez utiliser where, il convient de noter que vous pouvez le faire nativement dans les pandas:

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

Remarque: cela change le dtype de toutes les colonnes en object.

Exemple:

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

Remarque: ce que vous ne pouvez pas refondre les DataFrames dtypepour autoriser tous les types de types de données, en utilisant astype, puis la fillnaméthode DataFrame :

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

Malheureusement, ni cela, ni l'utilisation replace, ne fonctionne avec Nonevoir ce problème (fermé) .


En passant, il convient de noter que pour la plupart des cas d'utilisation, vous n'avez pas besoin de remplacer NaN par None, voir cette question sur la différence entre NaN et None dans les pandas .

Cependant, dans ce cas précis, il semble que vous le fassiez (du moins au moment de cette réponse).

Andy Hayden
la source
1
FWIW..this changera également le dtype des colonnes en object, vous ne vous en souciez probablement pas
Jeff
@Jeff Merci pour le lien, bizarrement je n'ai pas pu le trouver plus tôt! J'ai pensé qu'il fallait changer le type de dtype pour autoriser None, ce qui vaut vraiment la peine d'être mentionné!
Andy Hayden
utile à utiliser avant l'insertion avec Django pour éviter d' np.nanêtre converti en chaîne"nan"
shadi
Mise en garde utile. Il est logique de parcourir uniquement les colonnes qui sont déjà dtypede objectet de le faire pour celles-ci et de gérer les autres types différemment selon les besoins. Idéalement, ce fillna(None)serait formidable.
Vishal
83
df = df.replace({np.nan: None})

Le mérite revient à ce gars ici sur ce problème Github .

EliadL
la source
4
c'est la meilleure réponse que vous pouvez utiliser df.replace({np.nan: None})comme objet temporaire
Matt
17

Vous pouvez remplacer nanpar Nonedans votre tableau 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'>
Bogatron
la source
2
La préoccupation que le potentiel est le changement de dtype, x.dtypeest dtype('float64'), tout en y.dtypeest dtype('object').
Jaime
10

Après avoir trébuché, cela a fonctionné pour moi:

df = df.astype(object).where(pd.notnull(df),None)
rodney cox
la source
4

Juste un ajout à la réponse de @Andy Hayden:

Puisqu'il DataFrame.masks'agit du jumeau opposé de DataFrame.where, ils ont exactement la même signature mais avec une signification opposée:

  • DataFrame.whereest utile pour remplacer des valeurs où la condition est False .
  • DataFrame.maskest utilisé pour le remplacement des valeurs où la condition est True .

Donc, dans cette question, l'utilisation df.mask(df.isna(), other=None, inplace=True)pourrait être plus intuitive.

YaOzI
la source
2

Autre ajout: soyez prudent lors du remplacement des multiples et de la conversion du type de colonne d' objet en flottant . Si vous voulez être certain que votre None's ne reviendra pas à np.NaN' s appliquez @ andy-hayden's suggestion avec using pd.where. Illustration de la façon dont le remplacement peut toujours tourner mal:

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
gaatjeniksaan
la source
Merci d'avoir ajouté ceci. En revoyant à nouveau la documentation, je ne comprends toujours pas ce comportement. Quoi qu'il en soit, cela peut être contourné en enchaînant encore un autre.replace({np.nan: None})
EliadL
1
Oui, vous pouvez terminer en en ajoutant un autre replace({np.nan: None}). Mon commentaire a été ajouté pour souligner le piège potentiel lors du remplacement np.nande. Ce qui précède m'a certainement fait trébucher un peu!
gaatjeniksaan
1

Assez vieux, mais je suis tombé sur le même problème. Essayez de faire ceci:

df['col_replaced'] = df['col_with_npnans'].apply(lambda x: None if np.isnan(x) else x)
Robin Nemeth
la source
ne fonctionne pas si le type de données de la colonne est numérique car None est simplement reconverti en nan (pandas 0.23)
shadi