引言

pandas是Python生态系统中最重要的数据分析库之一,它提供了高性能、易于使用的数据结构和数据分析工具。无论你是数据科学家、分析师还是研究人员,掌握pandas都将极大提升你的数据处理能力。本文将通过十个经典应用案例,带你深入了解pandas的强大功能,助你从入门到精通。

pandas基础知识回顾

在深入案例之前,让我们简要回顾pandas的核心数据结构:

  • Series:一维标记数组,能够保存任何数据类型。
  • DataFrame:二维标记数据结构,类似于Excel表格或SQL表。

安装pandas非常简单:

pip install pandas 

导入pandas的常规方式:

import pandas as pd import numpy as np 

案例一:数据清洗与预处理

数据清洗是数据分析过程中最耗时但至关重要的步骤。pandas提供了多种工具来处理常见的数据问题。

问题识别与处理

# 创建包含各种数据问题的示例DataFrame data = { 'Name': ['John', 'Anna', 'Peter', 'Linda', 'John', 'NaN'], 'Age': [28, 24, 35, 32, 28, 'unknown'], 'Salary': [50000, 60000, 70000, 80000, 50000, None], 'Join_Date': ['2020-01-01', '2019-05-15', '2018-11-20', '2021-02-10', '2020-01-01', '2022-03-05'] } df = pd.DataFrame(data) print("原始数据:") print(df) # 1. 处理重复值 print("n重复值检测:") print(df.duplicated()) # 删除重复行 df_cleaned = df.drop_duplicates() print("n删除重复行后:") print(df_cleaned) # 2. 处理缺失值 print("n缺失值检测:") print(df_cleaned.isnull()) # 填充缺失值 df_cleaned['Salary'].fillna(df_cleaned['Salary'].mean(), inplace=True) print("n填充缺失值后:") print(df_cleaned) # 3. 处理异常值 # 将'unknown'替换为NaN,然后转换为数值类型 df_cleaned['Age'] = pd.to_numeric(df_cleaned['Age'], errors='coerce') df_cleaned['Age'].fillna(df_cleaned['Age'].mean(), inplace=True) print("n处理异常值后:") print(df_cleaned) # 4. 数据类型转换 df_cleaned['Join_Date'] = pd.to_datetime(df_cleaned['Join_Date']) print("n数据类型转换后:") print(df_cleaned.dtypes) 

数据标准化与规范化

# 创建示例数据 data = { 'Product': ['A', 'B', 'C', 'D', 'E'], 'Price': [100, 200, 300, 400, 500], 'Weight': [10, 20, 30, 40, 50] } df = pd.DataFrame(data) # 最小-最大规范化 (Min-Max Normalization) df['Price_Normalized'] = (df['Price'] - df['Price'].min()) / (df['Price'].max() - df['Price'].min()) df['Weight_Normalized'] = (df['Weight'] - df['Weight'].min()) / (df['Weight'].max() - df['Weight'].min()) print("最小-最大规范化后:") print(df) # Z-score标准化 df['Price_Standardized'] = (df['Price'] - df['Price'].mean()) / df['Price'].std() df['Weight_Standardized'] = (df['Weight'] - df['Weight'].mean()) / df['Weight'].std() print("nZ-score标准化后:") print(df) 

案例二:数据探索性分析

探索性数据分析(EDA)是理解数据集特征、发现模式和关系的关键步骤。

基本统计描述

# 使用内置数据集 import seaborn as sns df = sns.load_dataset('iris') # 基本统计描述 print("数据集基本信息:") print(df.info()) print("n数据集描述性统计:") print(df.describe()) # 按类别分组统计 print("n按物种分组的统计信息:") print(df.groupby('species').describe()) 

相关性分析

# 计算相关性矩阵 correlation = df.corr() print("相关性矩阵:") print(correlation) # 可视化相关性矩阵 import matplotlib.pyplot as plt import seaborn as sns plt.figure(figsize=(10, 8)) sns.heatmap(correlation, annot=True, cmap='coolwarm', linewidths=0.5) plt.title('特征相关性热图') plt.show() 

分布分析

