第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的时间序列分析功能。

« 上一篇 Pandas DataFrame 下一篇 » 数据筛选与排序