Tự Học Data Science · 17/11/2023 0

03.03 Operating on Data in Pandas

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 SeriesDataFrame.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.