引言:为什么Python是数据分析的首选工具

在当今数据驱动的世界中,Python已经成为数据分析领域的绝对王者。根据2023年Kaggle开发者调查,超过90%的数据科学家将Python作为主要编程语言。Python之所以如此受欢迎,是因为它拥有丰富的库生态系统、简洁的语法以及强大的社区支持。

想象一下,你是一家电商公司的数据分析师,每天需要处理数百万条用户行为数据。使用Python,你可以轻松地从数据库中提取数据、清洗脏数据、进行复杂的统计分析,并生成直观的可视化图表。这一切都可以在同一个环境中完成,无需在多个工具之间切换。

Python在数据分析中的优势主要体现在以下几个方面:

  • 易学性:即使是编程新手也能快速上手
  • 丰富的库:Pandas、NumPy、Matplotlib等库提供了强大的功能
  • 可扩展性:可以处理从几KB到几TB的数据
  • 集成性:可以与机器学习、深度学习框架无缝对接

基础篇:搭建Python数据分析环境

1. 安装和配置

要开始Python数据分析之旅,首先需要搭建合适的开发环境。推荐使用Anaconda发行版,它预装了所有必要的库和工具。

# 下载并安装Anaconda
# 访问 https://www.anaconda.com/products/distribution 下载适合你操作系统的版本

# 安装完成后,打开终端或命令提示符,创建新的conda环境
conda create -n data_analysis python=3.9

# 激活新环境
conda activate data_analysis

# 安装核心数据分析库
conda install pandas numpy matplotlib seaborn scikit-learn

2. Jupyter Notebook入门

Jupyter Notebook是数据分析师的瑞士军刀,它允许你以交互式的方式编写和运行代码。

# 创建你的第一个Jupyter Notebook
# 在终端输入以下命令启动Jupyter
jupyter notebook

# 在Notebook中尝试以下代码
import pandas as pd
import numpy as np

# 创建一个简单的DataFrame
data = {
    '姓名': ['张三', '李四', '王五'],
    '年龄': [25, 30, 35],
    '薪资': [8000, 12000, 15000]
}

df = pd.DataFrame(data)
print(df)

输出结果:

   姓名  年龄   薪资
0  张三  25   8000
1  李四  30  12000
2  王五  35  15000

核心篇:Pandas数据处理实战

1. 数据读取与写入

Pandas支持多种数据格式的读写操作,这是数据分析的第一步。

import pandas as pd

# 读取CSV文件
df_csv = pd.read_csv('sales_data.csv')

# 读取Excel文件
df_excel = pd.read_excel('customer_info.xlsx', sheet_name='Sheet1')

# 读取SQL数据库(需要安装sqlalchemy)
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://username:password@localhost/dbname')
df_sql = pd.read_sql('SELECT * FROM orders', engine)

# 将数据写入不同格式
df_csv.to_csv('processed_data.csv', index=False)
df_excel.to_excel('report.xlsx', sheet_name='Summary')

2. 数据清洗与预处理

真实世界的数据往往是脏乱的,数据清洗是分析前的必要步骤。

# 示例:处理销售数据中的常见问题
import pandas as pd
import numpy as np

# 创建包含问题的示例数据
data = {
    '订单ID': [1, 2, 3, 4, 5, 6],
    '产品名称': ['手机', '电脑', '平板', '手机', '电脑', None],
    '销售日期': ['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-01', '2023-01-02', '2023-01-03'],
    '销售额': [2999, 5999, 1999, 2999, 5999, 999],
    '客户地区': ['北京', '上海', '广州', '北京', None, '深圳']
}

df = pd.DataFrame(data)

# 1. 处理缺失值
print("原始数据:")
print(df)

# 检查缺失值
print("\n缺失值统计:")
print(df.isnull().sum())

# 填充缺失值
df['产品名称'].fillna('未知产品', inplace=True)
df['客户地区'].fillna('未知地区', inplace=True)

# 2. 处理重复值
df = df.drop_duplicates()

# 3. 数据类型转换
df['销售日期'] = pd.to_datetime(df['销售日期'])

