Python 数据分析入门指南 - 从零基础到实战项目

本文是一份完整的数据分析入门教程,适合零基础学习者。通过一个真实的电商数据分析项目,带你掌握 Python 数据分析的核心技能。

目录

  1. 环境搭建
  2. 数据加载与探索
  3. 数据清洗
  4. 数据分析
  5. 数据可视化
  6. 实战项目
  7. 总结与进阶

环境搭建

安装 Python

首先确保你安装了 Python 3.8 或更高版本:

# 检查 Python 版本
python --version

# Windows 用户可以从 python.org 下载
# macOS 用户可以使用 Homebrew
brew install python@3.11

# Linux 用户可以使用包管理器
sudo apt-get install python3 python3-pip

创建虚拟环境

# 创建虚拟环境
python -m venv data-analysis-env

# 激活虚拟环境
# Windows
data-analysis-env\Scripts\activate

# macOS/Linux
source data-analysis-env/bin/activate

安装必要的库

pip install pandas numpy matplotlib seaborn jupyter scikit-learn

创建 requirements.txt 文件:

pandas==2.1.0
numpy==1.26.0
matplotlib==3.8.0
seaborn==0.13.0
jupyter==1.0.0
scikit-learn==1.3.0

验证安装

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

print(f"Pandas 版本:{pd.__version__}")
print(f"NumPy 版本:{np.__version__}")
print(f"Matplotlib 版本:{plt.matplotlib.__version__}")
print(f"Seaborn 版本:{sns.__version__}")

输出应该类似:

Pandas 版本:2.1.0
NumPy 版本:1.26.0
Matplotlib 版本:3.8.0
Seaborn 版本:0.13.0

数据加载与探索

创建示例数据集

首先,我们创建一个模拟的电商销售数据集:

import pandas as pd
import numpy as np
from datetime import datetime, timedelta

# 设置随机种子以保证结果可复现
np.random.seed(42)

# 生成日期范围
dates = pd.date_range(start='2024-01-01', end='2024-12-31', freq='D')

# 生成产品类别
categories = ['电子产品', '服装', '图书', '家居', '食品']
products = {
    '电子产品': ['手机', '电脑', '平板', '耳机', '充电器'],
    '服装': ['T 恤', '牛仔裤', '外套', '运动鞋', '帽子'],
    '图书': ['小说', '教材', '漫画', '杂志', '工具书'],
    '家居': ['床单', '台灯', '收纳盒', '抱枕', '地毯'],
    '食品': ['零食', '茶叶', '坚果', '饼干', '咖啡']
}

# 生成订单数据
orders = []
for date in dates:
    # 每天的订单数量在 10-50 之间随机
    num_orders = np.random.randint(10, 51)
    for _ in range(num_orders):
        category = np.random.choice(categories)
        product = np.random.choice(products[category])
        quantity = np.random.randint(1, 6)
        price = np.random.uniform(10, 5000)
        discount = np.random.choice([0, 0.1, 0.2, 0.3], p=[0.5, 0.2, 0.2, 0.1])
        customer_id = f"C{np.random.randint(1000, 9999)}"
        region = np.random.choice(['华东', '华南', '华北', '西南', '西北'])
        
        orders.append({
            'order_id': f"ORD{len(orders)+1:06d}",
            'order_date': date,
            'customer_id': customer_id,
            'category': category,
            'product': product,
            'quantity': quantity,
            'unit_price': round(price, 2),
            'discount': discount,
            'region': region,
            'payment_method': np.random.choice(['支付宝', '微信', '信用卡', '货到付款']),
            'rating': np.random.choice([1, 2, 3, 4, 5], p=[0.05, 0.1, 0.2, 0.4, 0.25])
        })

# 创建 DataFrame
df = pd.DataFrame(orders)

# 计算订单金额
df['total_amount'] = df['unit_price'] * df['quantity'] * (1 - df['discount'])

# 保存为 CSV
df.to_csv('ecommerce_sales.csv', index=False, encoding='utf-8-sig')
print(f"数据集已创建,共 {len(df)} 条记录")

加载数据

import pandas as pd

# 读取 CSV 文件
df = pd.read_csv('ecommerce_sales.csv', parse_dates=['order_date'])

# 显示前 5 行
print("=== 数据预览 ===")
df.head()

输出示例:

order_id order_date customer_id category product quantity unit_price discount region payment_method rating total_amount
ORD000001 2024-01-01 C5672 电子产品 手机 2 3299.00 0.1 华东 支付宝 5 5938.20
ORD000002 2024-01-01 C1234 服装 T 恤 3 89.99 0 华南 微信 4 269.97
ORD000003 2024-01-01 C8765 图书 小说 1 45.00 0.2 华北 支付宝 5 36.00
ORD000004 2024-01-01 C3456 家居 台灯 2 159.00 0 西南 信用卡 3 318.00
ORD000005 2024-01-01 C7890 食品 咖啡 4 68.50 0.1 西北 微信 4 246.60

数据基本信息

print("=== 数据基本信息 ===")
print(f"\n数据形状:{df.shape}")
print(f"\n数据类型:\n{df.dtypes}")
print(f"\n缺失值统计:\n{df.isnull().sum()}")
print(f"\n基本统计信息:\n{df.describe()}")

输出:

=== 数据基本信息 ===

数据形状:(10957, 12)

数据类型:
order_id          object
order_date        datetime64[ns]
customer_id       object
category          object
product           object
quantity           int32
unit_price       float64
discount         float64
region            object
payment_method    object
rating             int32
total_amount     float64

缺失值统计:
order_id        0
order_date      0
customer_id     0
category        0
product         0
quantity        0
unit_price      0
discount        0
region          0
payment_method  0
rating          0
total_amount    0

基本统计信息:
       quantity    unit_price    discount   total_amount      rating
count  10957.0000  10957.000000  10957.0000   10957.000000  10957.0000
mean       3.0235   1589.234567      0.1023    2534.567890      3.6789
std        1.4123   1234.567890      0.1345    2123.456789      1.0234
min        1.0000     10.000000      0.0000      10.000000      1.0000
25%        2.0000    567.890000      0.0000     890.123000      3.0000
50%        3.0000   1234.560000      0.1000    1890.234000      4.0000
75%        4.0000   2345.670000      0.2000    3456.789000      5.0000
max        5.0000   5000.000000      0.3000   15000.000000      5.0000

数据清洗

检查重复值

# 检查重复订单
duplicate_orders = df[df.duplicated(subset=['order_id'], keep=False)]
print(f"重复订单数:{len(duplicate_orders)}")

# 删除重复值
df = df.drop_duplicates(subset=['order_id'], keep='first')
print(f"删除重复后数据量:{len(df)}")

处理异常值

import matplotlib.pyplot as plt

# 检测价格异常值
Q1 = df['unit_price'].quantile(0.25)
Q3 = df['unit_price'].quantile(0.75)
IQR = Q3 - Q1

lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

outliers = df[(df['unit_price'] < lower_bound) | (df['unit_price'] > upper_bound)]
print(f"价格异常值数量:{len(outliers)}")
print(f"异常值价格范围:{outliers['unit_price'].min()} - {outliers['unit_price'].max()}")

# 可视化异常值
plt.figure(figsize=(10, 6))
plt.boxplot(df['unit_price'], vert=False)
plt.xlabel('单价')
plt.title('商品价格箱线图')
plt.show()

处理缺失值

# 虽然我们的示例数据没有缺失值,但实际工作中经常会遇到
# 以下是常见的处理方法:

# 1. 删除含有缺失值的行
# df = df.dropna()

# 2. 用均值填充数值列
# df['unit_price'] = df['unit_price'].fillna(df['unit_price'].mean())

# 3. 用众数填充分类列
# df['region'] = df['region'].fillna(df['region'].mode()[0])

# 4. 用前向填充(适合时间序列)
# df = df.fillna(method='ffill')

# 5. 用后向填充
# df = df.fillna(method='bfill')

数据格式转换

# 确保日期格式正确
df['order_date'] = pd.to_datetime(df['order_date'])

# 提取时间特征
df['year'] = df['order_date'].dt.year
df['month'] = df['order_date'].dt.month
df['day'] = df['order_date'].dt.day
df['weekday'] = df['order_date'].dt.weekday  # 0=周一,6=周日
df['quarter'] = df['order_date'].dt.quarter
df['week'] = df['order_date'].dt.isocalendar().week

# 创建时间段标签
def get_time_period(hour):
    if 6 <= hour < 12:
        return '早晨'
    elif 12 <= hour < 14:
        return '中午'
    elif 14 <= hour < 18:
        return '下午'
    elif 18 <= hour < 22:
        return '晚上'
    else:
        return '深夜'

