Pandas: 数据选取
最后更新:2026-08-26
数据选取是数据分析最频繁的操作——"给我看满足条件的数据"。Pandas 提供了丰富的选取方式:按标签、按位置、按条件、按表达式,甚至像 SQL 一样用 query 字符串。本节带你掌握所有选取方法,并避开最常见的"链式索引"陷阱。
⚠️ 注意: 以下代码需在本地 Python 环境中运行。
1. 你将学到
- ❶ loc 标签选取
- ❷ iloc 位置选取
- ❸ 条件筛选(布尔索引)
- ❹ query 方法
- ❺ isin 过滤与链式索引陷阱
2. Charlie 的商品筛选需求
(1) 痛点:多条件组合太繁琐
Charlie 需要从 1000 件商品中筛选出"价格 > 50 且评分 > 4.0 的电子产品"。他先用布尔索引写了一长串条件:
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard',
'Mouse', 'Headset', 'Speaker', 'Camera', 'Charger'],
'category': ['Electronics', 'Electronics', 'Electronics', 'Electronics',
'Accessories', 'Accessories', 'Accessories', 'Accessories',
'Electronics', 'Accessories'],
'price': [999.99, 699.99, 349.99, 449.99, 79.99,
29.99, 149.99, 89.99, 599.99, 19.99],
'stock': [50, 120, 80, 35, 200, 300, 150, 180, 25, 500],
'rating': [4.7, 4.5, 4.3, 4.6, 4.2, 4.0, 4.4, 4.1, 4.8, 3.9]
})
# Boolean indexing — works but verbose
result = df[(df['price'] > 50) & (df['rating'] > 4.0) & (df['category'] == 'Electronics')]
print(result[['name', 'price', 'rating']])
# name price rating
# 0 Laptop 999.99 4.7
# 1 Phone 699.99 4.5
# 2 Tablet 349.99 4.3
# 3 Monitor 449.99 4.6
# 8 Camera 599.99 4.8
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) 解法:query 方法更可读
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:query 可读查询(难度⭐⭐)
PYTHON
# Same result, much more readable
result = df.query('price > 50 and rating > 4.0 and category == "Electronics"')
print(result[['name', 'price', 'rating']])
# With variable
min_price = 50
min_rating = 4.0
result2 = df.query('price > @min_price and rating > @min_rating')
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(3) 收益:4 种选取方式各有所长
| 方式 | 语法 | 最适合 |
|---|---|---|
| loc | df.loc[row, col] |
精确标签选取 |
| iloc | df.iloc[r, c] |
按位置选取 |
| 布尔索引 | df[condition] |
简单条件 |
| query | df.query('expr') |
复杂多条件 |
3. loc:标签选取
(1) loc 语法
df.loc[row_label, col_label] — 按标签选取,切片包含端点。
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:loc 标签选取(难度⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard'],
'price': [999.99, 699.99, 349.99, 449.99, 79.99],
'stock': [50, 120, 80, 35, 200]
}, index=['A001', 'A002', 'A003', 'A004', 'A005'])
# Single row by label
print(df.loc['A001'])
# name Laptop
# price 999.99
# stock 50
# Multiple rows
print(df.loc[['A001', 'A003']])
# Row slice + column slice (labels, INCLUDES endpoint)
print(df.loc['A001':'A003', 'name':'price'])
# name price
# A001 Laptop 999.99
# A002 Phone 699.99
# A003 Tablet 349.99
# Specific rows + specific columns
print(df.loc[['A001', 'A004'], ['name', 'stock']])
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) loc 条件选取
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:loc + 条件(难度⭐⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard'],
'price': [999.99, 699.99, 349.99, 449.99, 79.99],
'stock': [50, 120, 80, 35, 200]
})
# Filter rows + select columns in one operation
expensive = df.loc[df['price'] > 400, ['name', 'price']]
print(expensive)
# name price
# 0 Laptop 999.99
# 1 Phone 699.99
# 3 Monitor 449.99
# With assignment (safe — no chained indexing)
df.loc[df['stock'] < 50, 'stock'] = 50 # restock low items
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
4. iloc:位置选取
(1) iloc 语法
df.iloc[row_pos, col_pos] — 按整数位置选取,切片不包含端点(Python 风格)。
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:iloc 位置选取(难度⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard'],
'price': [999.99, 699.99, 349.99, 449.99, 79.99],
'stock': [50, 120, 80, 35, 200]
})
# Single row by position
print(df.iloc[0]) # first row (Laptop)
# Multiple rows by position list
print(df.iloc[[0, 2, 4]])
# Row slice + column slice (positions, EXCLUDES endpoint)
print(df.iloc[0:3, 0:2])
# name price
# 0 Laptop 999.99
# 1 Phone 699.99
# 2 Tablet 349.99
# Last 2 rows
print(df.iloc[-2:])
# Every other row
print(df.iloc[::2])
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) loc vs iloc 关键区别
| 特性 | loc | iloc |
|---|---|---|
| 索引依据 | 标签 | 整数位置 |
| 切片端点 | 包含端点 | 不包含端点 |
| 用字符串标签 | ✅ | ❌ |
| 用负数索引 | ❌ | ✅ |
| 用条件筛选 | ✅ | ❌ |
| 推荐场景 | 知道名称 | 知道位置 |
🔥 易错:
df.loc[0:3] 包含行 0,1,2,3(4 行),df.iloc[0:3] 包含行 0,1,2(3 行)。这是 loc 和 iloc 最常见的混淆点。
5. 条件筛选(布尔索引)
(1) 单条件与多条件
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:条件筛选(难度⭐⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard'],
'category': ['Electronics', 'Electronics', 'Electronics', 'Electronics', 'Accessories'],
'price': [999.99, 699.99, 349.99, 449.99, 79.99],
'stock': [50, 120, 80, 35, 200],
'rating': [4.7, 4.5, 4.3, 4.6, 4.2]
})
# Single condition
print(df[df['price'] > 400])
# Multiple conditions: & (AND), | (OR), ~ (NOT)
# MUST use parentheses around each condition!
high_price_good_rating = df[(df['price'] > 400) & (df['rating'] >= 4.5)]
print(high_price_good_rating[['name', 'price', 'rating']])
# OR condition
hot_items = df[(df['price'] > 500) | (df['stock'] > 100)]
print(hot_items[['name', 'price', 'stock']])
# NOT condition
not_electronics = df[~(df['category'] == 'Electronics')]
print(not_electronics)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
⚠️ 注意: 多条件组合必须用
& / | / ~,不能用 and / or / not。每个条件必须用括号包裹,否则运算符优先级会导致报错。
(2) 字符串条件
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:字符串条件筛选(难度⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Wireless Mouse', 'USB Keyboard', 'Bluetooth Headset',
'Wireless Speaker', 'USB Camera'],
'price': [29.99, 79.99, 149.99, 89.99, 599.99]
})
# Contains substring
wireless = df[df['name'].str.contains('Wireless')]
print(wireless)
# Starts with
usb = df[df['name'].str.startswith('USB')]
print(usb)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
6. query 方法
(1) 基本语法
df.query('expression') — 用字符串表达式筛选行,更接近 SQL 的可读性。
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:query 表达式查询(难度⭐⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard'],
'category': ['Electronics', 'Electronics', 'Electronics', 'Electronics', 'Accessories'],
'price': [999.99, 699.99, 349.99, 449.99, 79.99],
'stock': [50, 120, 80, 35, 200],
'rating': [4.7, 4.5, 4.3, 4.6, 4.2]
})
# Simple condition
print(df.query('price > 400'))
# Multiple conditions (and/or instead of &/|)
print(df.query('price > 400 and rating >= 4.5'))
# String comparison
print(df.query('category == "Electronics"'))
# Use @ to reference Python variables
threshold = 100
print(df.query('stock > @threshold'))
# Column names with spaces (backtick)
# df.query('`unit price` > 100')
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) query vs 布尔索引对比
| 特性 | 布尔索引 | query |
|---|---|---|
| 语法 | df[(df.a>1) & (df.b<2)] |
df.query('a>1 and b<2') |
| 可读性 | 括号嵌套 | 接近 SQL |
| 变量引用 | 直接用 | 需要 @ 前缀 |
| 列名空格 | 无问题 | 需反引号 |
| 性能 | 略慢(大DF) | 略快(引擎优化) |
| 灵活性 | 最高 | 受限于表达式语法 |
7. isin 过滤
(1) 多值匹配
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:isin 多值过滤(难度⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard'],
'category': ['Electronics', 'Electronics', 'Electronics', 'Electronics', 'Accessories'],
'price': [999.99, 699.99, 349.99, 449.99, 79.99]
})
# Filter by multiple category values
target_cats = ['Electronics', 'Audio']
# Note: Audio not in data → no match, no error
result = df[df['category'].isin(target_cats)]
print(result[['name', 'category']])
# Negation: NOT in list
other = df[~df['category'].isin(['Electronics'])]
print(other)
# Only Accessories
# isin with numeric values
target_prices = [999.99, 79.99]
print(df[df['price'].isin(target_prices)])
# Laptop and Keyboard
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) isin vs == 多值对比
| 方式 | 语法 | 适用 |
|---|---|---|
| isin | df[col].isin([v1,v2,v3]) |
多值匹配 |
| == | df[col] == v1 |
单值匹配 |
| | 组合 | (df[col]==v1) | (df[col]==v2) |
少量多值 |
| query | df.query('col in ["v1","v2"]') |
可读多值 |
8. 链式索引陷阱
(1) 什么是链式索引
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:链式索引的隐患(难度⭐⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Laptop', 'Phone', 'Tablet'],
'price': [999.99, 699.99, 349.99],
'category': ['Electronics', 'Electronics', 'Electronics']
})
# ❌ Chained indexing — may trigger SettingWithCopyWarning
# df[df['price'] > 400]['price'] = 0 # Unpredictable!
# ✅ Single operation with loc
df.loc[df['price'] > 400, 'price'] = 0 # Always works
# ❌ Another chained form
# df[df['category'] == 'Electronics']['stock'] = 100
# ✅ Correct approach
df.loc[df['category'] == 'Electronics', 'stock'] = 100
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
🔥 易错: 链式索引
df[condition][col] = value 可能不修改原 DataFrame(中间结果是副本)。正确写法:df.loc[condition, col] = value——一次操作同时指定行和列。
(2) 安全选取决策树
graph TB
Q["Need to select data?"] -->|"Read only"| LOC["loc / iloc / boolean"]
Q -->|"Read + Assign"| SAFE["loc[row_cond, col] = value"]
Q -->|"Complex filter"| QUERY["query()"]
Q -->|"Multi-value match"| ISIN["isin()"]
SAFE --> WARN["❌ Never: df[cond][col] = val"]
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
9. 完整示例:电商商品多维度筛选
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:商品筛选全流程(难度⭐⭐⭐)
PYTHON
import pandas as pd
import numpy as np
# ============================================
# Comprehensive example: E-commerce product
# multi-dimension selection workflow
# ============================================
# 1. Create product catalog
np.random.seed(42)
df = pd.DataFrame({
'name': [f'Product_{i:03d}' for i in range(1, 51)],
'category': np.random.choice(['Electronics', 'Clothing', 'Home', 'Sports'], 50),
'price': np.round(np.random.uniform(10, 500, 50), 2),
'stock': np.random.randint(0, 300, 50),
'rating': np.round(np.random.uniform(3.0, 5.0, 50), 1),
'brand': np.random.choice(['Alpha', 'Beta', 'Gamma', 'Delta'], 50)
})
# 2. loc: precise selection
print("=== Electronics with price > 200 ===")
elec_expensive = df.loc[
(df['category'] == 'Electronics') & (df['price'] > 200),
['name', 'price', 'rating']
]
print(elec_expensive.head())
# 3. iloc: position-based selection
print("\n=== First 3 rows, first 4 columns ===")
print(df.iloc[:3, :4])
# 4. Boolean: multi-condition
print("\n=== High rating, in stock, under $100 ===")
bargains = df[(df['rating'] >= 4.5) & (df['stock'] > 0) & (df['price'] < 100)]
print(bargains[['name', 'price', 'rating', 'stock']])
# 5. query: readable complex filter
print("\n=== Alpha brand Electronics or Home, rating >= 4.0 ===")
query_result = df.query(
'brand == "Alpha" and category in ["Electronics", "Home"] and rating >= 4.0'
)
print(query_result[['name', 'category', 'rating']])
# 6. isin: multi-value filter
print("\n=== Selected brands ===")
top_brands = df[df['brand'].isin(['Alpha', 'Beta'])]
print(f"Alpha + Beta products: {len(top_brands)}")
# 7. Safe assignment
df.loc[df['stock'] == 0, 'status'] = 'Out of Stock'
df.loc[df['stock'] > 0, 'status'] = 'In Stock'
print(f"\n=== Stock Status ===")
print(df['status'].value_counts())
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
❓ 常见问题
Q loc 和 iloc 区别?
A loc 按标签选取(行名/列名),切片包含端点。iloc 按整数位置选取,切片不包含端点(Python 风格)。知道名称用 loc,知道位置用 iloc。当 Index 是默认 RangeIndex(0,1,2...)时,loc[0] 和 iloc[0] 结果相同,但语义不同。
Q 条件筛选为什么要括号?
A Python 的 & / | / ~ 运算符优先级高于比较运算符。
df['a'] > 1 & df['b'] < 2 被解析为 df['a'] > (1 & df['b']) < 2,报错。必须写 (df['a'] > 1) & (df['b'] < 2)。不能使用 and/or/not——它们不支持数组级别的逐元素运算。Q chain indexing 什么问题?
A
df[condition][col] = value 是两次独立操作:第一次返回可能是视图也可能是副本,第二次在副本上赋值不会影响原 DataFrame。这导致"改了但没生效"的隐蔽 bug。正确写法:df.loc[condition, col] = value,一次操作同时指定行列。Q query 支持变量吗?
A 支持。用 @ 引用外部变量:
df.query('price > @min_price')。列名有空格用反引号:df.query('unit price > 100')。query 内部支持 and/or/not/in 等关键字,更接近自然语言。Q isin 和 == 区别?
A == 只能匹配单个值,isin 可以一次匹配多个值。
df[col].isin([v1,v2,v3]) 等价于 (df[col]==v1) | (df[col]==v2) | (df[col]==v3),但更简洁高效。需要取反时用 ~df[col].isin(...)。Q 选取后赋值有什么坑?
A 最大的坑是链式索引(见 FAQ #3)。另一个坑是
df[df.a > 0] = 1 会把整行设为 1(不是只设 a 列)。正确:df.loc[df.a > 0, 'a'] = 1。始终用 loc 同时指定行条件和目标列。Q loc 切片为什么包含端点?
A 这是 Pandas 的设计选择——按标签切片时,端点的含义是"从标签 A 到标签 B",包含两者更符合直觉(就像字典的 key range)。iloc 按位置切片遵循 Python 惯例(不包含端点)。记住:loc 是"标签语义",iloc 是"Python 语义"。
📖 小节
- loc 按标签选取,切片包含端点;iloc 按位置选取,切片不包含端点
- 条件筛选用布尔索引,多条件组合用 & / | / ~(必须括号包裹)
- query 方法用字符串表达式,更接近 SQL 可读性,支持 @变量引用
- isin 用于多值匹配,比多个 == + | 组合更简洁高效
- 链式索引
df[cond][col] = val是隐蔽 bug,必须用df.loc[cond, col] = val - 字符串条件筛选用 .str.contains() / .str.startswith() 等
- 选取决策:读数据→loc/iloc/query/isin,赋值→loc[行条件, 列名]
📝 作业
- 基础题(难度⭐):创建一个学生 DataFrame(name / math / english / science),用 loc 选取 math > 80 的学生的 name 和 math 列,用 iloc 选取前 3 行。
- 进阶题(难度⭐⭐):用 3 种方式(布尔索引 / query / isin)筛选同一样数据:price 在 50-200 之间且 category 为 Electronics 或 Home。对比代码量和可读性。
- 挑战题(难度⭐⭐⭐):创建一个 50 行的商品 DataFrame,完成 5 种选取练习:loc 单行 / iloc 切片 / 多条件布尔 / query 变量 / isin 多值,每次选取后用 loc 安全赋值一个新列标记,最后统计各标记的数量。