Không dùng nữa values
và as_matrix()
!
pandas v0.24.0 đã giới thiệu hai phương thức mới để lấy mảng NumPy từ các đối tượng gấu trúc:
to_numpy()
, được định nghĩa trên Index
, Series,
và DataFrame
các đối tượng, và
array
, được định nghĩa trên Index
và Series
chỉ các đối tượng.
Nếu bạn truy cập tài liệu v0.24 cho .values
, bạn sẽ thấy một cảnh báo lớn màu đỏ có nội dung:
Cảnh báo: Chúng tôi khuyên bạn nên sử dụng DataFrame.to_numpy()
thay thế.
Xem phần này của ghi chú phát hành v0.24.0 và câu trả lời này để biết thêm thông tin.
Hướng tới tính nhất quán tốt hơn: to_numpy()
Với tinh thần thống nhất tốt hơn trong suốt API, một phương pháp mới to_numpy
đã được giới thiệu để trích xuất mảng NumPy cơ bản từ DataFrames.
# Setup.
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}, index=['a', 'b', 'c'])
df.to_numpy()
array([[1, 4],
[2, 5],
[3, 6]])
Như đã đề cập ở trên, phương thức này cũng được định nghĩa Index
và Series
các đối tượng (xem tại đây ).
df.index.to_numpy()
# array(['a', 'b', 'c'], dtype=object)
df['A'].to_numpy()
# array([1, 2, 3])
Theo mặc định, chế độ xem được trả về, vì vậy mọi sửa đổi được thực hiện sẽ ảnh hưởng đến bản gốc.
v = df.to_numpy()
v[0, 0] = -1
df
A B
a -1 4
b 2 5
c 3 6
Nếu bạn cần một bản sao thay thế, sử dụng to_numpy(copy=True
).
gấu trúc> = 1.0 cập nhật cho ExtensionTypes
Nếu bạn đang sử dụng gấu trúc 1.x, nhiều khả năng bạn sẽ phải đối phó với các loại tiện ích mở rộng hơn rất nhiều. Bạn sẽ phải cẩn thận hơn một chút rằng các loại tiện ích mở rộng này được chuyển đổi chính xác.
a = pd.array([1, 2, None], dtype="Int64")
a
<IntegerArray>
[1, 2, <NA>]
Length: 3, dtype: Int64
# Wrong
a.to_numpy()
# array([1, 2, <NA>], dtype=object) # yuck, objects
# Right
a.to_numpy(dtype='float', na_value=np.nan)
# array([ 1., 2., nan])
Điều này được gọi ra trong các tài liệu .
Nếu bạn cần dtypes
...
Như thể hiện trong một câu trả lời khác, DataFrame.to_records
là một cách tốt để làm điều này.
df.to_records()
# rec.array([('a', -1, 4), ('b', 2, 5), ('c', 3, 6)],
# dtype=[('index', 'O'), ('A', '<i8'), ('B', '<i8')])
Điều này không thể được thực hiện với to_numpy
, không may. Tuy nhiên, để thay thế, bạn có thể sử dụng np.rec.fromrecords
:
v = df.reset_index()
np.rec.fromrecords(v, names=v.columns.tolist())
# rec.array([('a', -1, 4), ('b', 2, 5), ('c', 3, 6)],
# dtype=[('index', '<U1'), ('A', '<i8'), ('B', '<i8')])
Hiệu suất khôn ngoan, nó gần giống nhau (thực ra, sử dụng rec.fromrecords
nhanh hơn một chút).
df2 = pd.concat([df] * 10000)
%timeit df2.to_records()
%%timeit
v = df2.reset_index()
np.rec.fromrecords(v, names=v.columns.tolist())
11.1 ms ± 557 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
9.67 ms ± 126 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Cơ sở lý luận để thêm một phương pháp mới
to_numpy()
(ngoài array
) đã được thêm vào do kết quả của các cuộc thảo luận theo hai vấn đề GitHub GH19954 và GH23623 .
Cụ thể, các tài liệu đề cập đến lý do:
[...] với .values
nó không rõ liệu giá trị được trả về sẽ là mảng thực tế, một số biến đổi của nó hoặc một trong các mảng tùy chỉnh gấu trúc (như Categorical
). Ví dụ, với PeriodIndex
, .values
tạo ra một ndarray
đối tượng thời gian mới mỗi lần. [...]
to_numpy
nhằm cải thiện tính nhất quán của API, đây là một bước quan trọng theo đúng hướng. .values
sẽ không bị phản đối trong phiên bản hiện tại, nhưng tôi hy vọng điều này có thể xảy ra vào một thời điểm nào đó trong tương lai, vì vậy tôi sẽ khuyến khích người dùng chuyển sang API mới hơn, ngay khi bạn có thể.
Phê bình các giải pháp khác
DataFrame.values
có hành vi không nhất quán, như đã lưu ý.
DataFrame.get_values()
chỉ đơn giản là một trình bao bọc xung quanh DataFrame.values
, vì vậy mọi thứ nói ở trên đều áp dụng.
DataFrame.as_matrix()
bây giờ không được dùng nữa, KHÔNG sử dụng!