# 4. 异常值处理(使用IQR方法)
Q1 = df['销售额'].quantile(0.25)
Q3 = df['销售额'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 过滤异常值
df = df[(df['销售额'] >= lower_bound) & (df['销售额'] <= upper_bound)]

print("\n清洗后的数据:")
print(df)

3. 数据筛选与查询

Pandas提供了强大的数据筛选功能,类似于SQL查询。

# 继续使用上面的df

# 基本筛选
high_sales = df[df['销售额'] > 3000]  # 销售额大于3000的记录

# 多条件筛选
beijing_high = df[(df['客户地区'] == '北京') & (df['销售额'] > 2500)]

# 使用query方法
result = df.query('销售额 > 2500 and 客户地区 in ["北京", "上海"]')

# 使用isin进行集合筛选
regions = ['北京', '上海']
regional_sales = df[df['客户地区'].isin(regions)]

# 字符串筛选
phone_sales = df[df['产品名称'].str.contains('手机')]

# 日期筛选(假设df['销售日期']已经是datetime类型)
january_sales = df[df['销售日期'].dt.month == 1]

4. 数据分组与聚合

分组聚合是数据分析中最常用的操作之一。

# 创建更复杂的销售数据示例
np.random.seed(42)
dates = pd.date_range('2023-01-01', '2023-12-31', freq='D')
products = ['手机', '电脑', '平板', '耳机']
regions = ['北京', '上海', '广州', '深圳', '杭州']

data = {
    '日期': np.random.choice(dates, 500),
    '产品': np.random.choice(products, 500),
    '地区': np.random.choice(regions, 500),
    '销售额': np.random.randint(1000, 10000, 500),
    '数量': np.random.randint(1, 10, 500)
}
sales_df = pd.DataFrame(data)

# 1. 基本分组聚合
# 按产品分组,计算每个产品的总销售额和平均销售额
product_stats = sales_df.groupby('产品').agg({
    '销售额': ['sum', 'mean', 'count'],
    '数量': 'sum'
}).round(2)

print("按产品分组统计:")
print(product_stats)

# 2. 多级分组
# 按地区和产品分组
region_product_stats = sales_df.groupby(['地区', '产品']).agg({
    '销售额': 'sum',
    '数量': 'mean'
}).round(2)

print("\n按地区和产品分组统计:")
print(region_product_stats)

# 3. 使用transform进行分组填充
# 计算每个产品的平均销售额,并填充到每行
sales_df['产品平均销售额'] = sales_df.groupby('产品')['销售额'].transform('mean')

# 4. 使用apply进行复杂分组操作
def top_n_products(group, n=3):
    return group.nlargest(n, '销售额')

top_products = sales_df.groupby('地区').apply(top_n_products, n=2)
print("\n各地区销售额前2名的产品:")
print(top_products)

进阶篇:数据可视化与探索性分析

1. Matplotlib基础绘图

Matplotlib是Python最基础的绘图库,提供了丰富的绘图功能。

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# 创建示例数据
np.random.seed(42)
dates = pd.date_range('2023-01-01', periods=12, freq='M')
sales = np.random.randint(50000, 150000, 12)
profit = sales * np.random.uniform(0.1, 0.3, 12)

monthly_data = pd.DataFrame({
    '月份': dates,
    '销售额': sales,
    '利润': profit
})

# 1. 基本折线图
plt.figure(figsize=(12, 6))
plt.plot(monthly_data['月份'], monthly_data['销售额'], 
         marker='o', linewidth=2, label='销售额')
plt.plot(monthly_data['月份'], monthly_data['利润'], 
         marker='s', linewidth=2, label='利润')

plt.title('2023年月度销售与利润趋势', fontsize=16, fontweight='bold')
plt.xlabel('月份', fontsize=12)
plt.ylabel('金额(元)', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

# 2. 柱状图
plt.figure(figsize=(10, 6))
products = ['手机', '电脑', '平板', '耳机']
product_sales = [450000, 380000, 250000, 180000]

bars = plt.bar(products, product_sales, color=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4'])
plt.title('2023年各产品销售额', fontsize=16, fontweight='bold')
plt.xlabel('产品', fontsize=12)
plt.ylabel('销售额(元)', fontsize=12)

# 在柱子上显示数值
for bar in bars:
    height = bar.get_height()
    plt.text(bar.get_x() + bar.get_width()/2., height,
             f'{height:,}', ha='center', va='bottom', fontsize=11)

plt.tight_layout()
plt.show()

# 3. 散点图(探索相关性)
plt.figure(figsize=(8, 6))
np.random.seed(42)
x = np.random.normal(100, 15, 100)  # 广告投入
y = x * 1.2 + np.random.normal(0, 10, 100)  # 销售额(正相关)

plt.scatter(x, y, alpha=0.6, color='#3498db', s=50)
plt.title('广告投入 vs 销售额', fontsize=16, fontweight='bold')
plt.xlabel('广告投入(万元)', fontsize=12)
plt.ylabel('销售额(万元)', fontsize=12)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

2. Seaborn高级可视化

Seaborn基于Matplotlib,提供了更美观的统计图形。

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# 设置Seaborn样式
sns.set_style("whitegrid")

# 创建示例数据
np.random.seed(42)
data = {
    '年龄': np.random.randint(20, 60, 200),
    '薪资': np.random.normal(15000, 5000, 200),
    '部门': np.random.choice(['技术', '销售', '市场', '人事'], 200),
    '绩效评分': np.random.uniform(3, 5, 200)
}
df = pd.DataFrame(data)

# 1. 箱线图(显示分布和异常值)
plt.figure(figsize=(10, 6))
sns.boxplot(x='部门', y='薪资', data=df, palette='Set2')
plt.title('各部门薪资分布', fontsize=16, fontweight='bold')
plt.xlabel('部门', fontsize=12)
plt.ylabel('薪资(元)', fontsize=12)
plt.tight_layout()
plt.show()

# 2. 小提琴图(结合箱线图和核密度估计)
plt.figure(figsize=(10, 6))
sns.violinplot(x='部门', y='绩效评分', data=df, palette='Set3', inner='quartile')
plt.title('各部门绩效评分分布', fontsize=16, fontweight='bold')
plt.xlabel('部门', fontsize=12)
plt.ylabel('绩效评分', fontsize=12)
plt.tight_layout()
plt.show()

# 3. 热力图(相关性矩阵)
plt.figure(figsize=(8, 6))
correlation_matrix = df[['年龄', '薪资', '绩效评分']].corr()
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0,
            square=True, linewidths=0.5, cbar_kws={"shrink": 0.8})
plt.title('变量相关性热力图', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()

# 4. Pairplot(多变量关系)
# 注意:这个图会显示所有数值变量之间的两两关系
# sns.pairplot(df, hue='部门', palette='husl')
# plt.show()

高级篇:时间序列分析

1. 时间序列基础操作

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 创建时间序列数据
np.random.seed(42)
dates = pd.date_range('2020-01-01', '2023-12-31', freq='D')
values = np.random.normal(100, 15, len(dates)).cumsum()  # 随机游走

ts = pd.Series(values, index=dates)
print("时间序列前5行:")
print(ts.head())

# 1. 重采样(Resampling)
# 将日数据转换为月数据
monthly_mean = ts.resample('M').mean()
monthly_sum = ts.resample('M').sum()

print("\n月度平均值:")
print(monthly_mean.head())

# 2. 滚动窗口计算
rolling_7d = ts.rolling(window='7D').mean()  # 7天移动平均
rolling_30d = ts.rolling(window='30D').mean()  # 30天移动平均

# 3. 时间序列分解
from statsmodels.tsa.seasonal import seasonal_decompose

# 创建具有趋势和季节性的数据
np.random.seed(42)
dates = pd.date_range('2020-01-01', periods=365, freq='D')
trend = np.linspace(100, 200, 365)
seasonal = 20 * np.sin(2 * np.pi * np.arange(365) / 30)  # 30天周期
noise = np.random.normal(0, 5, 365)
values = trend + seasonal + noise

ts_decompose = pd.Series(values, index=dates)

# 进行分解(假设是月度数据)
decomposition = seasonal_decompose(ts_decompose, model='additive', period=30)

# 绘制分解结果
fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, figsize=(12, 10))
ts_decompose.plot(ax=ax1, title='原始数据')
decomposition.trend.plot(ax=ax2, title='趋势')
decomposition.seasonal.plot(ax=ax3, title='季节性')
decomposition.resid.plot(ax=ax4, title='残差')
plt.tight_layout()
plt.show()

2. 时间序列预测基础

from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.stattools import acf, pacf
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

# 使用之前创建的时间序列数据
# 注意:实际应用中需要确保数据是平稳的

# 1. 绘制ACF和PACF图确定ARIMA参数
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))
plot_acf(ts_decompose, ax=ax1, lags=40)
plot_pacf(ts_decompose, ax=ax2, lags=40)
plt.tight_layout()
plt.show()

