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?

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

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

EliadL
sumber
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'>
bogatron.dll
sumber
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)
rodney cox
sumber
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.

YaOzI
sumber
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
gaatjeniksaan
sumber
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)
Robin Nemeth
sumber
tidak berfungsi jika tipe data kolom adalah numerik karena Tidak ada yang diubah kembali menjadi nan (panda 0,23)
shadi