NumPy hoặc Pandas: Giữ kiểu mảng là số nguyên trong khi có giá trị NaN


160

Có cách nào ưu tiên để giữ kiểu dữ liệu của một numpymảng cố định là int( int64hoặc bất cứ thứ gì), trong khi vẫn có một phần tử được liệt kê là numpy.NaN?

Cụ thể, tôi đang chuyển đổi cấu trúc dữ liệu nội bộ sang Khung dữ liệu Pandas. Trong cấu trúc của chúng tôi, chúng tôi có các cột kiểu số nguyên vẫn có NaN (nhưng dtype của cột là int). Nó dường như làm lại mọi thứ dưới dạng nổi nếu chúng ta biến đây thành DataFrame, nhưng chúng tôi thực sự muốn như vậy int.

Suy nghĩ?

Những điều đã cố gắng:

Tôi đã thử sử dụng from_records()hàm theo pandas.DataFrame, coerce_float=Falsevà điều này không giúp được gì. Tôi cũng đã thử sử dụng mảng mặt nạ NumPy, với NaN fill_value, cũng không hoạt động. Tất cả những điều này làm cho kiểu dữ liệu cột trở thành một float.


Bạn có thể sử dụng một mảng mặt nạ numpy?
mgilson

Tôi sẽ thử. Tôi cũng đã thử from_recordschức năng theo pandas.DataFrame, coerce_float=Falsenhưng không may mắn ... nó vẫn làm cho dữ liệu mới có kiểu float64.
ely

1
Vâng, không có may mắn. Ngay cả với mảng mặt nạ, nó vẫn chuyển thành float. Trông giống như Pandas như thế này: "Có NaN ở đâu không? ... Sau đó, mọi thứ đều trôi nổi." Hy vọng có một cách xung quanh này.
ely

1
Hỗ trợ số nguyên Nullable tùy chọn hiện được thêm chính thức vào gấu trúc 0.24.0 - cuối cùng :) - vui lòng tìm câu trả lời dưới đây. gấu trúc 0,24.x ghi chú phát hành
mork

Câu trả lời:


70

Khả năng này đã được thêm vào gấu trúc (bắt đầu với phiên bản 0.24): https://pandas.pydata.org/pandas-docs/version/0.24/whatsnew/v0.24.0.html#optional-integer-na- support

Tại thời điểm này, nó yêu cầu sử dụng phần mở rộng dtype Int64 (viết hoa), thay vì dtype int64 mặc định (chữ thường).


1
Bây giờ bạn phải chỉ định một dtype đặc biệt muốn 'Int64'làm cho nó hoạt động. Nó sẽ còn tốt hơn khi nó được bật theo mặc định.
Jean Paul

Điều đó thật tuyệt! Có một vấn đề nhỏ mặc dù PyCharm không hiển thị khung dữ liệu trong cửa sổ gỡ lỗi nếu được sử dụng theo cách này. Bạn có thể thấy câu trả lời của tôi cho một câu hỏi khác về cách bắt buộc hiển thị nó: stackoverflow.com/questions/38956660/ (vấn đề ban đầu có khác, nhưng giải pháp hiển thị khung dữ liệu hoạt động)
Alaa M.

Tôi có phải sử dụng 'Int64'hoặc có một cái gì đó như thế 'Int8'nào? Nó sử dụng một lượng bộ nhớ điên rồ so với np.float.
Superdooperhero

'Int8'dường như làm việc, nhưng np.floatdường như vẫn tải cách nhanh hơn. Vấn đề dường như là nó không giải phóng bộ nhớ giữa. Giả sử người thu gom rác cuối cùng sẽ chạy.
Superdooperhero

103

NaNkhông thể được lưu trữ trong một mảng số nguyên. Đây là một hạn chế được biết đến của gấu trúc tại thời điểm này; Tôi đã chờ đợi tiến trình được thực hiện với các giá trị NA trong NumPy (tương tự NA trong R), nhưng sẽ mất ít nhất 6 tháng đến một năm trước khi NumPy có được các tính năng này, có vẻ như:

http://pandas.pydata.org/pandas-docs/urdy/gotchas.html#support-for-integer-na