# 单变量分布分析 plt.figure(figsize=(12, 6)) # 花萼长度分布 plt.subplot(2, 2, 1) sns.histplot(df['sepal_length'], kde=True) plt.title('花萼长度分布') # 花萼宽度分布 plt.subplot(2, 2, 2) sns.histplot(df['sepal_width'], kde=True) plt.title('花萼宽度分布') # 花瓣长度分布 plt.subplot(2, 2, 3) sns.histplot(df['petal_length'], kde=True) plt.title('花瓣长度分布') # 花瓣宽度分布 plt.subplot(2, 2, 4) sns.histplot(df['petal_width'], kde=True) plt.title('花瓣宽度分布') plt.tight_layout() plt.show() # 多变量分布分析(按物种) plt.figure(figsize=(12, 6)) # 花萼长度与宽度的关系 plt.subplot(1, 2, 1) sns.scatterplot(x='sepal_length', y='sepal_width', hue='species', data=df) plt.title('花萼长度与宽度的关系') # 花瓣长度与宽度的关系 plt.subplot(1, 2, 2) sns.scatterplot(x='petal_length', y='petal_width', hue='species', data=df) plt.title('花瓣长度与宽度的关系') plt.tight_layout() plt.show() 

案例三:时间序列数据分析

pandas提供了强大的时间序列处理功能,非常适合分析时间相关的数据。

时间序列基础操作

# 创建时间序列数据 dates = pd.date_range(start='20230101', end='20230131') values = np.random.randn(len(dates)) ts = pd.Series(values, index=dates) print("时间序列数据:") print(ts.head()) # 时间序列切片 print("n2023年1月1日至2023年1月10日的数据:") print(ts['2023-01-01':'2023-01-10']) # 重采样 - 将日数据转换为周数据 weekly_ts = ts.resample('W').mean() print("n重采样为周数据:") print(weekly_ts) # 移动窗口计算 rolling_mean = ts.rolling(window=7).mean() print("n7天移动平均:") print(rolling_mean.head(10)) 

时间序列可视化

# 创建更复杂的时间序列数据 dates = pd.date_range(start='20220101', end='20221231') values = np.sin(np.arange(len(dates)) * 0.1) + np.random.randn(len(dates)) * 0.1 ts = pd.Series(values, index=dates) # 绘制时间序列 plt.figure(figsize=(12, 6)) ts.plot() plt.title('2022年时间序列数据') plt.xlabel('日期') plt.ylabel('值') plt.grid(True) plt.show() # 绘制移动平均 plt.figure(figsize=(12, 6)) ts.plot(label='原始数据') ts.rolling(window=30).mean().plot(label='30天移动平均') ts.rolling(window=90).mean().plot(label='90天移动平均') plt.title('时间序列与移动平均') plt.xlabel('日期') plt.ylabel('值') plt.legend() plt.grid(True) plt.show() 

时间序列分解

from statsmodels.tsa.seasonal import seasonal_decompose # 创建具有趋势和季节性的时间序列 trend = np.linspace(0, 10, len(dates)) seasonality = np.sin(np.arange(len(dates)) * 0.5) noise = np.random.randn(len(dates)) * 0.2 values = trend + seasonality + noise ts = pd.Series(values, index=dates) # 分解时间序列 decomposition = seasonal_decompose(ts, model='additive', period=30) # 绘制分解结果 plt.figure(figsize=(12, 10)) plt.subplot(411) plt.plot(ts, label='原始数据') plt.legend() plt.subplot(412) plt.plot(decomposition.trend, label='趋势') plt.legend() plt.subplot(413) plt.plot(decomposition.seasonal, label='季节性') plt.legend() plt.subplot(414) plt.plot(decomposition.resid, label='残差') plt.legend() plt.tight_layout() plt.show() 

案例四:数据合并与连接

在实际数据分析中,我们经常需要从多个数据源合并数据。pandas提供了多种合并数据的方法。

concat函数

