Mengganti Pandas atau Numpy Nan dengan None untuk digunakan dengan MysqlDB


128

Saya mencoba untuk menulis dataframe Pandas (atau dapat menggunakan array numpy) ke database mysql menggunakan MysqlDB. MysqlDB sepertinya tidak mengerti 'nan' dan database saya mengeluarkan kesalahan yang mengatakan nan tidak ada dalam daftar lapangan. Saya perlu menemukan cara untuk mengubah 'nan' menjadi NoneType.

Ada ide?


2
Apakah tidak ada pengaturan Anda dapat mengubah Panda untuk membuatnya kembali Noneuntuk NULLbukan nan?
Nathan Hinchey

Jawaban:


195

@bogatron benar, Anda dapat menggunakan where, perlu dicatat bahwa Anda dapat melakukan ini secara native di panda:

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

Catatan: ini mengubah tipe d semua kolom menjadi object.

Contoh:

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

Catatan: apa yang tidak dapat Anda lakukan menyusun ulang DataFrames dtypeuntuk mengizinkan semua tipe tipe data, menggunakan astype, dan kemudian fillnametode DataFrame :

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

Sayangnya ini, maupun penggunaan replace, tidak berfungsi dengan Nonemelihat masalah (tertutup) ini .


Selain itu, perlu dicatat bahwa untuk sebagian besar kasus penggunaan Anda tidak perlu mengganti NaN dengan None, lihat pertanyaan tentang ini perbedaan antara NaN dan None pada panda ini .

Namun, dalam kasus khusus ini tampaknya Anda melakukannya (setidaknya pada saat jawaban ini).



1
FWIW..ini juga akan mengubah dtype kolom menjadi objek, Anda mungkin tidak peduli
Jeff

@Jeff Terima kasih untuk tautannya, anehnya saya tidak dapat menemukannya sebelumnya! Saya pikir itu harus mengubah dtype untuk memungkinkan Tidak Ada, pasti layak disebutkan!
Andy Hayden

berguna untuk digunakan sebelum menyisipkan dengan Django untuk menghindari np.nankonversi ke string"nan"
shadi

Peringatan yang berguna. Masuk akal untuk loop melalui hanya mereka kolom yang sudah dtypedari objectdan melakukannya untuk mereka dan menangani jenis lain berbeda sesuai kebutuhan. Idealnya, fillna(None)akan menjadi hebat.
Vishal

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

Penghargaan diberikan kepada orang ini di sini dalam masalah Github ini .


4
ini adalah jawaban terbaik yang dapat Anda gunakan df.replace({np.nan: None})sebagai objek temporer
Matt

17

Anda dapat mengganti nandengan Nonedi 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
Satu-satunya perhatian potensial adalah perubahan dtype, x.dtypeis dtype('float64'), while y.dtypeis dtype('object').
Jaime

10

Setelah tersandung, ini berhasil untuk saya:

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

4

Sekadar tambahan dari jawaban @Andy Hayden:

Karena DataFrame.maskmerupakan kembaran kebalikan dari DataFrame.where, mereka memiliki tanda tangan yang persis sama tetapi dengan arti yang berlawanan:

  • DataFrame.whereberguna untuk Mengganti nilai yang kondisinya False .
  • DataFrame.maskdigunakan untuk Mengganti nilai di mana kondisinya Benar .

Jadi dalam pertanyaan ini, penggunaan df.mask(df.isna(), other=None, inplace=True)mungkin lebih intuitif.


2

Tambahan lainnya: hati-hati saat mengganti kelipatan dan mengubah tipe kolom kembali dari objek menjadi float . Jika Anda ingin memastikan bahwa Anda Nonetidak akan membalik np.NaNsaran terapkan @ andy-hayden dengan menggunakan pd.where. Ilustrasi bagaimana penggantian masih bisa 'salah':

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

Terima kasih telah menambahkan ini. Membaca kembali dokumentasi, saya masih tidak dapat memahami perilaku ini. Bagaimanapun, ini dapat diselesaikan dengan .replace({np.nan: None})
merangkai yang

1
Ya, Anda dapat menyelesaikannya dengan menambahkan yang lain replace({np.nan: None}). Komentar saya ditambahkan untuk menunjukkan potensi jebakan saat mengganti np.nan. Hal di atas pasti membuat saya tersandung sedikit!
gaatjeniksaan

1

Cukup tua, namun saya menemukan masalah yang sama. Coba lakukan ini:

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

tidak berfungsi jika tipe data kolom adalah numerik karena Tidak ada yang diubah kembali menjadi nan (panda 0,23)
shadi
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.