Thay thế Gấu trúc hoặc Numpy Nan bằng Không có để sử dụng với MysqlDB


128

Tôi đang cố gắng ghi khung dữ liệu Pandas (hoặc có thể sử dụng một mảng numpy) vào cơ sở dữ liệu mysql bằng MysqlDB. MysqlDB có vẻ không hiểu 'nan' và cơ sở dữ liệu của tôi phát ra lỗi nói nan không có trong danh sách trường. Tôi cần tìm cách chuyển 'nan' thành NoneType.

Có ý kiến ​​gì không?


2
Có không có thiết lập bạn có thể thay đổi trong Pandas để làm cho nó trở lại Nonecho NULLthay vì nan?
Nathan Hinchey

Câu trả lời:


195

@bogatron nói đúng, bạn có thể sử dụng where, cần lưu ý rằng bạn có thể thực hiện điều này một cách tự nhiên ở gấu trúc:

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

Lưu ý: điều này thay đổi loại của tất cả các cột thành object.

Thí dụ:

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

Lưu ý: những gì bạn không thể làm là viết lại DataFrame dtypeđể cho phép tất cả các loại kiểu dữ liệu, sử dụng astypevà sau đó là fillnaphương thức DataFrame :

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

Thật không may, không phải điều này, cũng không sử dụng replace, hoạt động với Nonexem vấn đề này (đã đóng) .


Ngoài ra, cần lưu ý rằng đối với hầu hết các trường hợp sử dụng, bạn không cần thay thế NaN bằng Không, hãy xem câu hỏi này về sự khác biệt giữa NaN và Không có ở gấu trúc .

Tuy nhiên, trong trường hợp cụ thể này có vẻ như bạn làm (ít nhất là tại thời điểm câu trả lời này).



1
FWIW..this cũng sẽ thay đổi dtype trong các cột để đối tượng, có thể bạn không quan tâm mặc dù
Jeff

@Jeff Cảm ơn vì liên kết, kỳ lạ là tôi không thể tìm thấy nó sớm hơn! Tôi nghĩ rằng nó đã phải thay đổi loại dtype để cho phép Không có, chắc chắn đáng nói!
Andy Hayden

hữu ích để sử dụng trước khi chèn với Django để tránh np.nanbị chuyển đổi thành chuỗi"nan"
shadi

Cảnh báo hữu ích. Làm cho tinh thần để lặp qua chỉ những cột mà đã dtypevề objectvà làm điều đó cho những người và xử lý các loại khác khác khi cần thiết. Lý tưởng nhất, fillna(None)sẽ là tuyệt vời.
Vishal

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

Tín dụng được chuyển cho anh chàng này ở đây trên Github vấn đề này .


4
đây là câu trả lời tốt nhất vì bạn có thể sử dụng df.replace({np.nan: None})như một đối tượng tạm thời
Matt

17

Bạn có thể thay thế nanbằng Nonetrong mảng numpy của mình:

>>> 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
Mối quan tâm duy nhất tiềm năng là sự thay đổi của dtype, x.dtypedtype('float64'), trong khi y.dtypedtype('object').
Jaime

10

Sau khi vấp ngã, điều này đã hiệu quả với tôi:

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

4

Chỉ là một bổ sung cho câu trả lời của @Andy Hayden:

DataFrame.masklà cặp song sinh đối lập củaDataFrame.where nên chúng có cùng một chữ ký nhưng có ý nghĩa trái ngược nhau:

  • DataFrame.wherehữu ích cho việc Thay thế các giá trị trong đó điều kiện là Sai .
  • DataFrame.maskđược sử dụng để Thay thế các giá trị trong đó điều kiện là Đúng .

Vì vậy, trong câu hỏi này, việc sử dụng df.mask(df.isna(), other=None, inplace=True)có thể trực quan hơn.


2

Một bổ sung khác: hãy cẩn thận khi thay thế bội số và chuyển đổi kiểu của cột trở lại từ đối tượng thành float . Nếu bạn muốn chắc chắn rằng None's của bạn sẽ không quay lại np.NaN', hãy áp dụng gợi ý của @ andy-hayden với việc sử dụng pd.where. Hình minh họa về cách thay thế vẫn có thể xảy ra 'sai':

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

Cảm ơn vì đã thêm điều này. Xem lại tài liệu, tôi vẫn không thể hiểu hành vi này. Dù sao, điều này có thể được giải quyết bằng cách xâu chuỗi thêm một chuỗi khác.replace({np.nan: None})
EliadL

1
Có, bạn có thể hoàn thành bằng cách thêm một cái khác replace({np.nan: None}). Nhận xét của tôi đã được thêm vào để chỉ ra cạm bẫy tiềm ẩn khi thay thế np.nan's. Những điều trên chắc chắn đã làm tôi bối rối một chút!
gaatjeniksaan

1

Khá cũ, nhưng tôi tình cờ gặp vấn đề rất giống nhau. Hãy thử làm điều này:

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

không hoạt động nếu kiểu dữ liệu cột là số vì Không chỉ được trở lại chuyển đổi thành nan (gấu trúc 0,23)
Shadi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.