# 创建示例DataFrame df1 = pd.DataFrame({ 'ID': [1, 2, 3], 'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35] }) df2 = pd.DataFrame({ 'ID': [4, 5, 6], 'Name': ['David', 'Eva', 'Frank'], 'Age': [40, 45, 50] }) # 垂直堆叠(行方向) result_vertical = pd.concat([df1, df2], axis=0) print("垂直堆叠结果:") print(result_vertical) # 水平堆叠(列方向) df3 = pd.DataFrame({ 'Salary': [50000, 60000, 70000], 'Department': ['HR', 'IT', 'Finance'] }) result_horizontal = pd.concat([df1, df3], axis=1) print("n水平堆叠结果:") print(result_horizontal) 

merge函数

# 创建示例DataFrame df_left = pd.DataFrame({ 'ID': [1, 2, 3, 4], 'Name': ['Alice', 'Bob', 'Charlie', 'David'], 'Age': [25, 30, 35, 40] }) df_right = pd.DataFrame({ 'ID': [3, 4, 5, 6], 'Salary': [70000, 80000, 90000, 100000], 'Department': ['Finance', 'IT', 'HR', 'Marketing'] }) # 内连接(只保留两个表中都存在的ID) inner_join = pd.merge(df_left, df_right, on='ID', how='inner') print("内连接结果:") print(inner_join) # 左连接(保留左表的所有行) left_join = pd.merge(df_left, df_right, on='ID', how='left') print("n左连接结果:") print(left_join) # 右连接(保留右表的所有行) right_join = pd.merge(df_left, df_right, on='ID', how='right') print("n右连接结果:") print(right_join) # 外连接(保留两个表的所有行) outer_join = pd.merge(df_left, df_right, on='ID', how='outer') print("n外连接结果:") print(outer_join) 

join方法

# 创建示例DataFrame df1 = pd.DataFrame({ 'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35] }, index=[1, 2, 3]) df2 = pd.DataFrame({ 'Salary': [50000, 60000, 70000], 'Department': ['HR', 'IT', 'Finance'] }, index=[2, 3, 4]) # 使用join方法(基于索引) result = df1.join(df2, how='outer') print("join方法结果:") print(result) 

案例五:数据分组与聚合

数据分组与聚合是数据分析中常用的操作,可以帮助我们理解数据的分布特征。

groupby基础

# 创建示例数据 data = { 'Department': ['HR', 'IT', 'Finance', 'HR', 'IT', 'Finance', 'HR', 'IT'], 'Employee': ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Henry'], 'Salary': [50000, 80000, 90000, 55000, 85000, 95000, 52000, 88000], 'Experience': [2, 5, 7, 3, 6, 8, 4, 9] } df = pd.DataFrame(data) print("原始数据:") print(df) # 按部门分组并计算平均薪资 avg_salary_by_dept = df.groupby('Department')['Salary'].mean() print("n各部门平均薪资:") print(avg_salary_by_dept) # 按部门分组并计算多个统计量 stats_by_dept = df.groupby('Department').agg({ 'Salary': ['mean', 'min', 'max'], 'Experience': ['mean', 'min', 'max'] }) print("n各部门统计信息:") print(stats_by_dept) 

多级分组

# 创建更复杂的数据 data = { 'Department': ['HR', 'IT', 'Finance', 'HR', 'IT', 'Finance', 'HR', 'IT', 'Finance', 'HR'], 'Location': ['NY', 'NY', 'NY', 'LA', 'LA', 'LA', 'SF', 'SF', 'SF', 'NY'], 'Employee': ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Henry', 'Ivy', 'Jack'], 'Salary': [50000, 80000, 90000, 55000, 85000, 95000, 52000, 88000, 92000, 53000], 'Experience': [2, 5, 7, 3, 6, 8, 4, 9, 10, 3] } df = pd.DataFrame(data) print("原始数据:") print(df) # 按部门和位置多级分组 multi_group = df.groupby(['Department', 'Location']).mean() print("n多级分组结果:") print(multi_group) # 计算每个部门在不同位置的平均薪资 pivot_salary = df.pivot_table(values='Salary', index='Department', columns='Location', aggfunc='mean') print("n各部门在不同位置的平均薪资:") print(pivot_salary) 

自定义聚合函数

