Pandas: 数据选取

最后更新:2026-08-26

数据选取是数据分析最频繁的操作——"给我看满足条件的数据"。Pandas 提供了丰富的选取方式:按标签、按位置、按条件、按表达式,甚至像 SQL 一样用 query 字符串。本节带你掌握所有选取方法,并避开最常见的"链式索引"陷阱。

⚠️ 注意: 以下代码需在本地 Python 环境中运行。

1. 你将学到


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) 安全选取决策树

100%
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 语义"。

📖 小节


📝 作业

  1. 基础题(难度⭐):创建一个学生 DataFrame(name / math / english / science),用 loc 选取 math > 80 的学生的 name 和 math 列,用 iloc 选取前 3 行。
  2. 进阶题(难度⭐⭐):用 3 种方式(布尔索引 / query / isin)筛选同一样数据:price 在 50-200 之间且 category 为 Electronics 或 Home。对比代码量和可读性。
  3. 挑战题(难度⭐⭐⭐):创建一个 50 行的商品 DataFrame,完成 5 种选取练习:loc 单行 / iloc 切片 / 多条件布尔 / query 变量 / isin 多值,每次选取后用 loc 安全赋值一个新列标记,最后统计各标记的数量。

← 上一课:数据类型 · 下一课:数据读写 →

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