Ersetzen von Pandas oder Numpy Nan durch None für MysqlDB


127

Ich versuche, einen Pandas-Datenrahmen (oder kann ein Numpy-Array verwenden) mit MysqlDB in eine MySQL-Datenbank zu schreiben. MysqlDB scheint 'nan' nicht zu verstehen und meine Datenbank gibt einen Fehler aus, der besagt, dass nan nicht in der Feldliste enthalten ist. Ich muss einen Weg finden, das 'nan' in einen NoneType umzuwandeln.

Irgendwelche Ideen?


2
Gibt es keine Einstellung , die Sie in Pandas ändern kann darauf zurück machen Nonefür NULLstatt nan?
Nathan Hinchey

Antworten:


193

@bogatron hat es richtig, Sie können verwenden where, es ist erwähnenswert, dass Sie dies nativ in Pandas tun können:

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

Hinweis: Dadurch wird der dtype aller Spalten in geändert object.

Beispiel:

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

Hinweis: Was Sie nicht tun können, ist eine Neufassung der DataFrames dtype, um alle Datentypen zuzulassen astype, und anschließend die DataFrame- fillnaMethode:

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

Leider weder diese, noch mit replace, arbeitet mit Nonesehen diese (geschlossen) Problem .


Abgesehen davon ist es erwähnenswert, dass Sie in den meisten Anwendungsfällen NaN nicht durch None ersetzen müssen. Lesen Sie diese Frage zum Unterschied zwischen NaN und None bei Pandas .

In diesem speziellen Fall scheint dies jedoch der Fall zu sein (zumindest zum Zeitpunkt dieser Antwort).



1
FWIW..dies wird auch den dtype der Spalten in Objekt ändern, es ist Ihnen aber wahrscheinlich egal
Jeff

@ Jeff Danke für den Link, seltsamerweise konnte ich ihn früher nicht finden! Ich dachte, es müsste den dtype ändern, um None zuzulassen, definitiv erwähnenswert!
Andy Hayden

nützlich, um vor dem Einfügen mit Django zu verwenden, um zu vermeiden, dass die np.nanKonvertierung in String"nan"
Shadi

Nützliche Einschränkung. Das macht Sinn , um eine Schleife durch nur die Spalten , die bereits sind dtypevon objectund tun es für diese und andere Arten unterschiedlich behandeln je nach Bedarf. Im Idealfall fillna(None)wäre super.
Vishal

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

Dank geht an diesen Kerl hier in dieser Github-Ausgabe .


2
Dies ist die beste Antwort, die Sie df.replace({np.nan: None})als temporäres Objekt verwenden können
Matt

17

Sie können ersetzen nanmit Nonein Ihrer numpy Array:

>>> 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
Das einzige mögliche Problem ist die Änderung von dtype, x.dtypeist dtype('float64'), während y.dtypeist dtype('object').
Jaime

10

Nachdem ich herumgestolpert war, funktionierte das für mich:

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

4

Nur eine Ergänzung zu @Andy Haydens Antwort:

Da DataFrame.maskes sich um den entgegengesetzten Zwilling handelt DataFrame.where, haben sie genau die gleiche Signatur, jedoch mit entgegengesetzter Bedeutung:

  • DataFrame.whereist nützlich, um Werte zu ersetzen, bei denen die Bedingung False ist .
  • DataFrame.maskwird zum Ersetzen von Werten verwendet, bei denen die Bedingung True ist .

In dieser Frage ist die Verwendung df.mask(df.isna(), other=None, inplace=True)möglicherweise intuitiver.


2

Ein weiterer Zusatz: Seien Sie vorsichtig, wenn Sie Vielfache ersetzen und den Spaltentyp vom Objekt zum Float zurückkonvertieren . Wenn Sie sicher sein möchten, dass Ihre Nonenicht zu np.NaNden Vorschlägen von @ andy-hayden zurückkehren pd.where. Illustration, wie das Ersetzen immer noch "schief" gehen kann:

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

Vielen Dank für das Hinzufügen. Ich gehe die Dokumentation noch einmal durch und kann dieses Verhalten immer noch nicht verstehen. Wie auch immer, dies kann .replace({np.nan: None})
umgangen werden,

1
Ja, Sie können zum Schluss noch eine hinzufügen replace({np.nan: None}). Mein Kommentar wurde hinzugefügt, um auf die mögliche Gefahr beim Ersetzen hinzuweisen np.nan. Das obige hat mich sicherlich ein bisschen gestolpert!
Gaatjeniksaan

1

Ziemlich alt, aber ich bin auf das gleiche Problem gestoßen. Versuchen Sie Folgendes:

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

funktioniert nicht, wenn der
Spaltendatentyp
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.