# 定义自定义聚合函数 def salary_range(s): return s.max() - s.min() # 应用自定义聚合函数 custom_agg = df.groupby('Department').agg({ 'Salary': ['mean', salary_range], 'Experience': ['mean', 'max'] }) print("自定义聚合结果:") print(custom_agg) # 使用lambda函数 lambda_agg = df.groupby('Department').agg({ 'Salary': lambda x: x.max() - x.min(), 'Experience': lambda x: x.mean() > 5 }) print("n使用lambda函数的聚合结果:") print(lambda_agg) 

案例六:数据透视表分析

数据透视表是数据分析中非常强大的工具,可以快速汇总和分析大量数据。

基本透视表

# 创建示例数据 data = { 'Date': pd.date_range(start='20230101', periods=12), 'Region': ['North', 'South', 'East', 'West'] * 3, 'Product': ['A', 'B', 'C', 'D'] * 3, 'Sales': [100, 150, 200, 250, 120, 180, 220, 270, 110, 160, 210, 260], 'Quantity': [10, 15, 20, 25, 12, 18, 22, 27, 11, 16, 21, 26] } df = pd.DataFrame(data) print("原始数据:") print(df) # 创建基本透视表 pivot1 = pd.pivot_table(df, values='Sales', index='Region', columns='Product', aggfunc='sum') print("n基本透视表(区域×产品,销售额总和):") print(pivot1) # 创建多索引透视表 pivot2 = pd.pivot_table(df, values=['Sales', 'Quantity'], index=['Region', 'Product'], aggfunc={'Sales': 'sum', 'Quantity': 'mean'}) print("n多索引透视表:") print(pivot2) 

高级透视表功能

# 添加margins参数计算总计 pivot_with_margins = pd.pivot_table(df, values='Sales', index='Region', columns='Product', aggfunc='sum', margins=True) print("带总计的透视表:") print(pivot_with_margins) # 使用fill_value参数填充缺失值 pivot_fillna = pd.pivot_table(df, values='Sales', index='Region', columns='Product', aggfunc='sum', fill_value=0) print("n填充缺失值的透视表:") print(pivot_fillna) # 使用多个聚合函数 pivot_multi_agg = pd.pivot_table(df, values='Sales', index='Region', columns='Product', aggfunc=[sum, mean, len]) print("n多聚合函数的透视表:") print(pivot_multi_agg) 

透视表可视化

# 创建更复杂的数据用于可视化 np.random.seed(42) months = pd.date_range(start='20220101', periods=24, freq='M') regions = ['North', 'South', 'East', 'West'] products = ['A', 'B', 'C', 'D'] data = [] for month in months: for region in regions: for product in products: sales = np.random.randint(100, 500) quantity = np.random.randint(10, 50) data.append([month, region, product, sales, quantity]) df = pd.DataFrame(data, columns=['Date', 'Region', 'Product', 'Sales', 'Quantity']) # 创建透视表 pivot = pd.pivot_table(df, values='Sales', index='Region', columns='Product', aggfunc='sum') # 可视化透视表 plt.figure(figsize=(10, 6)) sns.heatmap(pivot, annot=True, fmt='.0f', cmap='YlGnBu') plt.title('各区域产品销售额热图') plt.xlabel('产品') plt.ylabel('区域') plt.show() # 创建时间序列透视表 df['Month'] = df['Date'].dt.to_period('M') pivot_time = pd.pivot_table(df, values='Sales', index='Month', columns='Region', aggfunc='sum') # 可视化时间序列透视表 plt.figure(figsize=(12, 6)) pivot_time.plot(kind='line', marker='o') plt.title('各区域月度销售额趋势') plt.xlabel('月份') plt.ylabel('销售额') plt.grid(True) plt.legend(title='区域') plt.show() 

案例七:文本数据处理

pandas提供了强大的字符串处理功能,可以方便地进行文本数据清洗和分析。

基本字符串操作

