第146集:Pandas DataFrame高级操作
1. 数据合并
1.1 使用merge()合并
merge()函数用于根据一个或多个键将两个DataFrame连接起来,类似于SQL的JOIN操作。
# 创建两个DataFrame
left = pd.DataFrame({
'key': ['K0', 'K1', 'K2', 'K3'],
'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3']
})
right = pd.DataFrame({
'key': ['K0', 'K1', 'K2', 'K3'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']
})
# 内连接(默认)
result = pd.merge(left, right, on='key')
print(result)
# 左连接
result = pd.merge(left, right, on='key', how='left')
# 右连接
result = pd.merge(left, right, on='key', how='right')
# 外连接
result = pd.merge(left, right, on='key', how='outer')
# 左连接示例
df1 = pd.DataFrame({'员工ID': ['E01', 'E02', 'E03'], '姓名': ['张三', '李四', '王五']})
df2 = pd.DataFrame({'员工ID': ['E01', 'E02', 'E04'], '部门': ['销售部', '技术部', '财务部']})
result = pd.merge(df1, df2, on='员工ID', how='left')
print(result)1.2 使用join()合并
join()函数用于根据索引进行合并。
left = pd.DataFrame({
'A': ['A0', 'A1', 'A2'],
'B': ['B0', 'B1', 'B2']
}, index=['K0', 'K1', 'K2'])
right = pd.DataFrame({
'C': ['C0', 'C1', 'C2'],
'D': ['D0', 'D1', 'D2']
}, index=['K0', 'K1', 'K3'])
# 默认左连接
result = left.join(right)
# 内连接
result = left.join(right, how='inner')
# 外连接
result = left.join(right, how='outer')1.3 使用concat()合并
concat()函数用于沿指定轴连接多个DataFrame。
# 创建三个DataFrame
df1 = pd.DataFrame({'A': ['A0', 'A1'], 'B': ['B0', 'B1']})
df2 = pd.DataFrame({'A': ['A2', 'A3'], 'B': ['B2', 'B3']})
df3 = pd.DataFrame({'C': ['C0', 'C1'], 'D': ['D0', 'D1']})
# 按行连接(垂直堆叠)
result = pd.concat([df1, df2])
# 按列连接(水平堆叠)
result = pd.concat([df1, df3], axis=1)
# 忽略原有索引,重新生成索引
result = pd.concat([df1, df2], ignore_index=True)2. 数据重塑
2.1 使用pivot()透视表
pivot()函数用于将长格式数据转换为宽格式数据。
data = {
'日期': ['2023-01-01', '2023-01-01', '2023-01-02', '2023-01-02'],
'城市': ['北京', '上海', '北京', '上海'],
'温度': [10, 15, 12, 18],
'湿度': [60, 70, 65, 75]
}
df = pd.DataFrame(data)
# 创建透视表
pivot_table = df.pivot(index='日期', columns='城市', values=['温度', '湿度'])
print(pivot_table)2.2 使用melt()融化
melt()函数用于将宽格式数据转换为长格式数据,与pivot()相反。
data = {
'姓名': ['张三', '李四'],
'数学': [95, 88],
'语文': [88, 92],
'英语': [90, 93]
}
df = pd.DataFrame(data)
# 融化数据
melted = df.melt(id_vars=['姓名'], value_vars=['数学', '语文', '英语'],
var_name='科目', value_name='成绩')
print(melted)2.3 使用stack()和unstack()
stack()将列索引转换为行索引,unstack()将行索引转换为列索引。
data = {
'日期': ['2023-01-01', '2023-01-02'],
'北京_温度': [10, 12],
'北京_湿度': [60, 65],
'上海_温度': [15, 18],
'上海_湿度': [70, 75]
}
df = pd.DataFrame(data)
df = df.set_index('日期')
# stack操作
stacked = df.stack()
print(stacked)
# unstack操作
unstacked = stacked.unstack()
print(unstacked)3. 高级分组操作
3.1 多层分组
data = {
'班级': ['一班', '一班', '二班', '二班', '三班', '三班'],
'性别': ['男', '女', '男', '女', '男', '女'],
'姓名': ['张三', '李四', '王五', '赵六', '钱七', '孙八'],
'成绩': [88, 92, 85, 90, 87, 89]
}
df = pd.DataFrame(data)
# 按班级和性别分组
grouped = df.groupby(['班级', '性别'])
# 计算每组的平均成绩
average_scores = grouped['成绩'].mean()
print(average_scores)
# 重置索引
average_scores = average_scores.reset_index()
print(average_scores)3.2 自定义聚合函数
# 定义自定义聚合函数
def range_func(x):
return x.max() - x.min()
# 使用自定义函数进行聚合
stats = grouped['成绩'].agg(['mean', 'max', 'min', range_func])
print(stats)4. 应用函数
4.1 apply()应用函数
# 创建DataFrame
data = {
'A': [1, 2, 3, 4, 5],
'B': [6, 7, 8, 9, 10],
'C': [11, 12, 13, 14, 15]
}
df = pd.DataFrame(data)
# 沿行应用函数(axis=1)
df['行和'] = df.apply(lambda x: x.sum(), axis=1)
# 沿列应用函数(axis=0,默认)
col_sums = df.apply(lambda x: x.sum(), axis=0)
print(df)
print(col_sums)4.2 applymap()应用函数到每个元素
# 将每个元素乘以2
df2 = df.applymap(lambda x: x * 2)
print(df2)4.3 transform()转换数据
# 计算每个分组的均值并减去该均值
df['成绩_标准化'] = grouped['成绩'].transform(lambda x: x - x.mean())
print(df)5. 处理日期时间数据
# 创建包含日期的数据
data = {
'日期': pd.date_range('2023-01-01', periods=12, freq='M'),
'销售额': [100, 120, 130, 110, 140, 150, 160, 170, 180, 190, 200, 210]
}
df = pd.DataFrame(data)
# 提取年份、月份、日期等信息
df['年份'] = df['日期'].dt.year
df['月份'] = df['日期'].dt.month
df['季度'] = df['日期'].dt.quarter
df['星期几'] = df['日期'].dt.day_name()
# 计算日期差
df['日期差'] = df['日期'] - df['日期'].min()
# 设置日期为索引
df = df.set_index('日期')
# 按年份分组统计
yearly_stats = df.groupby('年份')['销售额'].sum()
print(df)
print(yearly_stats)6. 字符串操作
# 创建包含字符串的数据
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'邮箱': ['zhangsan@example.com', 'lisi@example.com', 'wangwu@example.com', 'zhaoliu@example.com'],
'地址': ['北京市朝阳区', '上海市浦东新区', '广州市天河区', '深圳市南山区']
}
df = pd.DataFrame(data)
# 字符串长度
df['姓名长度'] = df['姓名'].str.len()
# 字符串分割
df['邮箱前缀'] = df['邮箱'].str.split('@').str[0]
df['邮箱后缀'] = df['邮箱'].str.split('@').str[1]
# 字符串包含
df['是北京'] = df['地址'].str.contains('北京')
# 字符串替换
df['地址'] = df['地址'].str.replace('市', '')
print(df)7. 高级索引
7.1 使用query()查询
# 创建数据
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 28, 26, 27],
'成绩': [88, 92, 85, 90]
}
df = pd.DataFrame(data)
# 使用query()查询成绩大于90的行
result = df.query('成绩 > 90')
# 查询年龄大于26且成绩大于85的行
result = df.query('年龄 > 26 & 成绩 > 85')
print(result)7.2 使用eval()进行计算
# 使用eval()创建新列
df['总分'] = df.eval('年龄 * 2 + 成绩')
# 比较操作
result = df.eval('成绩 > 90')
print(df)8. 案例分析:销售数据分析
# 创建销售数据
sales_data = {
'订单日期': pd.date_range('2023-01-01', periods=100, freq='D'),
'产品类别': np.random.choice(['电子', '服装', '食品', '家居'], 100),
'销售额': np.random.randint(1000, 10000, 100),
'成本': np.random.randint(500, 5000, 100)
}
df = pd.DataFrame(sales_data)
# 1. 添加利润列
df['利润'] = df['销售额'] - df['成本']
df['利润率'] = df['利润'] / df['销售额']
# 2. 按产品类别和月份分组
df['月份'] = df['订单日期'].dt.month
df['年份'] = df['订单日期'].dt.year
# 3. 计算每个类别每月的销售统计
sales_stats = df.groupby(['产品类别', '月份']).agg({
'销售额': ['sum', 'mean', 'max'],
'成本': ['sum', 'mean'],
'利润': ['sum', 'mean', 'mean']
})
# 4. 找出每个类别利润最高的月份
top_months = df.loc[df.groupby(['产品类别'])['利润'].idxmax()]
# 5. 计算月度销售趋势
monthly_trend = df.groupby('月份')['销售额'].sum()
print(df.head())
print(sales_stats)
print(top_months)
print(monthly_trend)9. 总结
- DataFrame高级操作包括数据合并、重塑、分组等功能
- merge()、join()、concat()用于不同场景的数据合并
- pivot()、melt()、stack()、unstack()用于数据重塑
- groupby()支持多层分组和自定义聚合函数
- apply()、transform()、applymap()用于应用函数到数据
- 提供了丰富的日期时间和字符串操作功能
- query()和eval()提供了更简洁的查询和计算方式
10. 代码练习
请参考code/第146集_Pandas DataFrame高级操作演示.py文件进行实际操作练习。
在下一集中,我们将学习Pandas的时间序列分析功能。