# 2. ARIMA模型预测
# 分割数据
train_size = int(len(ts_decompose) * 0.8)
train, test = ts_decompose[:train_size], ts_decompose[train_size:]

# 拟合ARIMA模型(参数需要根据ACF/PACF图确定)
model = ARIMA(train, order=(2, 1, 2))  # (p, d, q)
results = model.fit()

print("\nARIMA模型摘要:")
print(results.summary())

# 预测
forecast = results.forecast(steps=len(test))
forecast_index = test.index

# 绘制结果
plt.figure(figsize=(12, 6))
plt.plot(train.index, train, label='训练数据', color='blue')
plt.plot(test.index, test, label='实际数据', color='green')
plt.plot(forecast_index, forecast, label='预测数据', color='red', linestyle='--')
plt.title('ARIMA模型预测结果', fontsize=16, fontweight='bold')
plt.xlabel('日期', fontsize=12)
plt.ylabel('数值', fontsize=12)
plt.legend()
plt.tight_layout()
plt.show()

实战篇:电商销售数据分析完整案例

1. 数据加载与初步探索

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta

# 创建模拟的电商销售数据
np.random.seed(42)
n_orders = 1000

# 生成订单数据
order_data = {
    '订单ID': [f'ORD{i:05d}' for i in range(1, n_orders + 1)],
    '客户ID': np.random.randint(1000, 2000, n_orders),
    '产品ID': np.random.choice(['P001', 'P002', 'P003', 'P004', 'P005'], n_orders),
    '下单时间': [datetime(2023, 1, 1) + timedelta(days=np.random.randint(0, 365),
                                               hours=np.random.randint(0, 24),
                                               minutes=np.random.randint(0, 60))
                for _ in range(n_orders)],
    '数量': np.random.randint(1, 5, n_orders),
    '单价': np.random.choice([299, 499, 799, 999, 1299], n_orders),
    '客户地区': np.random.choice(['北京', '上海', '广州', '深圳', '杭州', '成都'], n_orders),
    '支付方式': np.random.choice(['支付宝', '微信支付', '信用卡', '储蓄卡'], n_orders)
}