# 创建包含文本数据的DataFrame data = { 'ID': [1, 2, 3, 4, 5], 'Text': ['Hello World', 'PANDAS is great', 'data analysis', 'Python Programming', ' extra spaces '], 'Email': ['john@example.com', 'JANE@EXAMPLE.COM', 'bob@test.org', 'invalid-email', 'alice@example.com'] } df = pd.DataFrame(data) print("原始数据:") print(df) # 转换为小写 df['Text_lower'] = df['Text'].str.lower() print("n转换为小写:") print(df[['Text', 'Text_lower']]) # 转换为大写 df['Text_upper'] = df['Text'].str.upper() print("n转换为大写:") print(df[['Text', 'Text_upper']]) # 去除首尾空格 df['Text_stripped'] = df['Text'].str.strip() print("n去除首尾空格:") print(df[['Text', 'Text_stripped']]) # 计算字符串长度 df['Text_length'] = df['Text'].str.len() print("n字符串长度:") print(df[['Text', 'Text_length']]) 

正则表达式应用

# 检查是否包含特定模式 df['Contains_data'] = df['Text'].str.contains('data', case=False) print("n是否包含'data':") print(df[['Text', 'Contains_data']]) # 提取特定模式 df['First_Word'] = df['Text'].str.extract(r'(bw+b)') print("n提取第一个单词:") print(df[['Text', 'First_Word']]) # 替换特定模式 df['Text_Replaced'] = df['Text'].str.replace(r'bw+ingb', 'XXXX') print("n替换以'ing'结尾的单词:") print(df[['Text', 'Text_Replaced']]) # 验证电子邮件格式 email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$' df['Valid_Email'] = df['Email'].str.match(email_pattern) print("n验证电子邮件格式:") print(df[['Email', 'Valid_Email']]) 

文本数据清洗

# 创建包含各种文本问题的DataFrame data = { 'ID': [1, 2, 3, 4, 5], 'Review': [ ' Great product! I love it. ', 'This product is OK, but not amazing...', 'Worst purchase EVER!!! So disappointed.', 'It's a decent product for the price.', 'Would NOT recommend to anyone.' ] } df = pd.DataFrame(data) print("原始数据:") print(df) # 文本清洗函数 def clean_text(text): # 转换为小写 text = text.lower() # 去除标点符号 text = text.str.replace(r'[^ws]', '') # 去除数字 text = text.str.replace(r'd+', '') # 去除多余空格 text = text.str.strip() return text # 应用清洗函数 df['Cleaned_Review'] = clean_text(df['Review']) print("n清洗后的文本:") print(df[['Review', 'Cleaned_Review']]) # 分词 df['Tokens'] = df['Cleaned_Review'].str.split() print("n分词结果:") print(df[['Cleaned_Review', 'Tokens']]) 

案例八:缺失值处理

现实世界的数据集通常包含缺失值,正确处理这些缺失值对数据分析至关重要。

缺失值检测

# 创建包含缺失值的DataFrame data = { 'ID': [1, 2, 3, 4, 5], 'Name': ['Alice', 'Bob', None, 'David', 'Eva'], 'Age': [25, None, 35, 40, None], 'Salary': [50000, 60000, None, 80000, 90000], 'Department': ['HR', 'IT', 'Finance', None, 'IT'] } df = pd.DataFrame(data) print("原始数据:") print(df) # 检测缺失值 print("n缺失值检测:") print(df.isnull()) # 计算每列的缺失值数量 print("n每列缺失值数量:") print(df.isnull().sum()) # 计算每列的缺失值比例 print("n每列缺失值比例:") print(df.isnull().mean() * 100) 

缺失值处理策略

# 删除包含缺失值的行 df_drop_rows = df.dropna() print("n删除包含缺失值的行:") print(df_drop_rows) # 删除包含缺失值的列 df_drop_cols = df.dropna(axis=1) print("n删除包含缺失值的列:") print(df_drop_cols) # 填充缺失值 - 常数值 df_fill_constant = df.copy() df_fill_constant['Name'].fillna('Unknown', inplace=True) df_fill_constant['Department'].fillna('Unknown', inplace=True) print("n使用常数值填充:") print(df_fill_constant) # 填充缺失值 - 统计量 df_fill_stats = df.copy() df_fill_stats['Age'].fillna(df_fill_stats['Age'].mean(), inplace=True) df_fill_stats['Salary'].fillna(df_fill_stats['Salary'].median(), inplace=True) print("n使用统计量填充:") print(df_fill_stats) # 前向填充和后向填充 df_ffill = df.copy() df_ffill['Age'].fillna(method='ffill', inplace=True) df_ffill['Salary'].fillna(method='bfill', inplace=True) print("n前向和后向填充:") print(df_ffill) 

