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?


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



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 .


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'>

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)

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.


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

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)

nie działa jeśli typ danych kolumny jest numeryczne, ponieważ żaden prostu staje przekształcany z powrotem w nan pandy (0.23)
— Shadi
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.