【零基础学AI】第5讲:Pandas数据处理
本节课你将学到
- 掌握Pandas的核心数据结构Series和DataFrame
- 学会数据的读取、查看和基本操作
- 掌握数据清洗和预处理技巧
- 学会数据分组、聚合和透视表操作
- 完成销售数据分析实战项目
开始之前
什么是Pandas?
Pandas(Panel Data Analysis)是基于NumPy构建的数据分析库。如果说:
- NumPy:是高效的数值计算工具,像计算器
- Pandas:是强大的数据分析平台,像Excel的超级加强版
Pandas专门用于处理结构化数据,提供了:
- 高效的数据结构:Series(一维)和DataFrame(二维)
- 灵活的数据操作:选择、过滤、分组、聚合
- 强大的IO功能:读写CSV、Excel、JSON、SQL等格式
- 数据清洗工具:处理缺失值、重复数据、异常值
为什么Pandas在AI中如此重要?
1. 数据预处理
机器学习有句话:“垃圾进,垃圾出”。Pandas帮你把原始数据变成干净的、可用的数据。
2. 探索性数据分析
在建模之前,需要理解数据的分布、关系、异常等,Pandas提供了强大的分析工具。
3. 特征工程
将原始数据转换为机器学习算法能够使用的特征,这是AI项目成功的关键。
4. 数据整合
现实中的数据往往来自多个源头,Pandas可以轻松合并、连接不同的数据集。
环境要求
- 已完成前四讲的环境配置
- Pandas已安装(在第1讲中已安装)
- Matplotlib用于数据可视化
Pandas核心数据结构
导入Pandas
# 标准导入方式
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt# 查看Pandas版本
print(f"Pandas版本: {pd.__version__}")# 设置显示选项
pd.set_option('display.max_columns', None) # 显示所有列
pd.set_option('display.max_rows', 10) # 最多显示10行
pd.set_option('display.width', None) # 不限制显示宽度
pd.set_option('display.precision', 2) # 小数精度print("✅ Pandas环境配置完成")
Series:一维数据结构
# Series基础操作
print("📊 Series基础操作")
print("=" * 30)# 创建Series的多种方式
# 方式1:从列表创建
scores = pd.Series([85, 92, 78, 96, 88])
print("从列表创建的Series:")
print(scores)
print(f"数据类型: {scores.dtype}")
print(f"形状: {scores.shape}")# 方式2:从字典创建(带标签)
student_scores = pd.Series({'Alice': 85,'Bob': 92, 'Charlie': 78,'Diana': 96,'Eve': 88
})
print(f"\n从字典创建的Series:")
print(student_scores)# 方式3:从NumPy数组创建
dates = pd.date_range('2024-01-01', periods=5, freq='D')
temperatures = pd.Series(np.random.normal(20, 5, 5), index=dates)
print(f"\n温度数据Series:")
print(temperatures)# Series的基本属性
print(f"\n📋 Series属性:")
print(f" 值 (values): {student_scores.values}")
print(f" 索引 (index): {student_scores.index.tolist()}")
print(f" 大小 (size): {student_scores.size}")
print(f" 形状 (shape): {student_scores.shape}")
print(f" 是否为空 (empty): {student_scores.empty}")# Series的基本操作
print(f"\n🔧 Series基本操作:")
print(f" 最高分: {student_scores.max()}")
print(f" 最低分: {student_scores.min()}")
print(f" 平均分: {student_scores.mean():.2f}")
print(f" 中位数: {student_scores.median()}")
print(f" 标准差: {student_scores.std():.2f}")# 访问元素
print(f"\n🎯 元素访问:")
print(f" Alice的分数: {student_scores['Alice']}")
print(f" 前三名学生: \n{student_scores.head(3)}")
print(f" 分数大于90的学生: \n{student_scores[student_scores > 90]}")
DataFrame:二维数据结构
# DataFrame基础操作
print("\n📋 DataFrame基础操作")
print("=" * 35)# 创建DataFrame的多种方式
# 方式1:从字典创建
student_data = {'Name': ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve'],'Age': [20, 21, 19, 22, 20],'Math': [85, 92, 78, 96, 88],'English': [88, 85, 82, 94, 90],'Science': [92, 88, 85, 98, 86]
}df_students = pd.DataFrame(student_data)
print("学生成绩DataFrame:")
print(df_students)# 方式2:从NumPy数组创建
np.random.seed(42) # 确保结果可重现
sales_data = np.random.randint(1000, 5000, (6, 4))
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
products = ['Product_A', 'Product_B', 'Product_C', 'Product_D']df_sales = pd.DataFrame(sales_data, index=months, columns=products)
print(f"\n销售数据DataFrame:")
print(df_sales)# DataFrame的基本属性
print(f"\n📊 DataFrame属性:")
print(f" 形状 (shape): {df_students.shape}")
print(f" 行数 (rows): {df_students.shape[0]}")
print(f" 列数 (columns): {df_students.shape[1]}")
print(f" 列名 (columns): {df_students.columns.tolist()}")
print(f" 索引 (index): {df_students.index.tolist()}")
print(f" 数据类型 (dtypes):")
print(df_students.dtypes)# DataFrame信息概览
print(f"\n🔍 DataFrame信息概览:")
print(df_students.info())# 基本统计信息
print(f"\n📈 基本统计信息:")
print(df_students.describe())
数据选择和索引
基本选择操作
# DataFrame数据选择
print("🎯 DataFrame数据选择")
print("=" * 30)# 创建示例数据
sales_data = {'Date': pd.date_range('2024-01-01', periods=10, freq='D'),'Product': ['A', 'B', 'A', 'C', 'B', 'A', 'C', 'B', 'A', 'C'],'Sales': [1200, 1500, 1100, 1800, 1600, 1300, 1900, 1400, 1250, 2000],'Quantity': [12, 15, 11, 18, 16, 13, 19, 14, 12, 20],'Price': [100, 100, 100, 100, 100, 100, 100, 100, 104, 100]
}df = pd.DataFrame(sales_data)
print("销售数据:")
print(df)# 列选择
print(f"\n📋 列选择:")
print("选择单列 - Sales:")
print(df['Sales'])print(f"\n选择多列 - Product和Sales:")
selected_cols = df[['Product', 'Sales']]
print(selected_cols)# 行选择
print(f"\n📏 行选择:")
print("前3行:")
print(df.head(3))print(f"\n最后3行:")
print(df.tail(3))print(f"\n第2到第5行 (iloc):")
print(df.iloc[1:5])print(f"\n根据索引选择 (loc):")
print(df.loc[2:4]) # 包含结束索引# 条件选择
print(f"\n🎯 条件选择:")
high_sales = df[df['Sales'] > 1500]
print("销售额大于1500的记录:")
print(high_sales)print(f"\n多条件选择:")
product_a_high = df[(df['Product'] == 'A') & (df['Sales'] > 1200)]
print("产品A且销售额大于1200:")
print(product_a_high)# 使用query方法
print(f"\n🔍 使用query方法:")
query_result = df.query('Product == "B" and Sales > 1400')
print("使用query选择产品B且销售额大于1400:")
print(query_result)
高级索引操作
# 设置索引和多级索引
print(f"\n🏗️ 高级索引操作")
print("=" * 25)# 设置Date为索引
df_indexed = df.set_index('Date')
print("以日期为索引:")
print(df_indexed.head())# 重置索引
df_reset = df_indexed.reset_index()
print(f"\n重置索引:")
print(df_reset.head())# 创建多级索引
multi_index_data = {'Sales': [1200, 1500, 1100, 1800, 1600, 1300],'Quantity': [12, 15, 11, 18, 16, 13]
}# 创建多级索引
index = pd.MultiIndex.from_tuples([('2024-01', 'A'), ('2024-01', 'B'), ('2024-01', 'C'),('2024-02', 'A'), ('2024-02', 'B'), ('2024-02', 'C')
], names=['Month', 'Product'])df_multi = pd.DataFrame(multi_index_data, index=index)
print(f"\n多级索引DataFrame:")
print(df_multi)# 多级索引选择
print(f"\n多级索引选择:")
print("2024-01月的数据:")
print(df_multi.loc['2024-01'])print(f"\n所有产品A的数据:")
print(df_multi.loc[pd.IndexSlice[:, 'A'], :])
数据清洗和预处理
处理缺失值
# 创建包含缺失值的数据
print("🧹 数据清洗和预处理")
print("=" * 30)# 创建包含缺失值的数据
dirty_data = {'Name': ['Alice', 'Bob', 'Charlie', None, 'Eve', 'Frank'],'Age': [25, 30, None, 28, 35, 32],'Salary': [50000, None, 60000, 55000, None, 65000],'Department': ['IT', 'HR', 'IT', 'Finance', 'HR', None]
}df_dirty = pd.DataFrame(dirty_data)
print("包含缺失值的数据:")
print(df_dirty)# 检查缺失值
print(f"\n🔍 缺失值检查:")
print("每列缺失值数量:")
print(df_dirty.isnull().sum())print(f"\n缺失值百分比:")
missing_percent = (df_dirty.isnull().sum() / len(df_dirty)) * 100
print(missing_percent)print(f"\n是否存在缺失值:")
print(df_dirty.isnull().any())# 处理缺失值的策略
print(f"\n🛠️ 处理缺失值:")# 策略1:删除包含缺失值的行
df_dropped_rows = df_dirty.dropna()
print("删除包含缺失值的行:")
print(df_dropped_rows)# 策略2:删除包含缺失值的列
df_dropped_cols = df_dirty.dropna(axis=1)
print(f"\n删除包含缺失值的列:")
print(df_dropped_cols)# 策略3:填充缺失值
df_filled = df_dirty.copy()# 用均值填充数值列
df_filled['Age'].fillna(df_filled['Age'].mean(), inplace=True)
df_filled['Salary'].fillna(df_filled['Salary'].median(), inplace=True)# 用众数填充分类列
df_filled['Name'].fillna('Unknown', inplace=True)
df_filled['Department'].fillna(df_filled['Department'].mode()[0], inplace=True)print(f"\n填充缺失值后:")
print(df_filled)# 策略4:前向填充和后向填充
df_ffill = df_dirty.fillna(method='ffill') # 前向填充
df_bfill = df_dirty.fillna(method='bfill') # 后向填充print(f"\n前向填充:")
print(df_ffill)
处理重复数据
# 处理重复数据
print(f"\n🔄 处理重复数据:")# 创建包含重复数据的DataFrame
duplicate_data = {'ID': [1, 2, 3, 2, 4, 3, 5],'Name': ['Alice', 'Bob', 'Charlie', 'Bob', 'Diana', 'Charlie', 'Eve'],'Score': [85, 92, 78, 92, 96, 78, 88]
}df_dup = pd.DataFrame(duplicate_data)
print("包含重复数据:")
print(df_dup)# 检查重复数据
print(f"\n检查重复数据:")
print("是否有重复行:")
print(df_dup.duplicated())print(f"\n重复行数量: {df_dup.duplicated().sum()}")# 删除重复数据
df_no_dup = df_dup.drop_duplicates()
print(f"\n删除重复数据后:")
print(df_no_dup)# 基于特定列删除重复
df_no_dup_name = df_dup.drop_duplicates(subset=['Name'])
print(f"\n基于Name列删除重复:")
print(df_no_dup_name)# 保留最后一个重复项
df_keep_last = df_dup.drop_duplicates(keep='last')
print(f"\n保留最后一个重复项:")
print(df_keep_last)
数据类型转换
# 数据类型转换
print(f"\n🔧 数据类型转换:")# 创建混合数据类型的DataFrame
mixed_data = {'ID': ['001', '002', '003', '004'],'Price': ['99.99', '150.50', '200.00', '75.25'],'Date': ['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04'],'Category': [1, 2, 1, 3]
}df_mixed = pd.DataFrame(mixed_data)
print("原始数据类型:")
print(df_mixed.dtypes)
print(df_mixed)# 转换数据类型
print(f"\n转换数据类型:")# 转换为数值类型
df_mixed['ID'] = pd.to_numeric(df_mixed['ID'])
df_mixed['Price'] = pd.to_numeric(df_mixed['Price'])# 转换为日期类型
df_mixed['Date'] = pd.to_datetime(df_mixed['Date'])# 转换为分类类型
df_mixed['Category'] = df_mixed['Category'].astype('category')print("转换后的数据类型:")
print(df_mixed.dtypes)
print(df_mixed)# 使用astype批量转换
type_dict = {'ID': 'int64','Price': 'float64'
}df_converted = df_mixed.astype(type_dict)
print(f"\n使用astype转换:")
print(df_converted.dtypes)
数据分组和聚合
GroupBy操作
# 创建销售数据用于分组分析
print(f"\n📊 数据分组和聚合")
print("=" * 30)# 创建更复杂的销售数据
np.random.seed(42)
sales_records = []products = ['Laptop', 'Phone', 'Tablet', 'Watch']
regions = ['North', 'South', 'East', 'West']
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']for month in months:for product in products:for region in regions:sales = np.random.randint(1000, 5000)quantity = np.random.randint(10, 50)sales_records.append({'Month': month,'Product': product,'Region': region,'Sales': sales,'Quantity': quantity})df_sales = pd.DataFrame(sales_records)
print("销售数据:")
print(df_sales.head(10))
print(f"数据形状: {df_sales.shape}")# 基本分组操作
print(f"\n🔍 基本分组操作:")# 按产品分组
product_group = df_sales.groupby('Product')
print("按产品分组的销售总额:")
product_sales = product_group['Sales'].sum().sort_values(ascending=False)
print(product_sales)# 按地区分组
region_group = df_sales.groupby('Region')
print(f"\n按地区分组的平均销售额:")
region_avg = region_group['Sales'].mean().sort_values(ascending=False)
print(region_avg)# 多列分组
print(f"\n🔄 多列分组:")
multi_group = df_sales.groupby(['Product', 'Region'])
multi_sales = multi_group['Sales'].sum()
print("按产品和地区分组的销售总额:")
print(multi_sales.head(10))# 多种聚合函数
print(f"\n📈 多种聚合函数:")
agg_result = df_sales.groupby('Product').agg({'Sales': ['sum', 'mean', 'max', 'min', 'count'],'Quantity': ['sum', 'mean']
})
print("多种聚合统计:")
print(agg_result)# 自定义聚合函数
print(f"\n🛠️ 自定义聚合函数:")
def sales_range(series):return series.max() - series.min()custom_agg = df_sales.groupby('Product')['Sales'].agg(['mean',('sales_range', sales_range),('coefficient_of_variation', lambda x: x.std() / x.mean())
])
print("自定义聚合:")
print(custom_agg)
透视表
# 透视表操作
print(f"\n📋 透视表操作:")# 创建简单透视表
pivot_simple = df_sales.pivot_table(values='Sales',index='Product',columns='Region',aggfunc='sum'
)
print("产品-地区销售透视表:")
print(pivot_simple)# 多值透视表
pivot_multi = df_sales.pivot_table(values=['Sales', 'Quantity'],index='Product',columns='Region',aggfunc='mean'
)
print(f"\n多值透视表:")
print(pivot_multi)# 带有总计的透视表
pivot_with_totals = df_sales.pivot_table(values='Sales',index='Product',columns='Region',aggfunc='sum',margins=True,margins_name='总计'
)
print(f"\n带总计的透视表:")
print(pivot_with_totals)# 多层索引透视表
pivot_multi_index = df_sales.pivot_table(values='Sales',index=['Product', 'Month'],columns='Region',aggfunc='sum',fill_value=0
)
print(f"\n多层索引透视表:")
print(pivot_multi_index.head(10))
数据合并和连接
合并DataFrame
# DataFrame合并操作
print(f"\n🔗 DataFrame合并操作")
print("=" * 35)# 创建示例数据
customers = pd.DataFrame({'CustomerID': [1, 2, 3, 4, 5],'Name': ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve'],'City': ['New York', 'London', 'Tokyo', 'Paris', 'Sydney']
})orders = pd.DataFrame({'OrderID': [101, 102, 103, 104, 105, 106],'CustomerID': [1, 2, 2, 3, 4, 6],'Product': ['Laptop', 'Phone', 'Tablet', 'Watch', 'Laptop', 'Phone'],'Amount': [1200, 800, 500, 300, 1200, 800]
})print("客户表:")
print(customers)
print(f"\n订单表:")
print(orders)# 内连接(默认)
print(f"\n🔄 内连接 (inner join):")
inner_join = pd.merge(customers, orders, on='CustomerID')
print(inner_join)# 左连接
print(f"\n⬅️ 左连接 (left join):")
left_join = pd.merge(customers, orders, on='CustomerID', how='left')
print(left_join)# 右连接
print(f"\n➡️ 右连接 (right join):")
right_join = pd.merge(customers, orders, on='CustomerID', how='right')
print(right_join)# 外连接
print(f"\n🔄 外连接 (outer join):")
outer_join = pd.merge(customers, orders, on='CustomerID', how='outer')
print(outer_join)# 基于索引合并
print(f"\n📋 基于索引合并:")
customers_indexed = customers.set_index('CustomerID')
orders_indexed = orders.set_index('CustomerID')index_join = pd.merge(customers_indexed, orders_indexed, left_index=True, right_index=True, how='inner')
print(index_join)
数据拼接
# 数据拼接操作
print(f"\n📎 数据拼接操作:")# 垂直拼接
q1_sales = pd.DataFrame({'Product': ['A', 'B', 'C'],'Q1_Sales': [1000, 1500, 1200]
})q2_sales = pd.DataFrame({'Product': ['A', 'B', 'C'],'Q2_Sales': [1100, 1600, 1300]
})print("Q1销售数据:")
print(q1_sales)
print(f"\nQ2销售数据:")
print(q2_sales)# 水平拼接
horizontal_concat = pd.concat([q1_sales, q2_sales], axis=1)
print(f"\n水平拼接:")
print(horizontal_concat)# 垂直拼接
sales_2023 = pd.DataFrame({'Product': ['A', 'B', 'C'],'Sales': [1000, 1500, 1200],'Year': [2023, 2023, 2023]
})sales_2024 = pd.DataFrame({'Product': ['A', 'B', 'C'],'Sales': [1100, 1600, 1300],'Year': [2024, 2024, 2024]
})vertical_concat = pd.concat([sales_2023, sales_2024], axis=0, ignore_index=True)
print(f"\n垂直拼接:")
print(vertical_concat)
完整项目:销售数据分析
让我们创建一个完整的销售数据分析项目:
# sales_analyzer.py - 销售数据分析项目
"""
使用Pandas进行销售数据分析
演示Pandas在业务数据分析中的应用
"""import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedeltaclass SalesAnalyzer:"""销售数据分析器"""def __init__(self):"""初始化分析器"""self.raw_data = Noneself.cleaned_data = Noneprint("📊 销售数据分析器初始化完成")def generate_sample_data(self, n_records=1000):"""生成示例销售数据参数:n_records: 生成记录数量"""print(f"🎲 生成 {n_records} 条销售记录...")np.random.seed(42) # 确保结果可重现# 基础数据products = ['iPhone', 'Samsung Galaxy', 'iPad', 'MacBook', 'Surface', 'AirPods']categories = ['Phone', 'Phone', 'Tablet', 'Laptop', 'Laptop', 'Audio']regions = ['North', 'South', 'East', 'West', 'Central']sales_reps = ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry']# 生成日期范围(过去一年)start_date = datetime.now() - timedelta(days=365)date_range = [start_date + timedelta(days=x) for x in range(365)]records = []for _ in range(n_records):# 随机选择基础信息product = np.random.choice(products)category = categories[products.index(product)]region = np.random.choice(regions)sales_rep = np.random.choice(sales_reps)date = np.random.choice(date_range)# 根据产品类型生成不同的价格范围if category == 'Phone':unit_price = np.random.normal(800, 200)elif category == 'Tablet':unit_price = np.random.normal(500, 150)elif category == 'Laptop':unit_price = np.random.normal(1200, 300)else: # Audiounit_price = np.random.normal(200, 50)# 确保价格为正数unit_price = max(unit_price, 100)# 生成销售数量(考虑季节性)month = date.monthseasonal_factor = 1 + 0.3 * np.sin(2 * np.pi * month / 12) # 年末销售旺季base_quantity = np.random.poisson(3) + 1 # 基础数量1-10quantity = int(base_quantity * seasonal_factor)# 计算总金额total_amount = unit_price * quantity# 添加一些随机的折扣discount_rate = np.random.choice([0, 0.05, 0.1, 0.15], p=[0.6, 0.2, 0.15, 0.05])final_amount = total_amount * (1 - discount_rate)records.append({'Date': date,'Product': product,'Category': category,'Region': region,'SalesRep': sales_rep,'Quantity': quantity,'UnitPrice': round(unit_price, 2),'TotalAmount': round(total_amount, 2),'DiscountRate': discount_rate,'FinalAmount': round(final_amount, 2)})self.raw_data = pd.DataFrame(records)print(f"✅ 数据生成完成,共 {len(self.raw_data)} 条记录")return self.raw_datadef clean_data(self):"""清洗数据"""print("🧹 开始数据清洗...")if self.raw_data is None:print("❌ 请先生成或加载数据")returnself.cleaned_data = self.raw_data.copy()print(f"📋 原始数据信息:")print(f" 数据形状: {self.cleaned_data.shape}")print(f" 缺失值检查:")missing_info = self.cleaned_data.isnull().sum()print(missing_info[missing_info > 0] if missing_info.sum() > 0 else " 无缺失值")# 数据类型优化print(f"\n🔧 数据类型优化:")# 转换日期类型self.cleaned_data['Date'] = pd.to_datetime(self.cleaned_data['Date'])# 创建派生字段self.cleaned_data['Year'] = self.cleaned_data['Date'].dt.yearself.cleaned_data['Month'] = self.cleaned_data['Date'].dt.monthself.cleaned_data['Quarter'] = self.cleaned_data['Date'].dt.quarterself.cleaned_data['Weekday'] = self.cleaned_data['Date'].dt.day_name()self.cleaned_data['IsWeekend'] = self.cleaned_data['Date'].dt.weekday >= 5# 分类数据优化categorical_columns = ['Product', 'Category', 'Region', 'SalesRep', 'Weekday']for col in categorical_columns:self.cleaned_data[col] = self.cleaned_data[col].astype('category')# 数据验证print(f"\n✅ 数据清洗完成:")print(f" 清洗后数据形状: {self.cleaned_data.shape}")print(f" 数据类型优化完成")print(f" 新增派生字段: Year, Month, Quarter, Weekday, IsWeekend")return self.cleaned_datadef basic_analysis(self):"""基础数据分析"""print("\n📊 基础数据分析")print("=" * 30)if self.cleaned_data is None:self.clean_data()df = self.cleaned_data# 总体概览print("🔍 总体概览:")print(f" 分析期间: {df['Date'].min().strftime('%Y-%m-%d')} 至 {df['Date'].max().strftime('%Y-%m-%d')}")print(f" 总销售记录: {len(df):,} 条")print(f" 总销售额: ${df['FinalAmount'].sum():,.2f}")print(f" 平均订单金额: ${df['FinalAmount'].mean():.2f}")print(f" 总销售数量: {df['Quantity'].sum():,} 件")# 产品分析print(f"\n📱 产品分析:")product_stats = df.groupby('Product').agg({'FinalAmount': ['sum', 'mean', 'count'],'Quantity': 'sum'}).round(2)# 扁平化列名product_stats.columns = ['总销售额', '平均订单额', '订单数', '总数量']product_stats = product_stats.sort_values('总销售额', ascending=False)print(product_stats)# 地区分析print(f"\n🌍 地区分析:")region_stats = df.groupby('Region').agg({'FinalAmount': ['sum', 'mean'],'Quantity': 'sum'}).round(2)region_stats.columns = ['总销售额', '平均订单额', '总数量']region_stats = region_stats.sort_values('总销售额', ascending=False)print(region_stats)# 销售代表分析print(f"\n👥 销售代表分析:")rep_stats = df.groupby('SalesRep').agg({'FinalAmount': ['sum', 'count'],'Quantity': 'sum'}).round(2)rep_stats.columns = ['总销售额', '订单数', '总数量']rep_stats['平均订单额'] = rep_stats['总销售额'] / rep_stats['订单数']rep_stats = rep_stats.sort_values('总销售额', ascending=False)print(rep_stats)return {'product_stats': product_stats,'region_stats': region_stats,'rep_stats': rep_stats}def time_series_analysis(self):"""时间序列分析"""print(f"\n📅 时间序列分析")print("=" * 25)df = self.cleaned_data# 月度销售趋势monthly_sales = df.groupby([df['Date'].dt.to_period('M')]).agg({'FinalAmount': 'sum','Quantity': 'sum','Date': 'count' # 订单数}).round(2)monthly_sales.columns = ['月度销售额', '月度销量', '月度订单数']monthly_sales.index = monthly_sales.index.astype(str)print("📈 月度销售趋势:")print(monthly_sales)# 季度分析quarterly_sales = df.groupby('Quarter').agg({'FinalAmount': ['sum', 'mean'],'Quantity': 'sum'}).round(2)quarterly_sales.columns = ['总销售额', '平均订单额', '总数量']print(f"\n📊 季度销售分析:")print(quarterly_sales)# 工作日vs周末分析weekend_analysis = df.groupby('IsWeekend').agg({'FinalAmount': ['sum', 'mean', 'count'],'Quantity': 'sum'}).round(2)weekend_analysis.columns = ['总销售额', '平均订单额', '订单数', '总数量']weekend_analysis.index = ['工作日', '周末']print(f"\n📅 工作日vs周末分析:")print(weekend_analysis)return {'monthly_sales': monthly_sales,'quarterly_sales': quarterly_sales,'weekend_analysis': weekend_analysis}def advanced_analysis(self):"""高级分析"""print(f"\n🔬 高级分析")print("=" * 20)df = self.cleaned_data# 客户价值分析(基于销售代表作为代理)print("💎 销售代表价值分析:")rep_value = df.groupby('SalesRep').agg({'FinalAmount': ['sum', 'count', 'mean'],'DiscountRate': 'mean'}).round(3)rep_value.columns = ['总销售额', '订单数', '平均订单额', '平均折扣率']# 计算销售效率指标rep_value['销售效率'] = rep_value['总销售额'] / rep_value['订单数']rep_value = rep_value.sort_values('总销售额', ascending=False)print(rep_value)# 产品组合分析print(f"\n📦 产品组合分析:")product_mix = df.groupby(['Category', 'Product']).agg({'FinalAmount': 'sum','Quantity': 'sum'}).round(2)product_mix.columns = ['销售额', '销量']# 计算各产品在类别中的占比category_totals = product_mix.groupby('Category')['销售额'].sum()product_mix['类别占比%'] = (product_mix['销售额'] / product_mix.groupby('Category')['销售额'].transform('sum') * 100).round(1)print(product_mix.sort_values('销售额', ascending=False))# 地区-产品交叉分析print(f"\n🗺️ 地区-产品交叉分析:")region_product = pd.crosstab(df['Region'], df['Category'], values=df['FinalAmount'], aggfunc='sum').round(2)print(region_product)# 折扣影响分析print(f"\n💰 折扣影响分析:")discount_analysis = df.groupby('DiscountRate').agg({'FinalAmount': ['sum', 'count', 'mean'],'Quantity': 'mean'}).round(2)discount_analysis.columns = ['总销售额', '订单数', '平均订单额', '平均数量']print(discount_analysis)return {'rep_value': rep_value,'product_mix': product_mix,'region_product': region_product,'discount_analysis': discount_analysis}def create_visualizations(self):"""创建可视化图表"""print(f"\n📊 创建可视化图表")print("=" * 25)df = self.cleaned_data# 设置中文字体plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']plt.rcParams['axes.unicode_minus'] = False# 创建子图fig, axes = plt.subplots(2, 3, figsize=(20, 12))fig.suptitle('销售数据分析仪表板', fontsize=16, fontweight='bold')# 1. 产品销售额对比product_sales = df.groupby('Product')['FinalAmount'].sum().sort_values(ascending=False)axes[0, 0].bar(range(len(product_sales)), product_sales.values, color='skyblue')axes[0, 0].set_title('各产品销售额对比')axes[0, 0].set_xlabel('产品')axes[0, 0].set_ylabel('销售额')axes[0, 0].set_xticks(range(len(product_sales)))axes[0, 0].set_xticklabels(product_sales.index, rotation=45)# 添加数值标签for i, v in enumerate(product_sales.values):axes[0, 0].text(i, v, f'${v:,.0f}', ha='center', va='bottom')# 2. 月度销售趋势monthly_data = df.groupby(df['Date'].dt.to_period('M'))['FinalAmount'].sum()axes[0, 1].plot(range(len(monthly_data)), monthly_data.values, marker='o', linewidth=2)axes[0, 1].set_title('月度销售趋势')axes[0, 1].set_xlabel('月份')axes[0, 1].set_ylabel('销售额')axes[0, 1].set_xticks(range(0, len(monthly_data), 2))axes[0, 1].set_xticklabels([str(monthly_data.index[i]) for i in range(0, len(monthly_data), 2)], rotation=45)axes[0, 1].grid(True, alpha=0.3)# 3. 地区销售分布饼图region_sales = df.groupby('Region')['FinalAmount'].sum()axes[0, 2].pie(region_sales.values, labels=region_sales.index, autopct='%1.1f%%', startangle=90)axes[0, 2].set_title('各地区销售分布')# 4. 产品类别销量对比category_quantity = df.groupby('Category')['Quantity'].sum().sort_values(ascending=True)axes[1, 0].barh(range(len(category_quantity)), category_quantity.values, color='lightgreen')axes[1, 0].set_title('各类别销量对比')axes[1, 0].set_xlabel('销量')axes[1, 0].set_ylabel('产品类别')axes[1, 0].set_yticks(range(len(category_quantity)))axes[1, 0].set_yticklabels(category_quantity.index)# 5. 销售代表业绩对比rep_performance = df.groupby('SalesRep')['FinalAmount'].sum().sort_values(ascending=False)axes[1, 1].bar(range(len(rep_performance)), rep_performance.values, color='orange')axes[1, 1].set_title('销售代表业绩对比')axes[1, 1].set_xlabel('销售代表')axes[1, 1].set_ylabel('销售额')axes[1, 1].set_xticks(range(len(rep_performance)))axes[1, 1].set_xticklabels(rep_performance.index, rotation=45)# 6. 折扣率vs平均订单额散点图discount_data = df.groupby('DiscountRate').agg({'FinalAmount': 'mean','Date': 'count'}).reset_index()scatter = axes[1, 2].scatter(discount_data['DiscountRate'] * 100, discount_data['FinalAmount'],s=discount_data['Date'] * 10, # 点的大小表示订单数alpha=0.6, color='red')axes[1, 2].set_title('折扣率 vs 平均订单额')axes[1, 2].set_xlabel('折扣率 (%)')axes[1, 2].set_ylabel('平均订单额')axes[1, 2].grid(True, alpha=0.3)plt.tight_layout()plt.show()print("✅ 可视化图表创建完成")def generate_report(self):"""生成分析报告"""print(f"\n📄 生成分析报告")print("=" * 25)# 执行所有分析basic_stats = self.basic_analysis()time_stats = self.time_series_analysis()advanced_stats = self.advanced_analysis()df = self.cleaned_data# 生成总结报告report = f"""
销售数据分析报告
{'='*50}📊 总体概览
- 分析期间: {df['Date'].min().strftime('%Y-%m-%d')} 至 {df['Date'].max().strftime('%Y-%m-%d')}
- 总销售额: ${df['FinalAmount'].sum():,.2f}
- 总订单数: {len(df):,} 笔
- 平均订单金额: ${df['FinalAmount'].mean():.2f}
- 总销售数量: {df['Quantity'].sum():,} 件🏆 关键发现
1. 最佳销售产品: {basic_stats['product_stats'].index[0]}销售额: ${basic_stats['product_stats'].iloc[0]['总销售额']:,.2f}2. 最佳销售地区: {basic_stats['region_stats'].index[0]}销售额: ${basic_stats['region_stats'].iloc[0]['总销售额']:,.2f}3. 最佳销售代表: {basic_stats['rep_stats'].index[0]}销售额: ${basic_stats['rep_stats'].iloc[0]['总销售额']:,.2f}📈 趋势分析
- 最高销售月份: {time_stats['monthly_sales']['月度销售额'].idxmax()}
- 最高月销售额: ${time_stats['monthly_sales']['月度销售额'].max():,.2f}
- 最佳销售季度: Q{time_stats['quarterly_sales']['总销售额'].idxmax()}💡 业务建议
1. 重点推广销售表现最好的产品和地区
2. 学习最佳销售代表的销售策略
3. 在销售旺季加大营销投入
4. 优化折扣策略以提高利润率📊 数据质量
- 数据完整性: {((len(df) - df.isnull().sum().sum()) / (len(df) * len(df.columns)) * 100):.1f}%
- 数据记录数: {len(df):,} 条
- 分析维度: {len(df.columns)} 个字段"""print(report)return reportdef demo_sales_analysis():"""销售数据分析完整演示"""print("🚀 销售数据分析完整演示")print("=" * 50)# 创建分析器实例analyzer = SalesAnalyzer()# 生成示例数据analyzer.generate_sample_data(1500)# 数据清洗analyzer.clean_data()# 显示数据概览print(f"\n📋 数据概览:")print(analyzer.cleaned_data.head())print(f"\n数据信息:")print(analyzer.cleaned_data.info())# 执行分析并生成报告report = analyzer.generate_report()# 创建可视化analyzer.create_visualizations()print(f"\n🎉 销售数据分析演示完成!")if __name__ == "__main__":demo_sales_analysis()
Pandas性能优化技巧
高效的数据操作
# Pandas性能优化技巧
print("⚡ Pandas性能优化技巧")
print("=" * 30)# 创建大型数据集进行性能测试
import timeprint("创建测试数据...")
n_rows = 100000
test_data = pd.DataFrame({'A': np.random.randint(1, 100, n_rows),'B': np.random.random(n_rows),'C': np.random.choice(['X', 'Y', 'Z'], n_rows),'D': pd.date_range('2020-01-01', periods=n_rows, freq='H')
})print(f"测试数据大小: {test_data.shape}")# 技巧1:使用向量化操作而不是循环
print(f"\n💡 技巧1: 向量化操作 vs 循环")# 慢速方法:使用循环
start_time = time.time()
result_slow = []
for idx, row in test_data.iterrows():result_slow.append(row['A'] * row['B'])
loop_time = time.time() - start_time# 快速方法:向量化操作
start_time = time.time()
result_fast = test_data['A'] * test_data['B']
vector_time = time.time() - start_timeprint(f" 循环方法耗时: {loop_time:.4f} 秒")
print(f" 向量化耗时: {vector_time:.4f} 秒")
print(f" 性能提升: {loop_time/vector_time:.1f} 倍")# 技巧2:使用分类数据类型
print(f"\n💡 技巧2: 分类数据类型优化")# 内存使用对比
memory_before = test_data.memory_usage(deep=True).sum()
test_data_optimized = test_data.copy()
test_data_optimized['C'] = test_data_optimized['C'].astype('category')
memory_after = test_data_optimized.memory_usage(deep=True).sum()print(f" 优化前内存: {memory_before / 1024 / 1024:.2f} MB")
print(f" 优化后内存: {memory_after / 1024 / 1024:.2f} MB")
print(f" 内存节省: {(1 - memory_after/memory_before)*100:.1f}%")# 技巧3:使用query方法进行高效筛选
print(f"\n💡 技巧3: 高效筛选")# 传统方法
start_time = time.time()
result1 = test_data[(test_data['A'] > 50) & (test_data['C'] == 'X')]
traditional_time = time.time() - start_time# query方法
start_time = time.time()
result2 = test_data.query('A > 50 and C == "X"')
query_time = time.time() - start_timeprint(f" 传统筛选耗时: {traditional_time:.4f} 秒")
print(f" query方法耗时: {query_time:.4f} 秒")
print(f" 结果一致性: {result1.equals(result2)}")
内存管理
# 内存管理技巧
print(f"\n💾 内存管理技巧:")# 技巧4:分块处理大文件
def process_large_file_in_chunks(filename, chunk_size=10000):"""分块处理大文件"""total_rows = 0total_sum = 0# 模拟读取大文件print(f" 分块处理大文件(块大小: {chunk_size})")for chunk in pd.read_csv(filename, chunksize=chunk_size):# 处理每个数据块total_rows += len(chunk)total_sum += chunk['value'].sum() # 假设有value列return total_rows, total_sum# 技巧5:使用适当的数据类型
print(f"\n💡 技巧5: 数据类型优化")# 创建示例数据
large_df = pd.DataFrame({'int_col': np.random.randint(0, 100, 50000),'float_col': np.random.random(50000),'str_col': np.random.choice(['A', 'B', 'C'], 50000)
})print(f" 原始内存使用:")
print(large_df.memory_usage(deep=True))# 优化数据类型
large_df_optimized = large_df.copy()
large_df_optimized['int_col'] = large_df_optimized['int_col'].astype('int8') # 0-100范围内用int8足够
large_df_optimized['str_col'] = large_df_optimized['str_col'].astype('category')print(f"\n 优化后内存使用:")
print(large_df_optimized.memory_usage(deep=True))
常见问题和解决方案
问题1:处理大数据集
# 处理大数据集的策略
print(f"\n🚨 常见问题解决方案")
print("=" * 35)print("问题1: 处理大数据集")
print("解决方案:")
print(" 1. 使用chunksize参数分块读取")
print(" 2. 选择性读取列:usecols参数")
print(" 3. 优化数据类型")
print(" 4. 使用Dask等分布式计算框架")# 示例:选择性读取
print(f"\n 示例:选择性读取大文件")
# df = pd.read_csv('large_file.csv',
# usecols=['col1', 'col2'],
# dtype={'col1': 'category'},
# chunksize=10000)
问题2:处理时间数据
# 时间数据处理
print(f"\n问题2: 时间数据处理")# 创建时间数据示例
time_data = pd.DataFrame({'date_str': ['2024-01-01', '2024-01-02', '2024-01-03'],'timestamp': pd.date_range('2024-01-01', periods=3, freq='D'),'value': [100, 200, 150]
})print("原始数据:")
print(time_data)
print(f"数据类型:")
print(time_data.dtypes)# 转换字符串为日期
time_data['date_converted'] = pd.to_datetime(time_data['date_str'])# 提取时间组件
time_data['year'] = time_data['timestamp'].dt.year
time_data['month'] = time_data['timestamp'].dt.month
time_data['weekday'] = time_data['timestamp'].dt.day_name()print(f"\n处理后数据:")
print(time_data)
问题3:处理编码问题
# 编码问题处理
print(f"\n问题3: 文件编码问题")
print("解决方案:")
print(" 1. 指定正确的编码:encoding='utf-8'")
print(" 2. 尝试不同编码:'gbk', 'latin-1'")
print(" 3. 自动检测编码:使用chardet库")# 示例
# df = pd.read_csv('file.csv', encoding='utf-8')
# df = pd.read_csv('file.csv', encoding='gbk') # 中文Windows系统常用
学习总结
通过本节课的学习,你已经掌握了:
✅ Pandas核心概念
- 理解了Pandas在数据分析中的重要地位
- 掌握了Series和DataFrame的创建和基本操作
- 学会了数据的选择、索引和切片
✅ 数据清洗技能
- 熟练处理缺失值、重复数据、异常值
- 掌握了数据类型转换和优化
- 学会了数据验证和质量检查
✅ 数据分析方法
- 掌握了分组聚合和透视表操作
- 学会了数据合并和连接
- 熟练使用各种统计函数
✅ 实际应用技能
- 完成了完整的销售数据分析项目
- 掌握了时间序列数据处理
- 学会了创建数据分析报告
✅ 性能优化
- 了解了向量化操作的重要性
- 掌握了内存优化技巧
- 学会了处理大数据集的策略
下节课预告
第6讲我们将学习数据可视化基础,使用Matplotlib创建各种图表:
- Matplotlib的基本概念和架构
- 创建线图、柱状图、散点图、饼图等
- 图表美化和自定义设置
- 子图和复杂布局
- 销售趋势图表实战项目
数据可视化是数据分析的重要环节,好的图表能让数据说话!
恭喜完成第5讲!
你已经掌握了Pandas这个数据分析的利器。Pandas强大的数据处理能力将让你在面对各种数据分析任务时游刃有余。现在你可以高效地清洗数据、分析数据,为机器学习做好数据准备!