高级缺失值处理

# 创建更复杂的数据集 np.random.seed(42) data = { 'A': np.random.randn(100), 'B': np.random.randn(100), 'C': np.random.randn(100), 'D': np.random.randn(100), 'E': np.random.randn(100) } df = pd.DataFrame(data) # 随机引入缺失值 for col in df.columns: df.loc[df.sample(frac=0.2).index, col] = np.nan print("随机引入缺失值后的数据:") print(df.head(10)) # 使用插值方法填充缺失值 df_interpolate = df.copy() df_interpolate['A'] = df_interpolate['A'].interpolate(method='linear') df_interpolate['B'] = df_interpolate['B'].interpolate(method='polynomial', order=2) df_interpolate['C'] = df_interpolate['C'].interpolate(method='spline', order=2) print("n使用插值方法填充后的数据:") print(df_interpolate.head(10)) # 使用KNN填充缺失值 from sklearn.impute import KNNImputer df_knn = df.copy() imputer = KNNImputer(n_neighbors=5) df_knn = pd.DataFrame(imputer.fit_transform(df_knn), columns=df_knn.columns) print("n使用KNN填充后的数据:") print(df_knn.head(10)) 

案例九:数据可视化基础

虽然pandas本身不是可视化库,但它提供了简单的绘图功能,可以快速进行数据可视化。

基本绘图功能

# 创建示例数据 np.random.seed(42) dates = pd.date_range(start='20230101', periods=100) values = np.cumsum(np.random.randn(100)) ts = pd.Series(values, index=dates) # 绘制线图 ts.plot(figsize=(12, 6), title='随机游走时间序列') plt.xlabel('日期') plt.ylabel('值') plt.grid(True) plt.show() # 创建DataFrame df = pd.DataFrame({ 'A': np.random.randn(100).cumsum(), 'B': np.random.randn(100).cumsum(), 'C': np.random.randn(100).cumsum() }, index=dates) # 绘制多列线图 df.plot(figsize=(12, 6), title='多列时间序列') plt.xlabel('日期') plt.ylabel('值') plt.grid(True) plt.show() 

不同类型的图表

# 创建示例数据 np.random.seed(42) data = { 'Category': ['A', 'B', 'C', 'D', 'E'], 'Value1': np.random.randint(10, 100, 5), 'Value2': np.random.randint(10, 100, 5) } df = pd.DataFrame(data) # 条形图 df.plot(x='Category', y='Value1', kind='bar', figsize=(10, 6), title='条形图') plt.xlabel('类别') plt.ylabel('值') plt.grid(True, axis='y') plt.show() # 水平条形图 df.plot(x='Category', y='Value1', kind='barh', figsize=(10, 6), title='水平条形图') plt.xlabel('值') plt.ylabel('类别') plt.grid(True, axis='x') plt.show() # 堆叠条形图 df.plot(x='Category', y=['Value1', 'Value2'], kind='bar', stacked=True, figsize=(10, 6), title='堆叠条形图') plt.xlabel('类别') plt.ylabel('值') plt.grid(True, axis='y') plt.show() # 饼图 df.set_index('Category')['Value1'].plot(kind='pie', figsize=(8, 8), autopct='%1.1f%%', title='饼图') plt.ylabel('') plt.show() # 散点图 np.random.seed(42) scatter_df = pd.DataFrame({ 'X': np.random.randn(100), 'Y': np.random.randn(100) }) scatter_df.plot(x='X', y='Y', kind='scatter', figsize=(10, 6), title='散点图') plt.xlabel('X值') plt.ylabel('Y值') plt.grid(True) plt.show() # 箱线图 box_df = pd.DataFrame({ 'A': np.random.normal(0, 1, 100), 'B': np.random.normal(1, 2, 100), 'C': np.random.normal(-1, 1.5, 100) }) box_df.plot(kind='box', figsize=(10, 6), title='箱线图') plt.ylabel('值') plt.grid(True, axis='y') plt.show() 

高级可视化技巧