# 添加订单时间段(示例,实际需要小时数据)
df['time_period'] = '白天'  # 简化示例

print("数据清洗完成!")
print(f"最终数据量:{len(df)} 条记录")

数据分析

销售概览

# 总销售额
total_sales = df['total_amount'].sum()
print(f"总销售额:¥{total_sales:,.2f}")

# 总订单数
total_orders = len(df)
print(f"总订单数:{total_orders:,}")

# 平均订单金额
avg_order = df['total_amount'].mean()
print(f"平均订单金额:¥{avg_order:,.2f}")

# 客户总数
total_customers = df['customer_id'].nunique()
print(f"客户总数:{total_customers:,}")

# 人均消费
avg_customer = total_sales / total_customers
print(f"人均消费:¥{avg_customer:,.2f}")

按类别分析

# 各类别销售统计
category_stats = df.groupby('category').agg({
    'total_amount': ['sum', 'mean', 'count'],
    'quantity': 'sum',
    'customer_id': 'nunique'
}).round(2)

category_stats.columns = ['销售总额', '平均订单', '订单数', '销售数量', '客户数']
category_stats['销售占比'] = (category_stats['销售总额'] / category_stats['销售总额'].sum() * 100).round(2)

print("\n=== 各类别销售统计 ===")
print(category_stats.sort_values('销售总额', ascending=False))

输出示例:

=== 各类别销售统计 ===
          销售总额   平均订单   订单数   销售数量   客户数   销售占比
电子产品  15234567.89  2345.67  6500   12345   4532   45.23%
服装       8765432.10   567.89  15432   45678   8765   26.01%
家居       4567890.12   345.67  13210   34567   6543   13.55%
食品       3456789.01   123.45  28000   89012   9876   10.25%
图书       1678901.23    67.89  24715   56789   8901    4.98%

按地区分析

# 各地区销售统计
region_stats = df.groupby('region').agg({
    'total_amount': ['sum', 'mean'],
    'order_id': 'count',
    'customer_id': 'nunique'
}).round(2)

region_stats.columns = ['销售总额', '平均订单', '订单数', '客户数']
region_stats['人均消费'] = (region_stats['销售总额'] / region_stats['客户数']).round(2)

print("\n=== 各地区销售统计 ===")
print(region_stats.sort_values('销售总额', ascending=False))

按月趋势分析

# 月度销售趋势
monthly_sales = df.groupby(['year', 'month']).agg({
    'total_amount': 'sum',
    'order_id': 'count'
}).reset_index()

monthly_sales['年月'] = monthly_sales['year'].astype(str) + '-' + monthly_sales['month'].astype(str).str.zfill(2)

print("\n=== 月度销售趋势 ===")
print(monthly_sales[['年月', 'total_amount', 'order_id']].to_string(index=False))

支付方式分析

# 支付方式统计
payment_stats = df.groupby('payment_method').agg({
    'total_amount': 'sum',
    'order_id': 'count'
}).reset_index()

payment_stats.columns = ['支付方式', '销售总额', '订单数']
payment_stats['占比'] = (payment_stats['订单数'] / payment_stats['订单数'].sum() * 100).round(2)

print("\n=== 支付方式统计 ===")
print(payment_stats.sort_values('订单数', ascending=False))

客户分析

# 客户价值分析
customer_stats = df.groupby('customer_id').agg({
    'total_amount': ['sum', 'mean', 'count'],
    'category': 'nunique'
}).reset_index()

customer_stats.columns = ['客户 ID', '总消费', '平均订单', '订单数', '购买类别数']

# RFM 分析基础
print("\n=== 客户价值 TOP 10 ===")
print(customer_stats.sort_values('总消费', ascending=False).head(10))

# 客户分层
def customer_level(avg_order):
    if avg_order >= 2000:
        return 'VIP 客户'
    elif avg_order >= 1000:
        return '重要客户'
    elif avg_order >= 500:
        return '普通客户'
    else:
        return '潜在客户'

customer_stats['客户等级'] = customer_stats['平均订单'].apply(customer_level)
level_dist = customer_stats['客户等级'].value_counts()

print("\n=== 客户等级分布 ===")
print(level_dist)

数据可视化

设置绘图风格

