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

03.02 Data Indexing and Selection

Lựa chọn dữ liệu trong dãy

Như chúng ta đã thấy ở phần trước, một đối tượng Series hoạt động theo nhiều cách giống như một mảng 1 chiều NumPy và cũng giống như một từ điển Python tiêu chuẩn.Nếu chúng ta giữ hai điểm tương đồng này trong đầu, nó sẽ giúp chúng ta hiểu các mẫu của việc chỉ mục và lựa chọn dữ liệu trong các mảng này.

Series như một từ điển

Tương tự như một từ điển, đối tượng Series cung cấp một ánh xạ từ một bộ các khóa đến một bộ các giá trị:

import pandas as pddata = pd.Series([0.25, 0.5, 0.75, 1.0],                 index=['a', 'b', 'c', 'd'])data
a    0.25b    0.50c    0.75d    1.00dtype: float64
data['b']
0.5

Chúng ta cũng có thể sử dụng các biểu thức và phương thức giống như từ điển trong Python để kiểm tra các khóa/chỉ mục và giá trị:

'a' in data
True
data.keys()
Index(['a', 'b', 'c', 'd'], dtype='object')
list(data.items())
[('a', 0.25), ('b', 0.5), ('c', 0.75), ('d', 1.0)]

Đối tượng Series thậm chí có thể được sửa đổi bằng cú pháp giống như từ điển.Tương tự như việc bạn có thể mở rộng một từ điển bằng cách gán cho một khóa mới, bạn cũng có thể mở rộng một Series bằng cách gán cho một giá trị chỉ mục mới:

data['e'] = 1.25data
a    0.25b    0.50c    0.75d    1.00e    1.25dtype: float64

Sự thay đổi dễ dàng của các đối tượng này là một tính năng tiện lợi: dưới hậu trường, Pandas đang đưa ra quyết định về bố cục bộ nhớ và sao chép dữ liệu có thể cần xảy ra; người dùng thông thường không cần lo lắng về những vấn đề này.

Chuỗi dưới dạng một mảng một chiều

Một Series xây dựng trên giao diện giống như từ điển này và cung cấp lựa chọn mục bằng cách sử dụng các cơ chế cơ bản giống như mảng NumPy – tức là lát, lọc, và lập chỉ mục phong cách đặc biệt.Ví dụ về những thứ này như sau:

# slicing by explicit indexdata['a':'c']
a    0.25b    0.50c    0.75dtype: float64
# slicing by implicit integer indexdata[0:2]
a    0.25b    0.50dtype: float64
# maskingdata[(data > 0.3) & (data < 0.8)]
b    0.50c    0.75dtype: float64
# fancy indexingdata[['a', 'e']]
a    0.25e    1.25dtype: float64

Trong số đó, phần chia có thể là nguồn gây nhầm lẫn nhất.Chú ý rằng khi chia bằng chỉ số tường minh (ví dụ: data['a':'c']), chỉ số cuối cùng được bao gồm trong phần chia, trong khi khi chia bằng chỉ số ngầm định (ví dụ: data[0:2]), chỉ số cuối cùng được loại trừ khỏi phần chia.

Indexers: loc, iloc, và ix

Các quy ước chia trích và chia chỉ số này có thể gây nhầm lẫn.Ví dụ, nếu Serires của bạn có một chỉ mục số nguyên rõ ràng, một hoạt động chia chỉ số như data[1] sẽ sử dụng các chỉ mục rõ ràng, trong khi một hoạt động chia trích như data[1:3] sẽ sử dụng chỉ mục kiểu Python ngầm định.

data = pd.Series(['a', 'b', 'c'], index=[1, 3, 5])data
1    a3    b5    cdtype: object
# explicit index when indexingdata[1]
'a'
# implicit index when slicingdata[1:3]
3    b5    cdtype: object

Vì sự mơ hồ này trong trường hợp các chỉ số nguyên, Pandas cung cấp một số thuộc tính \em>indexer đặc biệt để hiển thị một số hệ thống chỉ mục cụ thể.Đây không phải là các phương thức hoạt động, mà là những thuộc tính mà tiết lộ một giao diện cắt bỏ cụ thể đến dữ liệu trong Series.

Đầu tiên, thuộc tính loc cho phép chỉ mục và cắt nguyên lúc luôn tham chiếu đến chỉ mục cụ thể:

data.loc[1]
'a'
data.loc[1:3]
1    a3    bdtype: object

Thuộc tính iloc cho phép truy cập và cắt các phần tử dựa trên chỉ mục ngầm định theo kiểu Python:

data.iloc[1]
'b'
data.iloc[1:3]
3    b5    cdtype: object

Một thuộc tính chỉ mục thứ ba, ix, là một sự kết hợp của hai thuộc tính trên và đối với các đối tượng Series tương đương với việc sử dụng chỉ mục thông thường dựa trên []. Mục đích của trình chỉ mục ix sẽ trở nên rõ ràng hơn trong bối cảnh của các đối tượng DataFrame, chúng ta sẽ thảo luận về chúng trong một khoảng thời gian ngắn.

Một nguyên tắc hướng dẫn viết mã Python là “rõ ràng hơn là ngầm định”.Tính rõ ràng của lociloc khiến chúng trở nên rất hữu ích trong việc duy trì mã sạch và dễ đọc; đặc biệt trong trường hợp chỉ số nguyên, tôi khuyến nghị sử dụng cả hai này để làm cho mã dễ đọc và hiểu, và ngăn chặn những lỗi tinh subtile do quy ước trộn lẫn chỉ mục/đoạn.

Sự lựa chọn dữ liệu trong DataFrame

Hãy nhớ rằng một DataFrame hoạt động theo nhiều cách giống như một mảng hai chiều hoặc cấu trúc có cấu trúc, và theo các cách khác như một từ điển của các cấu trúc Series chia sẻ cùng một chỉ mục.Những tương tự này có thể hữu ích khi chúng ta khám phá lựa chọn dữ liệu trong cấu trúc này.

DataFrame như là một từ điển

Đầu tiên, chúng ta sẽ xem xét tương tự đầu tiên là DataFrame như là một từ điển của các đối tượng Series liên quan.Hãy trở lại ví dụ của chúng ta về diện tích và dân số của các bang:

area = pd.Series({'California': 423967, 'Texas': 695662,                  'New York': 141297, 'Florida': 170312,                  'Illinois': 149995})pop = pd.Series({'California': 38332521, 'Texas': 26448193,                 'New York': 19651127, 'Florida': 19552860,                 'Illinois': 12882135})data = pd.DataFrame({'area':area, 'pop':pop})data

Các Series riêng lẻ tạo thành các cột của DataFrame có thể được truy cập thông qua chỉ mục kiểu từ điển của tên cột:

data['area']
California    423967Florida       170312Illinois      149995New York      141297Texas         695662Name: area, dtype: int64

Tương đương, chúng ta có thể sử dụng truy cập theo thuộc tính với tên cột là chuỗi:

data.area
California    423967Florida       170312Illinois      149995New York      141297Texas         695662Name: area, dtype: int64

Phương thức truy cập cột theo thuộc tính này thực ra truy cập vào chính đối tượng giống như phương thức truy cập cột theo từ điển:

data.area is data['area']
True

Mặc dù đây là một biểu trưng ngắn gọn hữu ích, hãy nhớ rằng nó không hoạt động cho tất cả các trường hợp!
Ví dụ, nếu tên cột không phải là chuỗi, hoặc nếu tên cột xung đột với các phương thức của DataFrame, truy cập theo phong cách thuộc tính này không thể thực hiện.
Ví dụ, DataFrame có một phương thức pop(), vì vậy data.pop sẽ chỉ đến phương thức này chứ không phải cột "pop":

data.pop is data['pop']
False

Đặc biệt, bạn nên tránh cám dỗ thử gán cột thông qua thuộc tính (tức là sử dụng data['pop'] = z thay vì data.pop = z).

Tương tự như với đối tượng Series được thảo luận trước đó, cú pháp theo kiểu từ điển này cũng có thể được sử dụng để sửa đổi đối tượng, trong trường hợp này là thêm một cột mới:

data['density'] = data['pop'] / data['area']data

Đoạn mã này cho thấy một bản xem trước về cú pháp đơn giản của phép tính từng phần tử giữa các đối tượng Series; chúng tôi sẽ khám phá sâu hơn về điều này trong phần Các phép toán trên dữ liệu trong Pandas.

DataFrame như một mảng hai chiều

