在数据处理和分析中,pandas库提供了强大的功能,支持从简单到复杂的数据操作。本文将介绍一些pandas的高级操作,包括多级索引(MultiIndex)、窗口函数(Window Functions)、数据透视表与复杂聚合、数据合并与连接、高级数据变换以及时间序列数据的高级处理。
1. 多级索引(MultiIndex)
多级索引(MultiIndex)是pandas中一个非常有用的功能,它允许我们在一个轴上拥有多个(两个以上)索引级别。这对于处理具有层次结构的数据非常有用,例如,我们可以同时按厂商和产品对销售数据进行分组。
import pandas as pd
import numpy as np
# 创建多重索引的列表
arrays = [
['华为', '华为', '苹果', '苹果', '小米', '小米', '三星', '三星'], # 厂商级别索引
['手机', '笔记本', '手机', '笔记本', '手机', '笔记本', '手机', '笔记本'] # 产品级别索引
]
# 从列表创建多重索引,并给索引级别命名
index = pd.MultiIndex.from_arrays(arrays, names=['厂商', '产品'])
# 创建数据框,使用多重索引作为行索引
# 假设华为的销量和销售额最高,其次是苹果,然后是小米,最后是三星
# 数据单位为“万”
sales_data = [1000, 800, 750, 600, 500, 400, 300, 200] # 销量(单位:万)
revenue_data = [5000, 4000, 3750, 3000, 2500, 2000, 1500, 1000] # 销售额(单位:万)
df = pd.DataFrame({'销量(万)': sales_data, '销售额(万)': revenue_data}, index=index)
print("原始数据框:")
print(df)
# 选择厂商为'华为'和产品为'手机'的数据
filtered_df = df.loc[('华为', '手机')]
print("\n选择厂商为'华为'和产品为'手机'的数据:")
print(filtered_df)
# 重塑数据框,将产品级别索引作为列
reshaped_df = df.unstack(level='产品')
print("\n重塑数据框,将产品级别索引作为列:")
print(reshaped_df)
运行结果:
原始数据框:
销量(万) 销售额(万)
厂商 产品
华为 手机 1000 5000
笔记本 800 4000
苹果 手机 750 3750
笔记本 600 3000
小米 手机 500 2500
笔记本 400 2000
三星 手机 300 1500
笔记本 200 1000
选择厂商为'华为'和产品为'手机'的数据:
销量(万) 1000
销售额(万) 5000
Name: (华为, 手机), dtype: int64
重塑数据框,将产品级别索引作为列:
销量(万) 销售额(万)
产品 手机 笔记本 手机 笔记本
厂商
三星 300 200 1500 1000
华为 1000 800 5000 4000
小米 500 400 2500 2000
苹果 750 600 3750 3000
2. 窗口函数(Window Functions)
窗口函数(Window Functions)是一种非常有用的数据分析工具,特别是在处理时间序列数据时。它们允许我们对数据进行滚动计算,例如计算移动平均。
import pandas as pd
# 创建示例数据框
dates = pd.date_range('2023-01-01', periods=10)
df = pd.DataFrame({'日期': dates, '数值': np.random.randn(10)})
# 设置日期列为索引
df.set_index('日期', inplace=True)
# 计算移动平均
df['移动平均'] = df['数值'].rolling(window=3).mean()
print(df)
运行结果:
数值 移动平均
日期
2023-01-01 -0.695894 NaN
2023-01-02 -0.335897 NaN
2023-01-03 -0.402681 -0.478157
2023-01-04 -0.081337 -0.273305
2023-01-05 0.178860 -0.101719
2023-01-06 -1.256918 -0.386465
2023-01-07 -0.756770 -0.611609
2023-01-08 -1.254951 -1.089546
2023-01-09 1.600473 -0.137083
2023-01-10 -0.343765 0.000586
3. 数据透视表与复杂聚合
数据透视表(Pivot Tables)是pandas中另一个强大的功能,它允许我们快速地对数据进行分组、聚合和重塑。我们还可以使用自定义聚合函数来创建更复杂的数据透视表。
# 创建示例数据框
data = {'类别': ['A', 'A', 'B', 'B'],
'子类别': ['X', 'Y', 'X', 'Y'],
'数值': [10, 20, 30, 40]}
df = pd.DataFrame(data)
# 自定义聚合函数
def custom_agg(x):
return np.sum(x) / np.mean(x)
# 创建数据透视表
pivot_df = df.pivot_table(values='数值', index='类别', columns='子类别', aggfunc=custom_agg)
print(pivot_df)
4. 数据合并与连接
在数据分析中,我们经常需要合并来自不同来源的数据。pandas提供了多种数据合并和连接的方法,可以轻松处理重复列和缺失值。
import pandas as pd
# 创建多个示例数据框
df1 = pd.DataFrame({'产品类别': ['手机', '笔记本', '耳机'],
'品牌': ['华为', '苹果', '小米'],
'销量': [1000, 800, 750]})
df2 = pd.DataFrame({'产品类别': ['笔记本', '耳机', '电视'],
'品牌': ['苹果', '小米', '三星'],
'销售额': [5000, 4000, 3000]})
# 合并数据框
merged_df = df1.merge(df2, on=['产品类别', '品牌'], how='outer')
print(merged_df)
运行结果:
产品类别 品牌 销量 销售额
0 手机 华为 1000 NaN
1 笔记本 苹果 800 5000.0
2 耳机 小米 750 4000.0
3 电视 三星 NaN 3000.0
# 详细解释代码段
merged_df = df1.merge(df2, on=['产品类别', '品牌'], how='outer')
'''
1、df1.merge(df2, on=['产品类别', '品牌'], how='outer'):
df1 和 df2 是两个 pandas 数据框(DataFrame)。
merge 函数用于将两个或多个数据框根据一个或多个键进行合并。
on=['产品类别', '品牌']:指定用于合并的键。这里使用的是多键合并,意味着数据框将基于“产品类别”和“品牌”两个列进行合并。
how='outer':指定合并的方式。'outer' 表示外连接(Outer Join),在这种连接方式下,结果将包含左数据框(df1)和右数据框(df2)的所有行,即使在另一个数据框中没有匹配的行。
2、merged_df = ...:
merged_df 是合并操作的结果,它是一个新的数据框,包含了原始数据框的合并结果。
当运行这段代码时,merged_df 将包含所有在 df1 和 df2 中具有匹配“产品类别”和“品牌”的行。对于在任一数据框中没有匹配的键,结果数据框中将包含缺失值(NaN)。这种合并方式特别适用于需要将来自不同来源的数据整合在一起的场景,比如将销售数据和库存数据合并,以便进行全面的业务分析。
'''
5. 高级数据变换
pandas的apply函数允许我们对数据框的每一行或每一列应用自定义函数,从而实现高级数据变换。
import pandas as pd
# 创建示例数据框
data = {'A': [1, 2, 3, 4],
'B': [10, 20, 30, 40]}
df = pd.DataFrame(data)
# 定义复杂变换函数
def complex_transformation(row):
return pd.Series({
'A加B': row['A'] + row['B'],
'A乘B': row['A'] * row['B'],
'A除以B': row['A'] / row['B'] if row['B'] != 0 else np.nan
})
# 应用复杂变换函数
transformed_df = df.apply(complex_transformation, axis=1)
# 将变换结果和原df合并输出
merged_df=pd.merge(df,transformed_df,left_index=True,right_index=True,how='left')
print(merged_df)
运行结果:
A B A加B A乘B A除以B
0 1 10 11.0 10.0 0.1
1 2 20 22.0 40.0 0.1
2 3 30 33.0 90.0 0.1
3 4 40 44.0 160.0 0.1
【更高效的方案,特别是数据量大的情况】
上面代码是用一个复杂的变换函数来生成新的列。这个函数对每一行数据执行多种计算,包括加法、乘法和除法。为了优化这段代码,我们可以考虑以下几个方面:
- 避免使用apply函数:apply函数在处理大型数据集时可能会很慢,因为它会对每一行数据调用Python函数。使用Pandas的内建函数和向量操作会更高效。
- 直接使用向量操作:Pandas支持向量操作,这意味着您可以对整个列进行操作,而不需要逐行处理。这通常比使用apply函数快得多。
- 简化函数逻辑:如果可以的话,简化函数逻辑可以使其更容易理解和维护。
基于这些原则,我们可以重写代码如下所示:
import pandas as pd
# 创建示例数据框
data = {'A': [1, 2, 3, 4],
'B': [10, 20, 30, 40]}
df = pd.DataFrame(data)
# 使用向量操作进行计算
df['A加B'] = df['A'] + df['B']
df['A乘B'] = df['A'] * df['B']
df['A除以B'] = df['A'] / df['B']
df['A除以B'].fillna(value=np.nan, inplace=True) # 用NaN替换除以0的情况
print(df)
这段代码使用了Pandas的向量操作来计算新列,而不是对每一行应用一个函数。这种方法通常更快,尤其是在处理大型数据集时。同时,我们使用fillna函数来处理除以0的情况,将结果替换为NaN,运行结果一致。
6. 时间序列数据的高级处理
时间序列数据是数据分析中的一个重要方面。在处理时间序列数据时,我们经常需要处理缺失值和时间相关的数据。
import pandas as pd
import numpy as np
# 创建日期范围和数值
dates = pd.date_range('2023-01-01', periods=10)
values = [1, np.nan, 5, np.nan, 8, 13, np.nan, 24, np.nan, 40]
df = pd.DataFrame({'日期': dates, '数值': values})
# 设置日期列为索引
df.set_index('日期', inplace=True)
# 填充缺失值
df['插值填充后数值'] = df['数值'].interpolate(method='time')
print(df)
import matplotlib.pyplot as plt
# 绘图显示插值情况
plt.figure(figsize=(10, 6))
plt.plot(df.index, df['数值'], label='Original Value', marker='o',markersize=20)
plt.plot(df.index, df['插值填充后数值'], label='Interpolated Value', marker='o')
plt.title('Interpolation Results')
plt.xlabel('Date')
plt.ylabel('Value')
plt.legend()
plt.grid(True)
plt.show()
运行结果(插值结果):
数值 插值填充后数值
日期
2023-01-01 1.0 1.0
2023-01-02 NaN 3.0
2023-01-03 5.0 5.0
2023-01-04 NaN 6.5
2023-01-05 8.0 8.0
2023-01-06 13.0 13.0
2023-01-07 NaN 18.5
2023-01-08 24.0 24.0
2023-01-09 NaN 32.0
2023-01-10 40.0 40.0
通过这些示例,我们可以看到pandas的强大功能,它不仅支持基本的表格操作,还支持复杂的数据分析和数据处理任务。这些高级操作是数据科学家和数据分析师在实际工作中常用的工具,能够帮助他们更有效地处理和分析数据。