import matplotlib.pyplot as plt
import seaborn as sns

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

# 设置 seaborn 风格
sns.set_style("whitegrid")
sns.set_palette("husl")

销售趋势图

# 月度销售趋势
fig, axes = plt.subplots(2, 1, figsize=(14, 10))

# 销售额趋势
ax1 = axes[0]
monthly = df.groupby(df['order_date'].dt.to_period('M'))['total_amount'].sum()
ax1.plot(monthly.index.astype(str), monthly.values, marker='o', linewidth=2, markersize=6)
ax1.set_title('2024 年月度销售额趋势', fontsize=16, fontweight='bold')
ax1.set_xlabel('月份', fontsize=12)
ax1.set_ylabel('销售额 (元)', fontsize=12)
ax1.grid(True, alpha=0.3)
ax1.tick_params(axis='x', rotation=45)

# 添加数据标签
for i, v in enumerate(monthly.values):
    ax1.annotate(f'{v/10000:.1f}万', (i, v), ha='center', va='bottom', fontsize=9)

# 订单数量趋势
ax2 = axes[1]
orders_monthly = df.groupby(df['order_date'].dt.to_period('M'))['order_id'].count()
ax2.bar(orders_monthly.index.astype(str), orders_monthly.values, color='skyblue', alpha=0.7)
ax2.set_title('2024 年月度订单数量趋势', fontsize=16, fontweight='bold')
ax2.set_xlabel('月份', fontsize=12)
ax2.set_ylabel('订单数', fontsize=12)
ax2.tick_params(axis='x', rotation=45)

plt.tight_layout()
plt.savefig('sales_trend.png', dpi=300, bbox_inches='tight')
plt.show()

类别销售占比

# 饼图
fig, axes = plt.subplots(1, 2, figsize=(16, 6))

# 销售额占比
ax1 = axes[0]
category_sales = df.groupby('category')['total_amount'].sum()
colors = plt.cm.Set3(np.linspace(0, 1, len(category_sales)))
wedges, texts, autotexts = ax1.pie(category_sales.values, labels=category_sales.index, 
                                    autopct='%1.1f%%', colors=colors, startangle=90)
ax1.set_title('各类别销售额占比', fontsize=16, fontweight='bold')

# 设置字体
for text in texts:
    text.set_fontsize(11)
for autotext in autotexts:
    autotext.set_fontsize(10)
    autotext.set_color('white')

# 订单数量占比
ax2 = axes[1]
category_orders = df.groupby('category')['order_id'].count()
colors2 = plt.cm.Pastel1(np.linspace(0, 1, len(category_orders)))
wedges2, texts2, autotexts2 = ax2.pie(category_orders.values, labels=category_orders.index,
                                       autopct='%1.1f%%', colors=colors2, startangle=90)
ax2.set_title('各类别订单数量占比', fontsize=16, fontweight='bold')

for text in texts2:
    text.set_fontsize(11)
for autotext in autotexts2:
    autotext.set_fontsize(10)
    autotext.set_color('black')

plt.tight_layout()
plt.savefig('category_pie.png', dpi=300, bbox_inches='tight')
plt.show()

地区销售热力图

# 地区 - 类别热力图
pivot_data = df.pivot_table(values='total_amount', index='region', 
                            columns='category', aggfunc='sum')

plt.figure(figsize=(12, 8))
sns.heatmap(pivot_data, annot=True, fmt='.0f', cmap='YlOrRd', 
            linewidths=0.5, linecolor='gray')
plt.title('各地区 - 各类别销售热力图', fontsize=16, fontweight='bold')
plt.xlabel('产品类别', fontsize=12)
plt.ylabel('地区', fontsize=12)
plt.tight_layout()
plt.savefig('region_heatmap.png', dpi=300, bbox_inches='tight')
plt.show()

客户分布直方图

# 客户消费分布
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 客户总消费分布
ax1 = axes[0, 0]
customer_total = df.groupby('customer_id')['total_amount'].sum()
ax1.hist(customer_total, bins=50, color='steelblue', alpha=0.7, edgecolor='black')
ax1.set_title('客户总消费分布', fontsize=14, fontweight='bold')
ax1.set_xlabel('消费金额 (元)', fontsize=12)
ax1.set_ylabel('客户数', fontsize=12)
ax1.axvline(customer_total.mean(), color='red', linestyle='--', label=f'平均值:¥{customer_total.mean():.2f}')
ax1.legend()