# 创建时间序列数据 np.random.seed(42) dates = pd.date_range(start='20220101', periods=365) values = np.sin(np.arange(365) * 2 * np.pi / 30) + np.random.randn(365) * 0.2 ts = pd.Series(values, index=dates) # 创建移动平均 ma7 = ts.rolling(window=7).mean() ma30 = ts.rolling(window=30).mean() # 绘制时间序列和移动平均 plt.figure(figsize=(12, 6)) ts.plot(label='原始数据') ma7.plot(label='7天移动平均') ma30.plot(label='30天移动平均') plt.title('时间序列与移动平均') plt.xlabel('日期') plt.ylabel('值') plt.legend() plt.grid(True) plt.show() # 创建多个子图 fig, axes = plt.subplots(2, 2, figsize=(15, 10)) # 第一个子图 - 直方图 df['Value1'].plot(kind='hist', ax=axes[0, 0], bins=20, alpha=0.7) axes[0, 0].set_title('Value1的分布') axes[0, 0].set_xlabel('值') axes[0, 0].set_ylabel('频数') axes[0, 0].grid(True, axis='y') # 第二个子图 - 密度图 df['Value1'].plot(kind='density', ax=axes[0, 1]) axes[0, 1].set_title('Value1的密度估计') axes[0, 1].set_xlabel('值') axes[0, 1].set_ylabel('密度') axes[0, 1].grid(True, axis='y') # 第三个子图 - 面积图 df[['Value1', 'Value2']].plot(kind='area', ax=axes[1, 0], stacked=False, alpha=0.5) axes[1, 0].set_title('Value1和Value2的面积图') axes[1, 0].set_xlabel('索引') axes[1, 0].set_ylabel('值') axes[1, 0].grid(True, axis='y') # 第四个子图 - 散点矩阵 pd.plotting.scatter_matrix(df[['Value1', 'Value2']], ax=axes[1, 1], alpha=0.7, diagonal='kde') axes[1, 1].set_title('Value1和Value2的散点矩阵') plt.tight_layout() plt.show() 

案例十:大规模数据处理技巧

当处理大规模数据集时,内存和性能成为关键问题。pandas提供了多种技巧来优化大规模数据处理。

内存优化

# 创建大型DataFrame np.random.seed(42) n_rows = 1000000 data = { 'ID': range(1, n_rows + 1), 'Value1': np.random.randn(n_rows), 'Value2': np.random.randn(n_rows), 'Category': np.random.choice(['A', 'B', 'C', 'D', 'E'], n_rows), 'Date': pd.date_range(start='20200101', periods=n_rows) } df = pd.DataFrame(data) # 检查内存使用情况 print("原始DataFrame的内存使用:") print(df.memory_usage(deep=True)) # 优化数据类型以减少内存使用 df_optimized = df.copy() # 将整数列转换为最小可能的整数类型 df_optimized['ID'] = pd.to_numeric(df_optimized['ID'], downcast='integer') # 将浮点数列转换为最小可能的浮点数类型 df_optimized['Value1'] = pd.to_numeric(df_optimized['Value1'], downcast='float') df_optimized['Value2'] = pd.to_numeric(df_optimized['Value2'], downcast='float') # 将字符串列转换为category类型 df_optimized['Category'] = df_optimized['Category'].astype('category') print("n优化后的DataFrame内存使用:") print(df_optimized.memory_usage(deep=True)) # 比较内存使用 original_memory = df.memory_usage(deep=True).sum() optimized_memory = df_optimized.memory_usage(deep=True).sum() reduction = (1 - optimized_memory / original_memory) * 100 print(f"n原始内存使用: {original_memory / 1024**2:.2f} MB") print(f"优化后内存使用: {optimized_memory / 1024**2:.2f} MB") print(f"内存减少: {reduction:.2f}%") 

分块处理

