Ufuncs: Giữ nguyên chỉ số¶
Vì Pandas được thiết kế để làm việc với NumPy, bất kỳ ufunc NumPy nào cũng sẽ hoạt động trên các đối tượng Pandas Series
và DataFrame
.Hãy bắt đầu bằng cách xác định một Series
đơn giản và một DataFrame
để thể hiện điều này:
import pandas as pdimport numpy as np
rng = np.random.RandomState(42)ser = pd.Series(rng.randint(0, 10, 4))ser
0 61 32 73 4dtype: int64
df = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=['A', 'B', 'C', 'D'])df
Nếu chúng ta áp dụng một NumPy ufunc trên bất kỳ đối tượng nào trong số này, kết quả sẽ là một đối tượng Pandas khác với các chỉ số được bảo tồn:
np.exp(ser)
0 403.4287931 20.0855372 1096.6331583 54.598150dtype: float64
Hoặc, cho một phép tính phức tạp hơn:
np.sin(df * np.pi / 4)
Bất kỳ ufunc nào được thảo luận trong Tính toán trên mảng NumPy: Các hàm universal functions có thể được sử dụng theo cách tương tự.
UFuncs: Căn chỉnh Chỉ số¶
Đối với các phép toán nhị phân trên hai đối tượng Series
hoặc DataFrame
, Pandas sẽ căn chỉnh các chỉ số trong quá trình thực hiện phép toán.Điều này rất tiện lợi khi làm việc với dữ liệu không đầy đủ, như chúng ta sẽ thấy trong một số ví dụ sau đây.
Sắp xếp chỉ mục trong Series¶
Như một ví dụ, giả sử chúng ta đang kết hợp hai nguồn dữ liệu khác nhau và chỉ tìm ba tiểu bang Mỹ có diện tích cao nhất và ba tiểu bang Mỹ có dân số cao nhất:
area = pd.Series({'Alaska': 1723337, 'Texas': 695662, 'California': 423967}, name='area')population = pd.Series({'California': 38332521, 'Texas': 26448193, 'New York': 19651127}, name='population')
Hãy xem điều gì sẽ xảy ra khi chúng ta chia chúng để tính mật độ dân số:
population / area
Alaska NaNCalifornia 90.413926New York NaNTexas 38.018740dtype: float64
Mảng kết quả chứa sự hợp của các chỉ số từ hai mảng đầu vào, có thể được xác định bằng cách sử dụng phép toán tập hợp tiêu chuẩn của Python trên các chỉ số này:
area.index | population.index
Index(['Alaska', 'California', 'New York', 'Texas'], dtype='object')
Mọi mục mà một trong hai không có một mục nhập được đánh dấu bằng NaN
, hoặc “Not a Number,” được Pandas dùng để đánh dấu dữ liệu bị thiếu (xem thêm về dữ liệu thiếu trong Xử lý Dữ liệu Thiếu).Phù hợp với chỉ mục này được thực hiện như vậy cho bất kỳ biểu thức toán học tích hợp của Python nào; những giá trị bị thiếu sẽ được điền bằng NaN theo mặc định:
A = pd.Series([2, 4, 6], index=[0, 1, 2])B = pd.Series([1, 3, 5], index=[1, 2, 3])A + B
0 NaN1 5.02 9.03 NaNdtype: float64
Nếu việc sử dụng giá trị NaN không phải là hành vi mong muốn, giá trị điền có thể được thay đổi bằng cách sử dụng các phương thức đối tượng thích hợp thay vì toán tử.Ví dụ, việc gọi A.add(B)
tương đương với việc gọi A + B
, nhưng cho phép chỉ định rõ ràng tùy chọn của giá trị điền cho bất kỳ phần tử nào trong A
hoặc B
có thể không tồn tại:
A.add(B, fill_value=0)
0 2.01 5.02 9.03 5.0dtype: float64
Cân bằng chỉ số trong DataFrame¶
Một kiểu căn chỉnh tương tự xảy ra đối với cả cột và chỉ số khi thực hiện các hoạt động trên DataFrame
:
A = pd.DataFrame(rng.randint(0, 20, (2, 2)), columns=list('AB'))A
B = pd.DataFrame(rng.randint(0, 10, (3, 3)), columns=list('BAC'))B
A + B
Chú ý rằng các chỉ số được căn chỉnh đúng không phụ thuộc vào thứ tự của chúng trong hai đối tượng, và các chỉ số trong kết quả được sắp xếp.Như đã thấy trong ví dụ với Series
, chúng ta có thể sử dụng phương thức toán học của đối tượng liên quan và truyền bất kỳ fill_value
mong muốn để sử dụng thay vì các mục thiếu.Ở đây chúng ta sẽ điền bằng giá trị trung bình của tất cả các giá trị trong A
(được tính bằng cách xếp các hàng của A
):
fill = A.stack().mean()A.add(B, fill_value=fill)
Bảng dưới đây liệt kê các toán tử Python và các phương thức tương đương của đối tượng Pandas:
Ufuncs: Các hoạt động giữa DataFrame và Series¶
Khi thực hiện các phép tính giữa một DataFrame
và một Series
, việc cân bằng chỉ mục và cột được duy trì tương tự.Các phép tính giữa một DataFrame
và một Series
tương tự như các phép tính giữa một mảng NumPy hai chiều và một mảng một chiều.Xem xét một phép tính thông thường, trong đó chúng ta tìm hiệu của một mảng hai chiều và một trong các hàng của nó:
A = rng.randint(10, size=(3, 4))A
array([[3, 8, 2, 4], [2, 6, 4, 8], [6, 1, 3, 8]])
A - A[0]
array([[ 0, 0, 0, 0], [-1, -2, 2, 4], [ 3, -7, 1, 4]])
Theo quy tắc phát sóng của NumPy (xem Tính toán trên mảng: Phát sóng), phép trừ giữa một mảng hai chiều và một trong những hàng của nó được áp dụng theo hàng.
Trong Pandas, theo quy ước tương tự, mặc định hoạt động theo hàng:
df = pd.DataFrame(A, columns=list('QRST'))df - df.iloc[0]
Nếu bạn muốn thực hiện theo cột thay vì hàng, bạn có thể sử dụng các phương thức của đối tượng đã đề cập trước đó, trong khi chỉ định từ khóa axis
:
df.subtract(df['R'], axis=0)
Lưu ý rằng các thao tác DataFrame
/Series
này, giống như các thao tác đã được thảo luận ở trên, sẽ tự động căn chỉnh các chỉ số giữa hai phần tử:
halfrow = df.iloc[0, ::2]halfrow
Q 3S 2Name: 0, dtype: int64
df - halfrow
Việc bảo tồn và cân nhắc các chỉ mục và cột này có nghĩa là các thao tác trên dữ liệu trong Pandas sẽ luôn duy trì ngữ cảnh dữ liệu, từ đó ngăn chặn các lỗi ngớ ngẩn có thể xảy ra khi làm việc với dữ liệu không đồng nhất và/hoặc không cân nhắc trong các mảng NumPy gốc.