orders = pd.DataFrame(order_data)

# 计算订单金额
orders['订单金额'] = orders['数量'] * orders['单价']

# 添加产品类别信息
product_categories = {
    'P001': '手机',
    'P002': '电脑',
    'P003': '平板',
    'P004': '耳机',
    'P005': '配件'
}
orders['产品类别'] = orders['产品ID'].map(product_categories)

print("数据概览:")
print(orders.head())
print(f"\n数据形状:{orders.shape}")
print(f"\n数据类型:\n{orders.dtypes}")

2. 数据清洗与特征工程

# 1. 检查缺失值
print("缺失值统计:")
print(orders.isnull().sum())

# 2. 检查重复值
print(f"\n重复订单数:{orders.duplicated(subset=['订单ID']).sum()}")

# 3. 数据类型转换
orders['下单时间'] = pd.to_datetime(orders['下单时间'])

# 4. 特征工程
# 提取时间特征
orders['下单日期'] = orders['下单时间'].dt.date
orders['下单月份'] = orders['下单时间'].dt.month
orders['下单星期'] = orders['下单时间'].dt.dayofweek  # 0=周一, 6=周日
orders['下单小时'] = orders['下单时间'].dt.hour

# 计算折扣(模拟)
np.random.seed(42)
orders['折扣率'] = np.random.uniform(0.8, 1.0, len(orders))
orders['实际支付金额'] = (orders['订单金额'] * orders['折扣率']).round(2)

# 计算利润(假设成本是售价的60%)
orders['成本'] = (orders['单价'] * 0.6 * orders['数量']).round(2)
orders['利润'] = (orders['实际支付金额'] - orders['成本']).round(2)

print("\n添加特征后的数据:")
print(orders[['订单ID', '下单月份', '下单星期', '折扣率', '实际支付金额', '利润']].head())

3. 多维度分析

# 1. 整体销售情况分析
print("=== 整体销售情况 ===")
total_sales = orders['实际支付金额'].sum()
total_profit = orders['利润'].sum()
avg_order_value = orders['实际支付金额'].mean()
total_orders = len(orders)