# 创建一个非常大的CSV文件(模拟) import os large_file_path = 'large_data.csv' chunk_size = 100000 # 生成大型CSV文件 if not os.path.exists(large_file_path): print("生成大型CSV文件...") chunks = [] for i in range(10): # 创建10个块,每个块100,000行 chunk = pd.DataFrame({ 'ID': range(i * chunk_size, (i + 1) * chunk_size), 'Value': np.random.randn(chunk_size), 'Category': np.random.choice(['A', 'B', 'C', 'D'], chunk_size) }) chunks.append(chunk) # 将所有块合并并写入文件 pd.concat(chunks).to_csv(large_file_path, index=False) print("大型CSV文件生成完成。") # 使用分块读取和处理大型文件 print("n使用分块处理大型文件:") chunk_iter = pd.read_csv(large_file_path, chunksize=chunk_size) results = [] for i, chunk in enumerate(chunk_iter): print(f"处理第 {i+1} 个块...") # 对每个块进行处理 result = chunk.groupby('Category')['Value'].mean() results.append(result) # 合并所有块的结果 final_result = pd.concat(results).groupby(level=0).mean() print("n最终结果:") print(final_result) 

使用Dask处理超大规模数据

# 注意:运行此部分需要安装dask库 # pip install dask[dataframe] try: import dask.dataframe as dd # 创建Dask DataFrame ddf = dd.from_pandas(df, npartitions=10) # 执行计算 print("n使用Dask处理数据:") result = ddf.groupby('Category').Value.mean().compute() print(result) # 比较pandas和dask的执行时间 import time # pandas执行时间 start_time = time.time() pandas_result = df.groupby('Category')['Value1'].mean() pandas_time = time.time() - start_time # dask执行时间 start_time = time.time() dask_result = ddf.groupby('Category').Value1.mean().compute() dask_time = time.time() - start_time print(f"nPandas执行时间: {pandas_time:.4f} 秒") print(f"Dask执行时间: {dask_time:.4f} 秒") except ImportError: print("nDask未安装。跳过Dask示例。") 

并行处理

from multiprocessing import Pool, cpu_count # 定义一个处理函数 def process_chunk(chunk): return chunk.groupby('Category')['Value1'].mean() # 将DataFrame分成多个块 n_cores = cpu_count() chunks = np.array_split(df, n_cores) # 使用多进程并行处理 print(f"n使用 {n_cores} 个CPU核心并行处理:") start_time = time.time() with Pool(n_cores) as pool: results = pool.map(process_chunk, chunks) # 合并结果 final_result = pd.concat(results).groupby(level=0).mean() parallel_time = time.time() - start_time print("并行处理结果:") print(final_result) print(f"并行处理时间: {parallel_time:.4f} 秒") # 比较串行和并行处理时间 start_time = time.time() serial_result = df.groupby('Category')['Value1'].mean() serial_time = time.time() - start_time print(f"n串行处理时间: {serial_time:.4f} 秒") print(f"并行处理时间: {parallel_time:.4f} 秒") print(f"加速比: {serial_time / parallel_time:.2f}x") 

总结与进阶学习建议

通过这十个经典应用案例,我们深入了解了pandas在数据分析中的强大功能。从数据清洗、探索性分析到时间序列处理、数据合并与连接,再到分组聚合、透视表分析、文本处理、缺失值处理、数据可视化和大规模数据处理,pandas提供了全面的工具集来应对各种数据分析挑战。

进阶学习建议

  1. 深入学习pandas内部机制:了解pandas的内部数据结构和算法原理,这将帮助你更好地理解其性能特性。

  2. 掌握高级索引技术:学习多级索引、布尔索引和位置索引的高级用法,提高数据选择和筛选的效率。

  3. 结合其他数据分析库:学习如何将pandas与NumPy、SciPy、scikit-learn、statsmodels等库结合使用,构建完整的数据分析流程。

  4. 学习性能优化技巧:掌握向量化操作、避免循环、使用适当的数据类型等技巧,提高代码执行效率。

  5. 探索pandas扩展库:了解如pandas-profiling、swifter、modin等扩展库,扩展pandas的功能。

  6. 实践真实数据集:在Kaggle、UCI机器学习仓库等平台寻找真实数据集进行练习,将所学知识应用到实际问题中。

  7. 参与开源项目:参与pandas或相关项目的开源贡献,与社区交流学习。

pandas是一个功能强大且不断发展的库,持续学习和实践是掌握它的关键。希望本指南能帮助你提升数据处理能力,在数据分析的道路上取得更大进步。