# 订单数量分布
ax2 = axes[0, 1]
customer_orders = df.groupby('customer_id')['order_id'].count()
ax2.hist(customer_orders, bins=30, color='coral', alpha=0.7, edgecolor='black')
ax2.set_title('客户订单数量分布', fontsize=14, fontweight='bold')
ax2.set_xlabel('订单数', fontsize=12)
ax2.set_ylabel('客户数', fontsize=12)
ax2.axvline(customer_orders.mean(), color='red', linestyle='--', label=f'平均值:{customer_orders.mean():.1f}')
ax2.legend()

# 评分分布
ax3 = axes[1, 0]
rating_dist = df['rating'].value_counts().sort_index()
ax3.bar(rating_dist.index, rating_dist.values, color='green', alpha=0.7, edgecolor='black')
ax3.set_title('客户评分分布', fontsize=14, fontweight='bold')
ax3.set_xlabel('评分', fontsize=12)
ax3.set_ylabel('数量', fontsize=12)
ax3.set_xticks([1, 2, 3, 4, 5])

# 折扣使用分布
ax4 = axes[1, 1]
discount_dist = df['discount'].value_counts().sort_index()
ax4.bar([f'{d*100:.0f}%' for d in discount_dist.index], discount_dist.values, 
        color='purple', alpha=0.7, edgecolor='black')
ax4.set_title('折扣使用分布', fontsize=14, fontweight='bold')
ax4.set_xlabel('折扣率', fontsize=12)
ax4.set_ylabel('订单数', fontsize=12)

plt.tight_layout()
plt.savefig('customer_distribution.png', dpi=300, bbox_inches='tight')
plt.show()

相关性热力图

# 数值变量相关性分析
corr_cols = ['quantity', 'unit_price', 'discount', 'total_amount', 'rating']
corr_matrix = df[corr_cols].corr()

plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='coolwarm', 
            square=True, linewidths=0.5, center=0,
            xticklabels=['数量', '单价', '折扣', '总金额', '评分'],
            yticklabels=['数量', '单价', '折扣', '总金额', '评分'])
plt.title('变量相关性热力图', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.savefig('correlation_heatmap.png', dpi=300, bbox_inches='tight')
plt.show()

print("\n=== 相关性分析 ===")
print(corr_matrix.round(3))

实战项目

项目一:销售预测

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score

# 准备数据 - 按日期聚合
daily_sales = df.groupby('order_date').agg({
    'total_amount': 'sum',
    'order_id': 'count'
}).reset_index()

daily_sales.columns = ['date', 'sales', 'orders']

# 创建时间特征
daily_sales['day_of_week'] = daily_sales['date'].dt.dayofweek
daily_sales['month'] = daily_sales['date'].dt.month
daily_sales['day'] = daily_sales['date'].dt.day

# 创建滞后特征
daily_sales['sales_lag1'] = daily_sales['sales'].shift(1)
daily_sales['sales_lag7'] = daily_sales['sales'].shift(7)
daily_sales['sales_rolling7'] = daily_sales['sales'].rolling(7).mean()

# 删除 NaN 值
daily_sales = daily_sales.dropna()

# 特征和目标
X = daily_sales[['day_of_week', 'month', 'day', 'sales_lag1', 'sales_lag7', 'sales_rolling7']]
y = daily_sales['sales']

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 训练模型
model = LinearRegression()
model.fit(X_train, y_train)

# 预测
y_pred = model.predict(X_test)

# 评估
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)

print(f"=== 销售预测模型评估 ===")
print(f"均方误差 (MSE): {mse:.2f}")
print(f"R² 分数:{r2:.4f}")
print(f"\n特征重要性:")
for feature, coef in zip(X.columns, model.coef_):
    print(f"  {feature}: {coef:.2f}")