print(f"总销售额:{total_sales:,.2f} 元")
print(f"总利润:{total_profit:,.2f} 元")
print(f"平均订单金额:{avg_order_value:,.2f} 元")
print(f"总订单数:{total_orders}")

# 2. 按月份分析销售趋势
monthly_sales = orders.groupby('下单月份').agg({
    '实际支付金额': 'sum',
    '利润': 'sum',
    '订单ID': 'count'
}).round(2)

monthly_sales.columns = ['销售额', '利润', '订单数']
print("\n=== 月度销售情况 ===")
print(monthly_sales)

# 3. 按产品类别分析
category_analysis = orders.groupby('产品类别').agg({
    '实际支付金额': ['sum', 'mean'],
    '利润': 'sum',
    '数量': 'sum',
    '订单ID': 'count'
}).round(2)

category_analysis.columns = ['销售额', '平均订单金额', '总利润', '总销量', '订单数']
category_analysis = category_analysis.sort_values('销售额', ascending=False)
print("\n=== 产品类别分析 ===")
print(category_analysis)

# 4. 按地区分析
region_analysis = orders.groupby('客户地区').agg({
    '实际支付金额': 'sum',
    '利润': 'sum',
    '订单ID': 'count'
}).round(2)

region_analysis.columns = ['销售额', '利润', '订单数']
region_analysis = region_analysis.sort_values('销售额', ascending=False)
print("\n=== 地区分析 ===")
print(region_analysis)

# 5. 支付方式分析
payment_analysis = orders.groupby('支付方式').agg({
    '实际支付金额': 'sum',
    '订单ID': 'count'
}).round(2)

payment_analysis.columns = ['销售额', '订单数']
payment_analysis = payment_analysis.sort_values('销售额', ascending=False)
print("\n=== 支付方式分析 ===")
print(payment_analysis)

4. 可视化分析

# 设置中文字体(根据系统调整)
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

# 1. 月度销售趋势图
plt.figure(figsize=(12, 6))
plt.plot(monthly_sales.index, monthly_sales['销售额'], 
         marker='o', linewidth=2, color='#2E86AB', label='销售额')
plt.plot(monthly_sales.index, monthly_sales['利润'], 
         marker='s', linewidth=2, color='#A23B72', label='利润')

plt.title('2023年月度销售与利润趋势', fontsize=16, fontweight='bold')
plt.xlabel('月份', fontsize=12)
plt.ylabel('金额(元)', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3)
plt.xticks(range(1, 13))
plt.tight_layout()
plt.show()

# 2. 产品类别销售占比
plt.figure(figsize=(10, 8))
category_sales = category_analysis['销售额']
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']
plt.pie(category_sales.values, labels=category_sales.index, 
        autopct='%1.1f%%', colors=colors, startangle=90)
plt.title('各产品类别销售额占比', fontsize=16, fontweight='bold')
plt.axis('equal')
plt.tight_layout()
plt.show()

