为什么需要按行遍历DataFrame?
在Pandas数据分析中,DataFrame是最常用的数据结构。虽然向量化操作通常是首选,但在某些场景下按行遍历是必要的:
- 需要基于多列值进行复杂条件判断
- 行间计算(如时间序列分析中的前后行比较)
- 调用不接受向量输入的第三方库或API
- 处理需要逐行操作的文本数据
重要提示:
行遍历通常比向量化操作慢,建议仅在必要时使用。对于大型数据集,优先考虑向量化方法或使用更高效的遍历技术。
DataFrame行遍历方法对比
方法 | 速度 | 易用性 | 内存使用 | 适用场景 |
---|---|---|---|---|
iterrows() |
慢 | 高 | 高 | 小数据集、需要索引 |
itertuples() |
快 | 中 | 低 | 中等数据集、性能敏感 |
apply() |
中 | 高 | 中 | 简洁操作、函数式编程 |
索引循环 | 很慢 | 高 | 高 | 不推荐、仅用于教学 |
1. 使用iterrows()方法
iterrows()
是最常用的行遍历方法,它返回每行的索引和行数据(Series对象)。
基本用法示例
import pandas as pd
# 创建示例DataFrame
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 30, 35, 28],
'城市': ['北京', '上海', '广州', '深圳'],
'工资': [15000, 22000, 18000, 25000]
}
df = pd.DataFrame(data)
# 使用iterrows遍历
for index, row in df.iterrows():
# 访问行数据
name = row['姓名']
age = row['年龄']
city = row['城市']
salary = row['工资']
# 示例处理:计算税后工资
tax_rate = 0.1 if salary < 20000 else 0.15
net_salary = salary * (1 - tax_rate)
# 打印结果
print(f"{name}({age}岁,{city}): 税前{salary}元,税后{net_salary:.0f}元")
iterrows()优点:
- 语法简单直观
- 可直接访问列名
- 可同时获取索引和行数据
注意事项:
- 行数据是Series对象,创建有开销
- 修改行数据不会改变原始DataFrame
- 对于大型DataFrame性能较差
2. 使用itertuples()方法
itertuples()
返回命名元组,比iterrows()更快,内存效率更高。
高效遍历示例
# 使用itertuples遍历
for row in df.itertuples():
# 通过属性访问数据
name = row.姓名
age = row.年龄
city = row.城市
salary = row.工资
# 复杂条件判断
if city == '北京' and salary > 20000:
bonus = salary * 0.1
elif city == '上海' and age > 28:
bonus = salary * 0.08
else:
bonus = salary * 0.05
# 添加到新列(实际应用中应避免在循环中修改DataFrame)
df.at[row.Index, '奖金'] = bonus
# 显示结果
print(df[['姓名', '城市', '工资', '奖金']])
命名元组访问方式
row.列名
- 推荐方式row[1]
- 按位置访问(索引0是Index)getattr(row, '列名')
- 动态列名时使用
性能优势
- 比iterrows()快3-5倍
- 内存占用减少50%以上
- 特别适合中等规模数据集
3. 使用apply()方法
apply()
结合lambda函数或自定义函数,提供更函数式的行处理方式。
应用函数到每行
# 定义处理函数
def calculate_raise(row):
"""根据城市和年龄计算加薪比例"""
base_raise = 0.05
# 基于条件的调整
if row['城市'] in ['北京', '上海']:
base_raise += 0.02
if row['年龄'] > 30:
base_raise += 0.03
# 上限检查
return min(base_raise, 0.1)
# 应用函数到每行
df['加薪比例'] = df.apply(calculate_raise, axis=1)
# 计算新工资
df['新工资'] = df.apply(lambda row: row['工资'] * (1 + row['加薪比例']), axis=1)
# 显示结果
print(df[['姓名', '城市', '年龄', '工资', '加薪比例', '新工资']])
apply()最佳实践
- 使用命名函数而非复杂lambda,提高可读性
- 在函数内部避免修改原始行,返回新值
- 设置
axis=1
参数确保按行应用 - 对于简单操作,向量化方法可能更高效
性能比较与选择指南
1x
iterrows()
基准速度
3-5x
itertuples()
比iterrows快
1.5-2x
apply()
中等速度
选择指南:
- 小型数据集(<1,000行):任意方法均可,iterrows()最易用
- 中型数据集(1,000-100,000行):优先使用itertuples()
- 大型数据集(>100,000行):考虑向量化操作或分块处理
- 复杂行逻辑:apply()配合自定义函数可提高可读性
- 需要索引:iterrows()或itertuples()
发表评论