Như đã đề cập trước đó, chúng ta cũng có thể xem DataFrame như một mảng hai chiều nâng cao. Chúng ta có thể kiểm tra mảng dữ liệu cơ sở bằng cách sử dụng thuộc tính values:

data.values
array([[  4.23967000e+05,   3.83325210e+07,   9.04139261e+01],       [  1.70312000e+05,   1.95528600e+07,   1.14806121e+02],       [  1.49995000e+05,   1.28821350e+07,   8.58837628e+01],       [  1.41297000e+05,   1.96511270e+07,   1.39076746e+02],       [  6.95662000e+05,   2.64481930e+07,   3.80187404e+01]])

Với hình ảnh này trong tư duy, nhiều quan sát tương tự như mảng có thể được thực hiện trên chính DataFrame.

data.T

Khi nói đến việc chỉ mục các đối tượng DataFrame, tuy nhiên, rõ ràng việc chỉ mục theo kiểu từ điển của các cột không cho phép chúng ta đơn giản là xử lý nó như một mảng NumPy.Đặc biệt, việc truyền một chỉ mục duy nhất vào một mảng truy cập một hàng:

data.values[0]
array([  4.23967000e+05,   3.83325210e+07,   9.04139261e+01])

và việc truyền một “index” duy nhất vào một DataFrame để truy cập một cột:

data['area']
California    423967Florida       170312Illinois      149995New York      141297Texas         695662Name: area, dtype: int64

Do đó, để thực hiện chỉ mục theo kiểu mảng, chúng ta cần một quy ước khác.Ở đây, Pandas sử dụng lại các bộ chỉ mục loc, ilocix đã được đề cập trước đó.Sử dụng bộ chỉ mục iloc, chúng ta có thể chỉ mục mảng gốc như thể nó là một mảng NumPy đơn giản (sử dụng chỉ mục kiểu ngầm định của Python), nhưng các nhãn chỉ mục và cột của DataFrame được duy trì trong kết quả:

data.iloc[:3, :2]

Tương tự, sử dụng chỉ số loc chúng ta có thể chỉ mục dữ liệu gốc trong một kiểu dữ liệu giống như mảng nhưng sử dụng chỉ mục và tên cột rõ ràng:

data.loc[:'Illinois', :'pop']

Mục đánh chỉ mục ix cho phép một sự kết hợp của hai phương pháp này:

data.ix[:3, :'pop']

Hãy nhớ rằng đối với các chỉ số số nguyên, trình chỉ mục ix cũng có thể gây nhầm lẫn như đã thảo luận với các đối tượng Series được chỉ số số nguyên.

Bất kỳ mẫu truy cập dữ liệu trong phong cách NumPy nào cũng có thể được sử dụng trong những trình chỉ mục này.Ví dụ, trong bộ chỉ mục loc chúng ta có thể kết hợp lọc và chỉ mục phức tạp như sau:

data.loc[data.density > 100, ['pop', 'density']]

Bất kỳ trong số những quy ước chỉ mục này cũng có thể được sử dụng để đặt hoặc thay đổi các giá trị; điều này được thực hiện theo cách tiêu chuẩn mà bạn có thể quen thuộc từ việc làm việc với NumPy:

data.iloc[0, 2] = 90data

Để nâng cao khả năng xử lý dữ liệu trong Pandas, tôi đề nghị bạn dành một ít thời gian với một DataFrame đơn giản và khám phá các loại chỉ số, cắt, lọc và chỉ số tinh vi mà các phương pháp chỉ số này cho phép.

Các nguyên tắc chỉ mục bổ sung

Có một số quy ước về chỉ mục bổ sung có thể có vẻ mâu thuẫn với phần thảo luận trước đó, nhưng vẫn có thể rất hữu ích trong thực tế.Trước hết, trong khi indexing đề cập đến các cột, thì slicing đề cập đến các hàng:

data['Florida':'Illinois']

Những lát cắt cũng có thể tham chiếu đến các hàng bằng số thay vì bằng chỉ số:

data[1:3]

Tương tự, các hoạt động che khuất trực tiếp cũng được hiểu theo từng hàng chứ không phải từng cột:

data[data.density > 100]

Hai quy ước này cú pháp tương tự như trên một mảng NumPy, và mặc dù chúng có thể không chính xác phù hợp với các quy ước của Pandas, nhưng trong thực tế chúng vẫn rất hữu ích.