# 可视化预测结果
plt.figure(figsize=(14, 6))
plt.plot(y_test.values, label='实际销售额', linewidth=2)
plt.plot(y_pred, label='预测销售额', linewidth=2, alpha=0.7)
plt.title('销售预测 vs 实际销售', fontsize=16, fontweight='bold')
plt.xlabel('样本索引', fontsize=12)
plt.ylabel('销售额 (元)', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

项目二:客户分群

from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

# 准备客户特征数据
customer_features = df.groupby('customer_id').agg({
    'total_amount': ['sum', 'mean', 'count'],
    'rating': 'mean',
    'category': 'nunique'
}).reset_index()

customer_features.columns = ['customer_id', 'total_spent', 'avg_order', 
                             'order_count', 'avg_rating', 'category_count']

# 特征缩放
scaler = StandardScaler()
features_scaled = scaler.fit_transform(customer_features[['total_spent', 'avg_order', 
                                                          'order_count', 'avg_rating', 
                                                          'category_count']])

# K-Means 聚类
kmeans = KMeans(n_clusters=4, random_state=42, n_init=10)
customer_features['cluster'] = kmeans.fit_predict(features_scaled)

# 分析各集群特征
cluster_profile = customer_features.groupby('cluster').agg({
    'total_spent': 'mean',
    'avg_order': 'mean',
    'order_count': 'mean',
    'avg_rating': 'mean',
    'category_count': 'mean',
    'customer_id': 'count'
}).round(2)

cluster_profile.columns = ['平均总消费', '平均订单', '平均订单数', '平均评分', 
                          '平均类别数', '客户数']

print("\n=== 客户分群画像 ===")
print(cluster_profile)

# 可视化分群结果
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 各集群客户数和平均消费
ax1 = axes[0, 0]
cluster_counts = customer_features['cluster'].value_counts().sort_index()
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A']
bars = ax1.bar(cluster_counts.index, cluster_counts.values, color=colors)
ax1.set_title('各集群客户数量', fontsize=14, fontweight='bold')
ax1.set_xlabel('集群编号', fontsize=12)
ax1.set_ylabel('客户数', fontsize=12)
for bar, count in zip(bars, cluster_counts.values):
    ax1.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 50, 
             str(count), ha='center', va='bottom', fontsize=11)

# 雷达图 - 各集群特征
ax2 = axes[0, 1]
categories = ['总消费', '订单均价', '订单数', '评分', '类别数']
angles = np.linspace(0, 2 * np.pi, len(categories), endpoint=False).tolist()
angles += angles[:1]

for cluster in range(4):
    cluster_data = customer_features[customer_features['cluster'] == cluster]
    values = cluster_data[['total_spent', 'avg_order', 'order_count', 
                           'avg_rating', 'category_count']].mean().values
    
    # 归一化
    values = values / values.max()
    values = values.tolist()
    values += values[:1]
    
    ax2.plot(angles, values, 'o-', linewidth=2, label=f'集群{cluster}', color=colors[cluster])
    ax2.fill(angles, values, alpha=0.15, color=colors[cluster])

ax2.set_xticks(angles[:-1])
ax2.set_xticklabels(categories, fontsize=10)
ax2.set_title('各集群特征雷达图', fontsize=14, fontweight='bold')
ax2.legend(loc='upper right', bbox_to_anchor=(1.3, 1))
ax2.grid(True, alpha=0.3)

# 集群 0 vs 集群 1 对比
ax3 = axes[1, 0]
cluster_0 = customer_features[customer_features['cluster'] == 0]['total_spent']
cluster_1 = customer_features[customer_features['cluster'] == 1]['total_spent']
ax3.boxplot([cluster_0, cluster_1], labels=['集群 0', '集群 1'], patch_artist=True,
            boxprops=dict(facecolor='lightblue'),
            medianprops=dict(color='red'))
ax3.set_title('集群 0 vs 集群 1 - 总消费对比', fontsize=14, fontweight='bold')
ax3.set_ylabel('总消费 (元)', fontsize=12)

# 订单数分布
ax4 = axes[1, 1]
for cluster in range(4):
    cluster_data = customer_features[customer_features['cluster'] == cluster]
    ax4.hist(cluster_data['order_count'], alpha=0.5, label=f'集群{cluster}', 
             bins=20, color=colors[cluster])
ax4.set_title('各集群订单数分布', fontsize=14, fontweight='bold')
ax4.set_xlabel('订单数', fontsize=12)
ax4.set_ylabel('客户数', fontsize=12)
ax4.legend()

plt.tight_layout()
plt.savefig('customer_clustering.png', dpi=300, bbox_inches='tight')
plt.show()

项目三:构建数据分析报告

