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?

Rishi
quelle
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).

Andy Hayden
quelle
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 .

EliadL
quelle
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'>
Bogatron
quelle
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)
Rodney Cox
quelle
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.

YaOzI
quelle
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
gaatjeniksaan
quelle
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)
Robin Nemeth
quelle
funktioniert nicht, wenn der
Spaltendatentyp