# 3. 地区销售对比
plt.figure(figsize=(10, 6))
bars = plt.bar(region_analysis.index, region_analysis['销售额'], 
               color=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7', '#FFA07A'])
plt.title('各地区销售额对比', fontsize=16, fontweight='bold')
plt.xlabel('地区', fontsize=12)
plt.ylabel('销售额(元)', fontsize=12)
plt.xticks(rotation=45)

# 在柱子上显示数值
for bar in bars:
    height = bar.get_height()
    plt.text(bar.get_x() + bar.get_width()/2., height,
             f'{height:,.0f}', ha='center', va='bottom', fontsize=10)

plt.tight_layout()
plt.show()

# 4. 小时销售热力图
hourly_sales = orders.groupby(['下单星期', '下单小时'])['实际支付金额'].sum().unstack()
plt.figure(figsize=(12, 6))
sns.heatmap(hourly_sales, cmap='YlOrRd', annot=False, fmt='.0f')
plt.title('星期-小时销售热力图', fontsize=16, fontweight='bold')
plt.xlabel('小时', fontsize=12)
plt.ylabel('星期(0=周一)', fontsize=12)
plt.tight_layout()
plt.show()

5. 高级分析:RFM模型

# RFM模型分析(最近购买时间、购买频率、消费金额)
from datetime import datetime

# 计算参考日期(假设今天是2024-01-01)
reference_date = datetime(2024, 1, 1)

# 计算每个客户的RFM指标
rfm = orders.groupby('客户ID').agg({
    '下单时间': lambda x: (reference_date - x.max()).days,  # Recency
    '订单ID': 'count',  # Frequency
    '实际支付金额': 'sum'  # Monetary
}).round(2)

rfm.columns = ['Recency', 'Frequency', 'Monetary']

# RFM评分(1-5分)
rfm['R_Score'] = pd.qcut(rfm['Recency'], 5, labels=[5, 4, 3, 2, 1])  # 越小越好
rfm['F_Score'] = pd.qcut(rfm['Frequency'].rank(method='first'), 5, labels=[1, 2, 3, 4, 5])
rfm['M_Score'] = pd.qcut(rfm['Monetary'], 5, labels=[1, 2, 3, 4, 5])

# 合并RFM分数
rfm['RFM_Score'] = rfm['R_Score'].astype(str) + rfm['F_Score'].astype(str) + rfm['M_Score'].astype(str)

# 客户分群
def segment_customer(row):
    score = int(row['RFM_Score'])
    if score >= 555:
        return 'VIP客户'
    elif score >= 444:
        return '高价值客户'
    elif score >= 333:
        return '潜力客户'
    elif score >= 222:
        return '一般客户'
    else:
        return '流失风险客户'

rfm['客户分群'] = rfm.apply(segment_customer, axis=1)

print("\n=== RFM模型分析结果 ===")
print(rfm.head(10))

# 客户分群统计
print("\n客户分群统计:")
print(rfm['客户分群'].value_counts())

# 各分群的平均值
print("\n各分群平均值:")
print(rfm.groupby('客户分群')[['Recency', 'Frequency', 'Monetary']].mean().round(2))

6. 预测分析:销售预测

from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

# 准备数据:按天汇总销售
daily_sales = orders.groupby('下单日期').agg({
    '实际支付金额': 'sum',
    '订单ID': 'count'
}).reset_index()

daily_sales.columns = ['日期', '销售额', '订单数']

# 添加时间特征
daily_sales['日期'] = pd.to_datetime(daily_sales['日期'])
daily_sales['星期'] = daily_sales['日期'].dt.dayofweek
daily_sales['月份'] = daily_sales['日期'].dt.month
daily_sales['是否周末'] = daily_sales['星期'].isin([5, 6]).astype(int)

# 添加滞后特征(前1天、前7天的销售额)
daily_sales['lag_1'] = daily_sales['销售额'].shift(1)
daily_sales['lag_7'] = daily_sales['销售额'].shift(7)

# 移除包含NaN的行
daily_sales = daily_sales.dropna()

# 准备特征和目标变量
features = ['星期', '月份', '是否周末', 'lag_1', 'lag_7']
X = daily_sales[features]
y = daily_sales['销售额']

# 分割数据
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 训练随机森林模型
rf_model = RandomForestRegressor(n_estimators=100, random_state=42)
rf_model.fit(X_train, y_train)

# 预测
y_pred = rf_model.predict(X_test)

# 评估模型
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)

print("\n=== 销售预测模型评估 ===")
print(f"平均绝对误差(MAE):{mae:,.2f}")
print(f"均方误差(MSE):{mse:,.2f}")
print(f"R²分数:{r2:.4f}")

# 特征重要性
feature_importance = pd.DataFrame({
    '特征': features,
    '重要性': rf_model.feature_importances_
}).sort_values('重要性', ascending=False)

print("\n特征重要性:")
print(feature_importance)

# 可视化预测结果
plt.figure(figsize=(12, 6))
plt.plot(range(len(y_test)), y_test.values, label='实际值', color='blue', alpha=0.7)
plt.plot(range(len(y_pred)), y_pred, label='预测值', color='red', linestyle='--')
plt.title('销售预测:实际值 vs 预测值', fontsize=16, fontweight='bold')
plt.xlabel('样本索引', fontsize=12)
plt.ylabel('销售额', fontsize=12)
plt.legend()
plt.tight_layout()
plt.show()

总结与最佳实践

1. 性能优化技巧

# 1. 使用向量化操作替代循环
import numpy as np
import pandas as pd

