Zastąpienie Pandas lub Numpy Nan brakiem do użycia z MysqlDB

129

Próbuję napisać Dataframe Pandas (lub można użyć tablicy numpy) do bazy danych mysql przy użyciu MysqlDB. Wydaje się, że MysqlDB nie rozumie „nan”, a moja baza danych wyświetla błąd informujący, że nan nie ma na liście pól. Muszę znaleźć sposób na przekonwertowanie „nan” na NoneType.

Jakieś pomysły?

Rishi
źródło
2
Czy nie ma ustawienie można zmienić w Pandy, aby powrócić Nonedo NULLzamiast nan?
Nathan Hinchey

Odpowiedzi:

197

@bogatron ma rację, możesz użyć where, warto zauważyć, że możesz to zrobić natywnie w pandach:

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

Uwaga: spowoduje to zmianę typu dtype wszystkich kolumn na object.

Przykład:

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

Uwaga: czego nie można zrobić przekształcenia DataFrames, dtypeaby zezwolić na wszystkie typy danych, używając astype, a następnie fillnametody DataFrame :

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

Niestety ani to, ani przy użyciu replace, współpracuje z Nonezobaczyć tę kwestię (zamknięte) .


Na marginesie, warto zauważyć, że w większości przypadków użycia nie trzeba zastępować NaN na None, zobacz to pytanie o różnicę między NaN i None w pandach .

Jednak w tym konkretnym przypadku wydaje się, że tak (przynajmniej w momencie tej odpowiedzi).

Andy Hayden
źródło
zobacz dokumentację pandas.pydata.org/pandas-docs/stable/ ...
Jeff
1
FWIW .. to również zmieni typ kolumn na obiekt, prawdopodobnie nie obchodzi cię to
Jeff
@Jeff Dzięki za link, o dziwo nie mogłem go znaleźć wcześniej! Pomyślałem, że trzeba zmienić typ, aby zezwolić na Brak, zdecydowanie warto o tym wspomnieć!
Andy Hayden,
przydatne w użyciu przed wstawieniem za pomocą Django, aby uniknąć np.nankonwersji na ciąg"nan"
shadi
Przydatne zastrzeżenie. Sens pętli tylko tych kolumn, które są już dtypeod objecti robią to dla tych, którzy zajmują się inne rodzaje i różnie w zależności od potrzeb. Idealnie fillna(None)byłoby wspaniale.
Vishal,
84
df = df.replace({np.nan: None})

Podziękowania dla tego gościa w tej kwestii na Githubie .

Eliad L.
źródło
5
to najlepsza odpowiedź, ponieważ możesz użyć df.replace({np.nan: None})jako obiektu tymczasowego
Matt
17

Można wymienić nanze Nonew numpy tablicy:

>>> 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
źródło
2
Jedynym potencjalnym problemem jest zmiana dtype, x.dtypejest dtype('float64'), podczas gdy y.dtypejest dtype('object').
Jaime,
10

Po potknięciu się, to zadziałało dla mnie:

df = df.astype(object).where(pd.notnull(df),None)
Rodney Cox
źródło
4

To tylko dodatek do odpowiedzi @Andy Hayden:

Ponieważ DataFrame.maskjest przeciwieństwem DataFrame.where, mają dokładnie ten sam podpis, ale o przeciwnym znaczeniu:

  • DataFrame.wherejest przydatny do zastępowania wartości, w których warunek jest fałszywy .
  • DataFrame.masksłuży do zastępowania wartości, w których warunek to True .

Więc w tym pytaniu używanie df.mask(df.isna(), other=None, inplace=True)może być bardziej intuicyjne.

YaOzI
źródło
2

Kolejny dodatek: zachowaj ostrożność podczas zastępowania wielokrotności i konwertowania typu kolumny z powrotem z obiektu na zmiennoprzecinkowy . Jeśli chcesz mieć pewność, że Nonenie wrócisz do tego np.NaN, zastosuj sugestię @ andy-hayden dotyczącą używania pd.where. Ilustracja pokazująca, jak wymiana nadal może pójść „źle”:

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
źródło
Dzięki za dodanie tego. Przeglądając ponownie dokumentację, nadal nie mogę zrozumieć tego zachowania. W każdym razie można to obejść, łącząc w .replace({np.nan: None})
łańcuch
1
Tak, możesz zakończyć, dodając kolejny replace({np.nan: None}). Mój komentarz został dodany, aby zwrócić uwagę na potencjalną pułapkę podczas wymiany np.nan. Powyższe z pewnością trochę mnie zaskoczyło!
gaatjeniksaan
1

Dość stary, ale natknąłem się na ten sam problem. Spróbuj to zrobić:

df['col_replaced'] = df['col_with_npnans'].apply(lambda x: None if np.isnan(x) else x)
Robin Nemeth
źródło
nie działa jeśli typ danych kolumny jest numeryczne, ponieważ żaden prostu staje przekształcany z powrotem w nan pandy (0.23)
Shadi