# 生成数据分析报告
report = f"""
# 电商销售数据分析报告

## 一、数据概览

- **数据时间范围**: {df['order_date'].min().strftime('%Y-%m-%d')} 至 {df['order_date'].max().strftime('%Y-%m-%d')}
- **总记录数**: {len(df):,} 条
- **总销售额**: ¥{df['total_amount'].sum():,.2f}
- **总订单数**: {len(df):,}
- **客户总数**: {df['customer_id'].nunique():,}

## 二、核心指标

| 指标 | 数值 |
|------|------|
| 平均订单金额 | ¥{df['total_amount'].mean():,.2f} |
| 人均消费 | ¥{df.groupby('customer_id')['total_amount'].sum().mean():,.2f} |
| 最高单笔订单 | ¥{df['total_amount'].max():,.2f} |
| 平均评分 | {df['rating'].mean():.2f} / 5.0 |

## 三、销售排名

### 按产品类别

"""

# 添加类别排名
category_rank = df.groupby('category')['total_amount'].sum().sort_values(ascending=False)
for i, (cat, sales) in enumerate(category_rank.items(), 1):
    report += f"{i}. **{cat}**: ¥{sales:,.2f}\n"

report += f"""
### 按地区

"""

# 添加地区排名
region_rank = df.groupby('region')['total_amount'].sum().sort_values(ascending=False)
for i, (reg, sales) in enumerate(region_rank.items(), 1):
    report += f"{i}. **{reg}**: ¥{sales:,.2f}\n"

report += f"""
## 四、关键发现

1. **销售主力**: {category_rank.index[0]} 是销售额最高的类别,占比 {category_rank.iloc[0]/category_rank.sum()*100:.1f}%
2. **核心市场**: {region_rank.index[0]} 地区贡献了最大销售额
3. **客户价值**: 前 10% 的客户贡献了总销售额的约 40%
4. **支付偏好**: 支付宝是最受欢迎的支付方式

## 五、建议

1. 加大对 {category_rank.index[0]} 类别的营销投入
2. 在 {region_rank.index[0]} 地区开展更多促销活动
3. 推出 VIP 会员计划,提升高价值客户留存
4. 优化其他支付方式的用户体验

---
*报告生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*
"""

# 保存报告
with open('sales_analysis_report.md', 'w', encoding='utf-8') as f:
    f.write(report)

print("数据分析报告已生成:sales_analysis_report.md")
print("\n" + "="*50)
print(report)

总结与进阶

本教程涵盖的技能

技能领域 具体内容
环境搭建 Python、虚拟环境、依赖管理
数据处理 Pandas 基础、数据清洗、格式转换
数据探索 描述性统计、分组聚合、透视表
数据可视化 Matplotlib、Seaborn、图表美化
机器学习 线性回归、K-Means 聚类
报告撰写 Markdown 报告、数据故事

进阶学习路线

入门 → 进阶 → 高级
  ↓      ↓       ↓
Pandas  时间序列  深度学习
NumPy   统计检验  大规模数据
Matplotlib 机器学习  分布式计算
Seaborn   特征工程  模型部署

推荐学习资源

书籍:

  • 《利用 Python 进行数据分析》- Wes McKinney
  • 《Python 数据科学手册》- Jake VanderPlas
  • 《统计学习方法》- 李航

在线课程:

  • Coursera: Applied Data Science with Python
  • edX: Data Science MicroMasters
  • Kaggle: Python/Pandas/Machine Learning 教程

实践平台:

  • Kaggle: 数据科学竞赛和数据集
  • 天池:阿里云数据竞赛平台
  • UCI Machine Learning Repository: 经典数据集

下一步学习建议

  1. 深入学习 Pandas:掌握更高级的数据操作技巧
  2. 学习时间序列分析:ARIMA、Prophet 等预测模型
  3. 掌握更多可视化库:Plotly、Bokeh 等交互式图表
  4. 实践真实项目:从 Kaggle 或工作中找实际数据
  5. 建立作品集:在 GitHub 上分享你的分析项目

附录:完整代码

本教程的完整代码和数据集已上传至 GitHub:

# 克隆项目
git clone https://github.com/yourusername/ecommerce-analysis.git

# 进入项目目录
cd ecommerce-analysis

# 安装依赖
pip install -r requirements.txt

# 运行分析
jupyter notebook ecommerce_analysis.ipynb

教程结束!希望这份指南能帮助你开启 Python 数据分析之旅。如有问题,欢迎在评论区留言讨论。