# 不推荐的做法(使用循环)
def slow_calculation(df):
    result = []
    for i in range(len(df)):
        if df.iloc[i]['销售额'] > 5000:
            result.append('高')
        else:
            result.append('低')
    return result

# 推荐的做法(使用向量化)
def fast_calculation(df):
    return np.where(df['销售额'] > 5000, '高', '低')

# 2. 使用适当的数据类型
def optimize_memory(df):
    # 将object类型转换为category如果唯一值较少
    for col in df.select_dtypes(include=['object']).columns:
        if df[col].nunique() / len(df) < 0.5:
            df[col] = df[col].astype('category')
    
    # 将数值类型转换为更小的类型
    for col in df.select_dtypes(include=['int']).columns:
        df[col] = pd.to_numeric(df[col], downcast='integer')
    
    for col in df.select_dtypes(include=['float']).columns:
        df[col] = pd.to_numeric(df[col], downcast='float')
    
    return df

# 3. 使用chunksize处理大文件
def process_large_file(file_path, chunk_size=10000):
    chunks = pd.read_csv(file_path, chunksize=chunk_size)
    results = []
    
    for chunk in chunks:
        # 对每个chunk进行处理
        processed = chunk.groupby('类别')['销售额'].sum()
        results.append(processed)
    
    # 合并结果
    final_result = pd.concat(results).groupby(level=0).sum()
    return final_result

2. 代码组织与可维护性

# 使用函数封装重复逻辑
def load_data(file_path, file_type='csv'):
    """加载数据文件"""
    if file_type == 'csv':
        return pd.read_csv(file_path)
    elif file_type == 'excel':
        return pd.read_excel(file_path)
    else:
        raise ValueError("不支持的文件类型")

def clean_data(df, fillna_values=None, drop_duplicates=True):
    """数据清洗"""
    if fillna_values:
        df = df.fillna(fillna_values)
    if drop_duplicates:
        df = df.drop_duplicates()
    return df

def analyze_sales(df, group_by=None, agg_func='sum'):
    """销售分析"""
    if group_by:
        return df.groupby(group_by)['销售额'].agg(agg_func)
    else:
        return df['销售额'].agg(agg_func)

# 使用类封装复杂分析
class SalesAnalyzer:
    def __init__(self, data):
        self.data = data
        self.results = {}
    
    def monthly_trend(self):
        """月度趋势分析"""
        self.results['monthly'] = self.data.groupby('月份')['销售额'].sum()
        return self.results['monthly']
    
    def category_performance(self):
        """品类表现分析"""
        self.results['category'] = self.data.groupby('产品类别').agg({
            '销售额': 'sum',
            '利润': 'sum'
        })
        return self.results['category']
    
    def generate_report(self):
        """生成完整报告"""
        report = {
            '总销售额': self.data['销售额'].sum(),
            '总利润': self.data['利润'].sum(),
            '月度趋势': self.monthly_trend().to_dict(),
            '品类表现': self.category_performance().to_dict()
        }
        return report

3. 常见问题与解决方案

问题1:内存不足

# 解决方案:分块处理或使用Dask
import dask.dataframe as dd

# 使用Dask处理大数据
ddf = dd.read_csv('large_file.csv')
result = ddf.groupby('类别').销售额.sum().compute()

问题2:数据类型混乱

# 解决方案:统一数据类型
df['日期'] = pd.to_datetime(df['日期'], errors='coerce')
df['数值'] = pd.to_numeric(df['数值'], errors='coerce')

问题3:中文显示乱码

# 解决方案:设置字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

结语

Python数据分析是一个不断学习和实践的过程。从基础的Pandas操作到高级的时间序列分析和机器学习预测,每一步都需要扎实的理论基础和丰富的实践经验。

记住以下关键点:

  1. 数据质量是基础:花足够的时间在数据清洗和预处理上
  2. 理解业务:技术服务于业务,理解业务需求才能做出有价值的分析
  3. 持续学习:数据分析领域发展迅速,保持学习新技术和方法
  4. 代码规范:编写可读、可维护的代码,便于团队协作
  5. 可视化沟通:用图表讲好数据故事,让分析结果更容易被理解

通过本指南的学习,你应该能够独立完成从数据获取、清洗、分析到可视化的完整流程,并能够根据业务需求进行深入的探索性分析和预测建模。记住,最好的学习方式是实践,尝试用真实的数据来应用这些技术,你会发现数据分析的无限可能。