数据选择与过滤
数据分析中,经常需要从大量数据中筛选出需要的数据子集。Pandas 提供了多种强大的数据选择和过滤方法。本章将详细介绍这些技术。
选择器概述
Pandas 提供了多种数据选择方式:
选择列
选择单列
import pandas as pd
import numpy as np
# 创建示例数据
df = pd.DataFrame({
'name': ['张三', '李四', '王五', '赵六'],
'age': [25, 30, 35, 28],
'city': ['北京', '上海', '广州', '深圳'],
'salary': [10000, 15000, 20000, 12000],
'department': ['技术', '市场', '技术', '人事']
})
# 选择单列 - 返回 Series
name_series = df['name']
print(type(name_series))
# <class 'pandas.core.series.Series'>
print(name_series)
# 0 张三
# 1 李四
# 2 王五
# 3 赵六
# Name: name, dtype: object
选择多列
# 选择多列 - 返回 DataFrame
subset = df[['name', 'salary']]
print(type(subset))
# <class 'pandas.core.frame.DataFrame'>
print(subset)
# name salary
# 0 张三 10000
# 1 李四 15000
# 2 王五 20000
# 3 赵六 12000
使用 loc 和 iloc 选择列
# loc - 通过标签选择
print(df.loc[:, 'name']) # 所有行的 name 列
print(df.loc[:, 'name':'salary']) # name 到 salary 列(含)
# iloc - 通过位置选择
print(df.iloc[:, 0]) # 第1列
print(df.iloc[:, [0, 2, 4]]) # 第1、3、5列
print(df.iloc[:, :3]) # 前3列
选择行
使用 loc(通过标签)
# 设置索引
df = pd.DataFrame({
'name': ['张三', '李四', '王五', '赵六'],
'age': [25, 30, 35, 28],
'salary': [10000, 15000, 20000, 12000]
}, index=['a', 'b', 'c', 'd'])
# 选择单行
print(df.loc['a'])
# name 张三
# age 25
# salary 10000
# Name: a, dtype: object
# 选择多行
print(df.loc[['a', 'c']])
# name age salary
# a 张三 25 10000
# c 王五 35 20000
# 行范围切片
print(df.loc['a':'c'])
# name age salary
# a 张三 25 10000
# b 李四 30 15000
# c 王五 35 20000
使用 iloc(通过位置)
# 选择单行
print(df.iloc[0])
# name 张三
# age 25
# salary 10000
# Name: 0, dtype: object
# 选择多行
print(df.iloc[[0, 2]])
# name age salary
# 0 张三 25 10000
# 2 王五 35 20000
# 行范围切片
print(df.iloc[0:3])
# name age salary
# 0 张三 25 10000
# 1 李四 30 15000
# 2 王五 35 20000
同时选择行和列
使用 loc
# 同时指定行和列
print(df.loc['a', 'name']) # '张三' - 单个值
# 选择多行多列
print(df.loc[['a', 'c'], ['name', 'salary']])
# name salary
# a 张三 10000
# c 王五 20000
# 行列范围
print(df.loc['a':'c', 'name':'salary'])
# name age salary
# a 张三 25 10000
# b 李四 30 15000
# c 王五 35 20000
使用 iloc
# 同时指定行和列
print(df.iloc[0, 0]) # '张三'
# 选择多行多列
print(df.iloc[[0, 2], [0, 2]])
# name salary
# 0 张三 10000
# 2 王五 20000
# 行列范围
print(df.iloc[0:3, 0:3])
# name age salary
# 0 张三 25 10000
# 1 李四 30 15000
# 2 王五 35 20000
布尔索引(条件筛选)
布尔索引是数据筛选最常用的方式。
基础布尔索引
df = pd.DataFrame({
'name': ['张三', '李四', '王五', '赵六', '钱七'],
'age': [25, 30, 35, 28, 45],
'salary': [10000, 15000, 20000, 12000, 30000],
'department': ['技术', '市场', '技术', '人事', '技术']
})
# 简单条件
print(df[df['age'] > 30])
# name age salary department
# 2 王五 35 20000 技术
# 4 钱七 45 30000 技术
# 字符串条件
print(df[df['department'] == '技术'])
# name age salary department
# 0 张三 25 10000 技术
# 2 王五 35 20000 技术
# 4 钱七 45 30000 技术
组合条件
# AND 条件
print(df[(df['age'] > 25) & (df['salary'] > 15000)])
# name age salary department
# 2 王五 35 20000 技术
# 4 钱七 45 30000 技术
# OR 条件
print(df[(df['department'] == '技术') | (df['department'] == '市场')])
# name age salary department
# 0 张三 25 10000 技术
# 1 李四 30 15000 市场
# 2 王五 35 20000 技术
# 4 钱七 45 30000 技术
# NOT 条件
print(df[~(df['department'] == '技术')])
# name age salary department
# 1 李四 30 15000 市场
# 3 赵六 28 12000 人事
使用 isin
# 筛选值在列表中的行
print(df[df['department'].isin(['技术', '市场'])])
# name age salary department
# 0 张三 25 10000 技术
# 1 李四 30 15000 市场
# 2 王五 35 20000 技术
# 4 钱七 45 30000 技术
# 筛选值不在列表中的行
print(df[~df['department'].isin(['技术', '市场'])])
# name age salary department
# 3 赵六 28 12000 人事
使用 between
# 范围筛选
print(df[df['age'].between(25, 35)])
# name age salary department
# 0 张三 25 10000 技术
# 1 李四 30 15000 市场
# 2 王五 35 20000 技术
# 3 赵六 28 12000 人事
使用字符串方法
df = pd.DataFrame({
'name': ['张三', '李四', '王五', '赵六'],
'city': ['北京市', '上海市', '广州市', '深圳市']
})
# 字符串包含
print(df[df['city'].str.contains('北京')])
# name city
# 0 张三 北京市
# 字符串开头/结尾
print(df[df['city'].str.startswith('北')])
print(df[df['city'].str.endswith('市')])
# 字符串匹配
print(df[df['name'].str.match('张.*')])
# 正则表达式
print(df[df['city'].str.contains(r'[北上广深]')])
缺失值条件筛选
df = pd.DataFrame({
'name': ['张三', '李四', '王五', '赵六'],
'age': [25, 30, None, 28],
'salary': [10000, None, 20000, 12000]
})
# 筛选有缺失值的行
print(df[df.isnull().any(axis=1)])
# name age salary
# 1 李四 30.0 NaN
# 2 王五 NaN 20000.0
# 筛选无缺失值的行
print(df[df.notnull().all(axis=1)])
# name age salary
# 0 张三 25.0 10000.0
# 3 赵六 28.0 12000.0
使用 query 方法
query 方法提供了一种更直观的条件筛选方式。
基本用法
df = pd.DataFrame({
'name': ['张三', '李四', '王五', '赵六'],
'age': [25, 30, 35, 28],
'salary': [10000, 15000, 20000, 12000]
})
# 使用 query
print(df.query('age > 30'))
# name age salary
# 2 王五 35 20000
# 多条件
print(df.query('age > 25 and salary > 12000'))
# name age salary
# 2 王五 35 20000
使用变量
min_age = 25
min_salary = 12000
# 在 query 中使用变量(需要 @ 前缀)
print(df.query('age > @min_age and salary > @min_salary'))
# name age salary
# 1 李四 30 15000
# 2 王五 35 20000
列表条件
# 使用 in
print(df.query('name in ["张三", "王五"]'))
# 使用 not in
print(df.query('name not in ["张三", "王五"]'))
使用 filter 方法
filter 方法用于按列名模式筛选。
按列名筛选
df = pd.DataFrame({
'name': ['张三', '李四'],
'age': [25, 30],
'salary': [10000, 15000],
'bonus': [1000, 1500],
'department': ['技术', '市场']
})
# 包含关键词的列
print(df.filter(like='a')) # 包含 'a' 的列: age, salary
# age salary
# 0 25 10000
# 1 30 15000
# 正则表达式
print(df.filter(regex='[ab]')) # 包含 a 或 b 的列: name, bonus
# name bonus
# 0 张三 1000
# 1 李四 1500
高级技巧
使用 nlargest 和 nsmallest
# 最大的几行
print(df.nlargest(3, 'salary'))
# name age salary
# 2 王五 35 20000
# 1 李四 30 15000
# 3 赵六 28 12000
# 最小的几行
print(df.nsmallest(3, 'age'))
# name age salary
# 0 张三 25 10000
# 3 赵六 28 12000
# 1 李四 30 15000
使用 sample
# 随机抽样
print(df.sample(n=2)) # 随机选择2行
print(df.sample(frac=0.5)) # 随机选择50%的行
# 可重复抽样
print(df.sample(n=6, replace=True))
链式筛选
# 链式操作
result = (df
.query('age > 25') # 筛选年龄大于25
.sort_values('salary', ascending=False) # 按工资降序
.head(3) # 取前3
[['name', 'age', 'salary']] # 选择需要的列
)
print(result)
实战示例
示例:电商订单筛选
# 创建订单数据
orders = pd.DataFrame({
'order_id': [f'ORD{i:04d}' for i in range(1, 101)],
'customer': ['customer_' + str(i % 20) for i in range(100)],
'product': ['产品A', '产品B', '产品C', '产品D'] * 25,
'quantity': np.random.randint(1, 10, 100),
'price': np.random.randint(100, 1000, 100),
'date': pd.date_range('2024-01-01', periods=100)
})
# 计算订单总额
orders['total'] = orders['quantity'] * orders['price']
# 筛选条件
# 1. 订单金额大于5000
high_value = orders[orders['total'] > 5000]
print(f'高价值订单数量: {len(high_value)}')
# 2. 特定客户的订单
customer_orders = orders[orders['customer'] == 'customer_5']
print(f'customer_5 的订单数量: {len(customer_orders)}')
# 3. 某日期范围的订单
orders_2024 = orders.query('date >= "2024-01-15" and date <= "2024-01-31"')
print(f'1月15-31日订单数量: {len(orders_2024)}')
# 4. 复杂条件
# 购买产品A且订单金额大于3000的客户
target = orders[(orders['product'] == '产品A') & (orders['total'] > 3000)]
print(target[['order_id', 'customer', 'product', 'total']])
示例:员工数据分析
# 创建员工数据
employees = pd.DataFrame({
'id': range(1, 21),
'name': ['员工' + str(i) for i in range(1, 21)],
'department': ['技术']*8 + ['市场']*7 + ['人事']*5,
'position': ['工程师']*10 + ['经理']*5 + ['专员']*5,
'age': np.random.randint(22, 55, 20),
'salary': np.random.randint(5000, 30000, 20),
'performance': np.random.choice(['A', 'B', 'C', 'D'], 20)
})
# 1. 找出各部门年龄最大的员工
oldest = employees.loc[employees.groupby('department')['age'].idxmax()]
print(oldest[['name', 'department', 'age']])
# 2. 找出绩效为A的员工
top_performers = employees[employees['performance'] == 'A']
print(f'A级绩效员工数: {len(top_performers)}')
# 3. 薪资前20%的员工
threshold = employees['salary'].quantile(0.8)
top_salary = employees[employees['salary'] >= threshold]
print(top_salary[['name', 'salary']].sort_values('salary', ascending=False))
小结
本章我们学习了:
- 选择列:单列、多列、loc/iloc 选择
- 选择行:loc 标签索引、iloc 位置索引
- 布尔索引:基础条件、组合条件、isin、between
- 字符串方法:contains、startswith、regex
- query 方法:更直观的条件筛选
- filter 方法:按列名模式筛选
- 高级技巧:nlargest、nsmallest、sample、链式操作
练习
- 创建一个包含 100 行的随机数据 DataFrame
- 使用布尔索引筛选出值大于平均值的行
- 使用 query 方法筛选多条件数据
- 创建一个复杂的多条件筛选并解释每一步
参考资源
下一步
数据选择和过滤是数据分析的基础技能。接下来让我们学习 数据清洗,了解如何处理缺失值、异常值等常见数据问题!