(Tính năng này đã được bổ sung bắt đầu với phiên bản 0.24 của gấu trúc, nhưng lưu ý nó đòi hỏi việc sử dụng các phần mở rộng dtype Int64 (viết hoa), chứ không phải là dtype mặc định Int64 (viết thường): https://pandas.pydata.org/pandas- docs / phiên bản / 0.24 / whatsnew / v0.24.0.html # tùy chọn-số nguyên-na-hỗ trợ )


7
Xin chào Wes, có bản cập nhật nào về điều này không? Chúng tôi gặp phải các vấn đề liên quan đến các cột được chuyển đổi thành số nguyên hoặc số float, dựa trên sự tồn tại của giá trị NA trong danh sách ban đầu. (Tạo các vấn đề sau này khi cố gắng hợp nhất các tệp dữ liệu này)
Carst 23/07/13


8

Nếu hiệu suất không phải là vấn đề chính, bạn có thể lưu trữ chuỗi thay thế.

df.col = df.col.dropna().apply(lambda x: str(int(x)) )

Sau đó, bạn có thể trộn sau đó với NaNnhiều như bạn muốn. Nếu bạn thực sự muốn có số nguyên, tùy thuộc vào ứng dụng của bạn, bạn có thể sử dụng -1, hoặc 0, hoặc 1234567890, hoặc một số giá trị khác dành riêng để biểu diễn NaN.

Bạn cũng có thể tạm thời sao chép các cột: một như bạn có, với số float; một thử nghiệm khác, với ints hoặc chuỗi. Sau đó chèn assertsvào mọi nơi hợp lý kiểm tra xem hai cái có đồng bộ không. Sau khi kiểm tra đủ, bạn có thể thả phao.


5

Đây không phải là giải pháp cho tất cả các trường hợp, nhưng của tôi (tọa độ bộ gen) tôi đã sử dụng 0 làm NaN

a3['MapInfo'] = a3['MapInfo'].fillna(0).astype(int)

Điều này ít nhất cho phép sử dụng loại cột 'bản địa' thích hợp, các hoạt động như trừ, so sánh, v.v.


5

Gấu trúc v0.24 +

Chức năng hỗ trợ NaNtrong chuỗi số nguyên sẽ có sẵn trong v0.24 trở lên. Có thông tin về điều này trong phần "Có gì mới" v0.24 và biết thêm chi tiết trong Kiểu dữ liệu số nguyên không thể xóa được .

Gấu trúc v0,23 trở về trước

Nói chung, nó là tốt nhất để làm việc với floathàng loạt nếu có thể, ngay cả khi series là sự liệng lên từ intđể floatdo bao gồm các NaNgiá trị. Điều này cho phép các phép tính dựa trên NumPy được vector hóa trong đó, nếu không, các vòng lặp ở cấp độ Python sẽ được xử lý.

Các tài liệu đề nghị : "Một khả năng là sử dụng dtype=objectmảng thay thế." Ví dụ:

s = pd.Series([1, 2, 3, np.nan])

print(s.astype(object))

0      1
1      2
2      3
3    NaN
dtype: object

Vì lý do mỹ phẩm, ví dụ đầu ra cho một tập tin, điều này thể thích hợp hơn.

Pandas v0.23 trở về trước: nền

NaNđược coi là afloat . Các tài liệu hiện tại (kể từ v0,23) chỉ định lý do tại sao chuỗi số nguyên được đưa lên float:

Trong trường hợp không có hỗ trợ NA hiệu suất cao được tích hợp vào NumPy từ đầu, thương vong chính là khả năng thể hiện NA trong các mảng số nguyên.

Sự đánh đổi này được thực hiện chủ yếu vì lý do bộ nhớ và hiệu năng, và do đó, Series kết quả tiếp tục là số lượng.

Các tài liệu cũng cung cấp các quy tắc cho việc phát sóng do NaNbao gồm:

Typeclass   Promotion dtype for storing NAs
floating    no change
object      no change
integer     cast to float64
boolean     cast to object


1

Chỉ muốn thêm rằng trong trường hợp bạn đang cố gắng chuyển đổi một vectơ float (1.143) thành số nguyên (1) có NA chuyển đổi sang dtype 'Int64' mới sẽ gây ra lỗi cho bạn. Để giải quyết vấn đề này, bạn phải làm tròn số và sau đó thực hiện ".astype ('Int64')"

s1 = pd.Series([1.434, 2.343, np.nan])
#without round() the next line returns an error 
s1.astype('Int64')
#cannot safely cast non-equivalent float64 to int64
##with round() it works
s1.round().astype('Int64')
0      1
1      2
2    NaN
dtype: Int64

Trường hợp sử dụng của tôi là tôi có một chuỗi float mà tôi muốn làm tròn thành int, nhưng khi bạn thực hiện .round () a '* .0' ở cuối số vẫn còn, vì vậy bạn có thể bỏ 0 từ cuối chuyển đổi sang int.


0

Nếu có khoảng trống trong dữ liệu văn bản, các cột thường là số nguyên sẽ được chuyển thành float dưới dạng float64 dtype vì int64 dtype không thể xử lý null. Điều này có thể gây ra lược đồ không nhất quán nếu bạn đang tải nhiều tệp có một số khoảng trống (sẽ kết thúc là float64 và các tệp khác mà không có kết thúc là int64

Mã này sẽ cố gắng chuyển đổi bất kỳ cột loại số nào thành Int64 (trái ngược với int64) vì Int64 có thể xử lý null

import pandas as pd
import numpy as np

#show datatypes before transformation
mydf.dtypes

for c in mydf.select_dtypes(np.number).columns:
    try:
        mydf[c] = mydf[c].astype('Int64')
        print('casted {} as Int64'.format(c))
    except:
        print('could not cast {} to Int64'.format(c))

#show datatypes after transformation
mydf.dtypes
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.