Python疯狂练习60天——第十六天

今日练习主题:数据分析与可视化

今天我们将学习使用Python进行数据分析和可视化,主要使用pandas、numpy、matplotlib和seaborn等库。

练习1:NumPy基础操作

import numpy as np
import matplotlib.pyplot as plt

def numpy_basics():
    """NumPy基础操作"""
    print("=== NumPy基础操作 ===")
    
    # 创建数组
    arr1 = np.array([1, 2, 3, 4, 5])
    arr2 = np.arange(0, 10, 2)  # 0到10,步长为2
    arr3 = np.linspace(0, 1, 5)  # 0到1,5个等间距点
    zeros = np.zeros((3, 3))     # 3x3零矩阵
    ones = np.ones((2, 4))       # 2x4一矩阵
    identity = np.eye(3)         # 3x3单位矩阵
    random_arr = np.random.rand(5)  # 5个随机数
    
    print(f"一维数组: {arr1}")
    print(f"等差数组: {arr2}")
    print(f"等间距数组: {arr3}")
    print(f"零矩阵:
{zeros}")
    print(f"一矩阵:
{ones}")
    print(f"单位矩阵:
{identity}")
    print(f"随机数组: {random_arr}")
    
    # 数组操作
    print(f"
数组形状: {arr1.shape}")
    print(f"数组维度: {arr1.ndim}")
    print(f"数组大小: {arr1.size}")
    print(f"数组数据类型: {arr1.dtype}")
    
    # 数学运算
    print(f"
数组加法: {arr1 + 10}")
    print(f"数组乘法: {arr1 * 2}")
    print(f"数组平方: {arr1 ** 2}")
    print(f"数组正弦: {np.sin(arr1)}")
    
    # 统计操作
    print(f"
数组求和: {np.sum(arr1)}")
    print(f"数组均值: {np.mean(arr1)}")
    print(f"数组标准差: {np.std(arr1)}")
    print(f"数组最大值: {np.max(arr1)}")
    print(f"数组最小值: {np.min(arr1)}")
    
    # 二维数组操作
    matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    print(f"
二维数组:
{matrix}")
    print(f"转置矩阵:
{matrix.T}")
    print(f"矩阵行列式: {np.linalg.det(matrix):.2f}")
    print(f"矩阵逆:
{np.linalg.inv(matrix):.2f}")

numpy_basics()

练习2:Pandas数据处理

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

def pandas_basics():
    """Pandas数据处理基础"""
    print("
=== Pandas数据处理 ===")
    
    # 创建Series
    series_data = pd.Series([1, 3, 5, np.nan, 6, 8])
    print("Series:")
    print(series_data)
    
    # 创建DataFrame
    dates = pd.date_range('20230101', periods=6)
    df = pd.DataFrame({
        '日期': dates,
        'A': [1, 2, 3, 4, 5, 6],
        'B': [10, 20, 30, 40, 50, 60],
        'C': [100, 200, 300, 400, 500, 600],
        'D': ['北京', '上海', '广州', '深圳', '杭州', '成都']
    })
    
    print("
DataFrame:")
    print(df)
    
    # 基本信息
    print(f"
DataFrame形状: {df.shape}")
    print(f"列名: {df.columns.tolist()}")
    print(f"索引: {df.index.tolist()}")
    print(f"数据类型:
{df.dtypes}")
    
    # 数据选择
    print("
选择列A:")
    print(df['A'])
    
    print("
选择前3行:")
    print(df.head(3))
    
    print("
选择特定行和列:")
    print(df.loc[0:2, ['A', 'D']])
    
    # 数据筛选
    print("
筛选A列大于3的行:")
    print(df[df['A'] > 3])
    
    print("
多条件筛选:")
    print(df[(df['A'] > 2) & (df['B'] < 50)])
    
    # 数据排序
    print("
按A列降序排序:")
    print(df.sort_values('A', ascending=False))
    
    # 数据统计
    print("
描述性统计:")
    print(df.describe())
    
    # 处理缺失值
    df_with_nan = df.copy()
    df_with_nan.loc[2, 'A'] = np.nan
    df_with_nan.loc[4, 'B'] = np.nan
    
    print("
包含缺失值的数据:")
    print(df_with_nan)
    
    print("
填充缺失值:")
    print(df_with_nan.fillna(0))
    
    print("
删除包含缺失值的行:")
    print(df_with_nan.dropna())

def pandas_advanced():
    """Pandas高级操作"""
    print("
=== Pandas高级操作 ===")
    
    # 创建示例数据
    sales_data = {
        '日期': pd.date_range('2023-01-01', periods=100, freq='D'),
        '产品': np.random.choice(['产品A', '产品B', '产品C'], 100),
        '销售额': np.random.randint(100, 1000, 100),
        '数量': np.random.randint(1, 20, 100),
        '地区': np.random.choice(['华北', '华东', '华南', '西部'], 100)
    }
    
    df = pd.DataFrame(sales_data)
    df['单价'] = df['销售额'] / df['数量']
    
    print("销售数据:")
    print(df.head())
    
    # 分组聚合
    print("
按产品分组统计:")
    product_stats = df.groupby('产品').agg({
        '销售额': ['sum', 'mean', 'count'],
        '数量': 'sum',
        '单价': 'mean'
    })
    print(product_stats)
    
    # 数据透视表
    print("
数据透视表(地区×产品):")
    pivot_table = pd.pivot_table(df, 
                               values='销售额', 
                               index='地区', 
                               columns='产品', 
                               aggfunc='sum',
                               fill_value=0)
    print(pivot_table)
    
    # 时间序列分析
    df.set_index('日期', inplace=True)
    print("
月度销售额统计:")
    monthly_sales = df['销售额'].resample('M').sum()
    print(monthly_sales)
    
    # 移动平均
    df['销售额_7天移动平均'] = df['销售额'].rolling(window=7).mean()
    print("
7天移动平均:")
    print(df[['销售额', '销售额_7天移动平均']].head(10))

pandas_basics()
pandas_advanced()

练习3:Matplotlib基础可视化

import matplotlib.pyplot as plt
import numpy as np

def matplotlib_basics():
    """Matplotlib基础可视化"""
    print("=== Matplotlib基础可视化 ===")
    
    # 设置中文字体
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    plt.rcParams['axes.unicode_minus'] = False    # 用来正常显示负号
    
    # 创建数据
    x = np.linspace(0, 10, 100)
    y1 = np.sin(x)
    y2 = np.cos(x)
    y3 = np.tan(x) / 10  # 缩小tan函数的值
    
    # 1. 折线图
    plt.figure(figsize=(12, 8))
    
    plt.subplot(2, 2, 1)
    plt.plot(x, y1, 'b-', label='sin(x)', linewidth=2)
    plt.plot(x, y2, 'r--', label='cos(x)', linewidth=2)
    plt.title('三角函数曲线')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.legend()
    plt.grid(True, alpha=0.3)
    
    # 2. 散点图
    plt.subplot(2, 2, 2)
    x_scatter = np.random.rand(50) * 10
    y_scatter = np.random.rand(50) * 10
    sizes = np.random.rand(50) * 100
    colors = np.random.rand(50)
    
    plt.scatter(x_scatter, y_scatter, s=sizes, c=colors, alpha=0.6, cmap='viridis')
    plt.colorbar(label='颜色值')
    plt.title('散点图')
    plt.xlabel('X轴')
    plt.ylabel('Y轴')
    
    # 3. 柱状图
    plt.subplot(2, 2, 3)
    categories = ['产品A', '产品B', '产品C', '产品D', '产品E']
    values = [23, 45, 56, 12, 67]
    
    bars = plt.bar(categories, values, color=['#FF9999', '#66B2FF', '#99FF99', '#FFD700', '#FF69B4'])
    plt.title('产品销售额')
    plt.xlabel('产品类别')
    plt.ylabel('销售额(万元)')
    
    # 在柱子上添加数值标签
    for bar in bars:
        height = bar.get_height()
        plt.text(bar.get_x() + bar.get_width()/2., height,
                f'{height}', ha='center', va='bottom')
    
    # 4. 饼图
    plt.subplot(2, 2, 4)
    labels = ['技术', '市场', '销售', '行政', '研发']
    sizes = [15, 30, 25, 10, 20]
    colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc']
    explode = (0.1, 0, 0, 0, 0)  # 突出显示第一部分
    
    plt.pie(sizes, explode=explode, labels=labels, colors=colors, 
            autopct='%1.1f%%', shadow=True, startangle=90)
    plt.title('部门人员分布')
    
    plt.tight_layout()
    plt.show()

def matplotlib_advanced():
    """Matplotlib高级可视化"""
    print("
=== Matplotlib高级可视化 ===")
    
    # 创建数据
    np.random.seed(42)  # 设置随机种子保证结果可重复
    x = np.linspace(0, 10, 100)
    y1 = 2 * x + 1 + np.random.normal(0, 1, 100)
    y2 = 0.5 * x**2 - 2 * x + 3 + np.random.normal(0, 3, 100)
    
    # 创建子图网格
    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(15, 10))
    
    # 1. 带误差线的折线图
    x_error = np.arange(10)
    y_error = x_error ** 2
    y_err = np.random.rand(10) * 5
    
    ax1.errorbar(x_error, y_error, yerr=y_err, fmt='-o', capsize=5, 
                capthick=2, elinewidth=2, markersize=8)
    ax1.set_title('带误差线的折线图')
    ax1.set_xlabel('X轴')
    ax1.set_ylabel('Y轴')
    ax1.grid(True, alpha=0.3)
    
    # 2. 直方图
    data_hist = np.random.normal(170, 10, 1000)  # 身高数据
    
    ax2.hist(data_hist, bins=30, density=True, alpha=0.7, color='skyblue', 
             edgecolor='black')
    ax2.set_title('身高分布直方图')
    ax2.set_xlabel('身高(cm)')
    ax2.set_ylabel('频率')
    
    # 添加正态分布曲线
    from scipy.stats import norm
    x_hist = np.linspace(data_hist.min(), data_hist.max(), 100)
    ax2.plot(x_hist, norm.pdf(x_hist, data_hist.mean(), data_hist.std()), 
             'r-', linewidth=2)
    
    # 3. 箱线图
    data_box = [np.random.normal(0, std, 100) for std in range(1, 4)]
    
    ax3.boxplot(data_box, labels=['组1', '组2', '组3'])
    ax3.set_title('箱线图')
    ax3.set_ylabel('数值')
    
    # 4. 面积图
    x_area = np.linspace(0, 10, 100)
    y1_area = np.sin(x_area)
    y2_area = np.cos(x_area)
    
    ax4.fill_between(x_area, y1_area, alpha=0.3, label='sin(x)')
    ax4.fill_between(x_area, y2_area, alpha=0.3, label='cos(x)')
    ax4.plot(x_area, y1_area, 'b-', alpha=0.8)
    ax4.plot(x_area, y2_area, 'r-', alpha=0.8)
    ax4.set_title('面积图')
    ax4.set_xlabel('X轴')
    ax4.set_ylabel('Y轴')
    ax4.legend()
    ax4.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()

matplotlib_basics()
matplotlib_advanced()

练习4:Seaborn统计可视化

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

def seaborn_visualization():
    """Seaborn统计可视化"""
    print("=== Seaborn统计可视化 ===")
    
    # 设置样式
    sns.set_style("whitegrid")
    sns.set_palette("husl")
    
    # 创建示例数据
    np.random.seed(42)
    n = 200
    
    data = pd.DataFrame({
        '年龄': np.random.randint(18, 65, n),
        '收入': np.random.normal(50000, 15000, n),
        '教育年限': np.random.randint(8, 20, n),
        '性别': np.random.choice(['男', '女'], n),
        '城市': np.random.choice(['北京', '上海', '广州', '深圳'], n),
        '满意度': np.random.randint(1, 11, n)
    })
    
    # 确保收入为正数
    data['收入'] = data['收入'].clip(lower=20000)
    
    print("示例数据:")
    print(data.head())
    
    # 创建多图布局
    plt.figure(figsize=(15, 12))
    
    # 1. 分布图
    plt.subplot(2, 3, 1)
    sns.histplot(data=data, x='收入', kde=True, bins=20)
    plt.title('收入分布')
    
    # 2. 箱线图
    plt.subplot(2, 3, 2)
    sns.boxplot(data=data, x='城市', y='收入')
    plt.title('各城市收入分布')
    plt.xticks(rotation=45)
    
    # 3. 小提琴图
    plt.subplot(2, 3, 3)
    sns.violinplot(data=data, x='性别', y='收入', hue='性别', split=True)
    plt.title('性别收入分布')
    
    # 4. 散点图与回归线
    plt.subplot(2, 3, 4)
    sns.regplot(data=data, x='年龄', y='收入', scatter_kws={'alpha':0.5})
    plt.title('年龄与收入关系')
    
    # 5. 热力图(相关性矩阵)
    plt.subplot(2, 3, 5)
    numeric_data = data.select_dtypes(include=[np.number])
    correlation = numeric_data.corr()
    sns.heatmap(correlation, annot=True, cmap='coolwarm', center=0)
    plt.title('变量相关性热力图')
    
    # 6. 配对图(小样本)
    # 由于配对图较复杂,我们使用子样本
    plt.subplot(2, 3, 6)
    sample_data = data.sample(50)
    sns.scatterplot(data=sample_data, x='年龄', y='收入', hue='城市', size='满意度', sizes=(20, 200))
    plt.title('多变量散点图')
    
    plt.tight_layout()
    plt.show()
    
    # 7. 分类图
    plt.figure(figsize=(12, 5))
    
    plt.subplot(1, 2, 1)
    sns.barplot(data=data, x='城市', y='收入', hue='性别', ci='sd')
    plt.title('各城市性别收入对比')
    plt.xticks(rotation=45)
    
    plt.subplot(1, 2, 2)
    sns.countplot(data=data, x='城市', hue='性别')
    plt.title('各城市性别分布')
    plt.xticks(rotation=45)
    
    plt.tight_layout()
    plt.show()

seaborn_visualization()

练习5:实际数据分析案例

def sales_analysis():
    """销售数据分析案例"""
    print("=== 销售数据分析案例 ===")
    
    # 创建模拟销售数据
    np.random.seed(123)
    n_customers = 1000
    
    # 生成客户数据
    customers = pd.DataFrame({
        '客户ID': range(1, n_customers + 1),
        '年龄': np.random.randint(18, 70, n_customers),
        '性别': np.random.choice(['男', '女'], n_customers, p=[0.55, 0.45]),
        '城市': np.random.choice(['北京', '上海', '广州', '深圳', '杭州', '成都'], n_customers),
        '会员等级': np.random.choice(['普通', '银卡', '金卡', '白金'], n_customers, p=[0.6, 0.25, 0.1, 0.05]),
        '注册日期': pd.date_range('2020-01-01', periods=n_customers, freq='D')
    })
    
    # 生成交易数据
    n_transactions = 5000
    transactions = pd.DataFrame({
        '交易ID': range(1, n_transactions + 1),
        '客户ID': np.random.randint(1, n_customers + 1, n_transactions),
        '交易日期': pd.date_range('2023-01-01', periods=n_transactions, freq='H'),
        '产品类别': np.random.choice(['电子产品', '服装', '家居', '食品', '图书'], n_transactions),
        '金额': np.random.exponential(100, n_transactions),
        '数量': np.random.randint(1, 5, n_transactions)
    })
    
    # 合并数据
    merged_data = transactions.merge(customers, on='客户ID')
    
    print("数据概览:")
    print(f"客户数量: {len(customers)}")
    print(f"交易数量: {len(transactions)}")
    print(f"合并后数据形状: {merged_data.shape}")
    
    # 数据分析
    print("
=== 数据分析 ===")
    
    # 1. 基本统计
    print("交易金额统计:")
    print(merged_data['金额'].describe())
    
    # 2. 月度销售趋势
    merged_data['月份'] = merged_data['交易日期'].dt.to_period('M')
    monthly_sales = merged_data.groupby('月份').agg({
        '金额': 'sum',
        '交易ID': 'count'
    }).rename(columns={'交易ID': '交易次数'})
    
    print("
月度销售趋势:")
    print(monthly_sales.tail())
    
    # 3. 产品类别分析
    category_analysis = merged_data.groupby('产品类别').agg({
        '金额': ['sum', 'mean', 'count'],
        '数量': 'sum'
    }).round(2)
    
    print("
产品类别分析:")
    print(category_analysis)
    
    # 4. 客户分析
    customer_analysis = merged_data.groupby('客户ID').agg({
        '金额': 'sum',
        '交易ID': 'count',
        '年龄': 'first',
        '性别': 'first',
        '城市': 'first',
        '会员等级': 'first'
    }).rename(columns={'交易ID': '购买次数', '金额': '总消费金额'})
    
    print("
客户分析(前10名):")
    print(customer_analysis.nlargest(10, '总消费金额'))
    
    # 可视化分析
    plt.figure(figsize=(15, 10))
    
    # 1. 月度销售趋势图
    plt.subplot(2, 2, 1)
    monthly_sales['金额'].plot(kind='line', marker='o')
    plt.title('月度销售额趋势')
    plt.xlabel('月份')
    plt.ylabel('销售额')
    plt.xticks(rotation=45)
    plt.grid(True, alpha=0.3)
    
    # 2. 产品类别销售额
    plt.subplot(2, 2, 2)
    category_sales = merged_data.groupby('产品类别')['金额'].sum().sort_values(ascending=False)
    category_sales.plot(kind='bar')
    plt.title('各产品类别销售额')
    plt.xlabel('产品类别')
    plt.ylabel('销售额')
    plt.xticks(rotation=45)
    
    # 3. 客户性别分布
    plt.subplot(2, 2, 3)
    gender_dist = merged_data['性别'].value_counts()
    plt.pie(gender_dist.values, labels=gender_dist.index, autopct='%1.1f%%')
    plt.title('客户性别分布')
    
    # 4. 会员等级消费分析
    plt.subplot(2, 2, 4)
    member_sales = merged_data.groupby('会员等级')['金额'].mean().sort_values(ascending=False)
    member_sales.plot(kind='bar', color=['gold', 'silver', '#cd7f32', 'lightblue'])
    plt.title('各会员等级平均消费金额')
    plt.xlabel('会员等级')
    plt.ylabel('平均消费金额')
    
    plt.tight_layout()
    plt.show()
    
    # 高级分析:RFM分析
    print("
=== RFM客户分析 ===")
    
    # 计算RFM值
    analysis_date = merged_data['交易日期'].max()
    
    rfm = merged_data.groupby('客户ID').agg({
        '交易日期': lambda x: (analysis_date - x.max()).days,  # 最近一次购买
        '交易ID': 'count',                                    # 购买频率
        '金额': 'sum'                                         # 购买金额
    }).rename(columns={
        '交易日期': 'Recency',
        '交易ID': 'Frequency',
        '金额': 'Monetary'
    })
    
    # RFM分箱
    rfm['R_Score'] = pd.qcut(rfm['Recency'], 4, labels=[4, 3, 2, 1])  # 最近购买得分(越小越好)
    rfm['F_Score'] = pd.qcut(rfm['Frequency'], 4, labels=[1, 2, 3, 4]) # 购买频率得分
    rfm['M_Score'] = pd.qcut(rfm['Monetary'], 4, labels=[1, 2, 3, 4])  # 购买金额得分
    
    rfm['RFM_Score'] = rfm['R_Score'].astype(str) + rfm['F_Score'].astype(str) + rfm['M_Score'].astype(str)
    
    # 客户分层
    def rfm_segment(row):
        if row['R_Score'] >= 3 and row['F_Score'] >= 3 and row['M_Score'] >= 3:
            return '高价值客户'
        elif row['R_Score'] >= 2 and row['F_Score'] >= 2:
            return '潜力客户'
        elif row['R_Score'] >= 3:
            return '新客户'
        elif row['F_Score'] >= 3:
            return '忠实客户'
        else:
            return '一般客户'
    
    rfm['Segment'] = rfm.apply(rfm_segment, axis=1)
    
    print("RFM客户分层统计:")
    print(rfm['Segment'].value_counts())
    
    # RFM可视化
    plt.figure(figsize=(12, 5))
    
    plt.subplot(1, 2, 1)
    segment_counts = rfm['Segment'].value_counts()
    plt.pie(segment_counts.values, labels=segment_counts.index, autopct='%1.1f%%')
    plt.title('客户分层分布')
    
    plt.subplot(1, 2, 2)
    segment_metrics = rfm.groupby('Segment')[['Recency', 'Frequency', 'Monetary']].mean()
    segment_metrics.plot(kind='bar', figsize=(10, 6))
    plt.title('各客户分层平均指标')
    plt.xlabel('客户分层')
    plt.ylabel('平均值')
    plt.xticks(rotation=45)
    plt.legend(['最近购买(天)', '购买频率', '购买金额'])
    
    plt.tight_layout()
    plt.show()

sales_analysis()

练习6:时间序列分析

def time_series_analysis():
    """时间序列分析"""
    print("=== 时间序列分析 ===")
    
    # 创建时间序列数据
    dates = pd.date_range('2020-01-01', '2023-12-31', freq='D')
    n = len(dates)
    
    # 生成有趋势、季节性和噪声的时间序列
    trend = np.linspace(100, 200, n)  # 线性趋势
    seasonal = 10 * np.sin(2 * np.pi * np.arange(n) / 365)  # 年季节性
    noise = np.random.normal(0, 5, n)  # 随机噪声
    
    # 合成时间序列
    ts_data = trend + seasonal + noise
    
    # 创建DataFrame
    ts_df = pd.DataFrame({
        '日期': dates,
        '销售额': ts_data
    })
    ts_df.set_index('日期', inplace=True)
    
    print("时间序列数据:")
    print(ts_df.head())
    
    # 时间序列可视化
    plt.figure(figsize=(15, 10))
    
    # 1. 原始时间序列
    plt.subplot(3, 2, 1)
    plt.plot(ts_df.index, ts_df['销售额'])
    plt.title('原始时间序列')
    plt.xlabel('日期')
    plt.ylabel('销售额')
    plt.grid(True, alpha=0.3)
    
    # 2. 年度对比
    plt.subplot(3, 2, 2)
    for year in [2020, 2021, 2022, 2023]:
        year_data = ts_df[ts_df.index.year == year]
        plt.plot(year_data.index.dayofyear, year_data['销售额'], label=str(year))
    plt.title('年度对比')
    plt.xlabel('一年中的第几天')
    plt.ylabel('销售额')
    plt.legend()
    plt.grid(True, alpha=0.3)
    
    # 3. 移动平均
    plt.subplot(3, 2, 3)
    ts_df['MA_7'] = ts_df['销售额'].rolling(window=7).mean()
    ts_df['MA_30'] = ts_df['销售额'].rolling(window=30).mean()
    
    plt.plot(ts_df.index, ts_df['销售额'], alpha=0.3, label='原始数据')
    plt.plot(ts_df.index, ts_df['MA_7'], label='7天移动平均')
    plt.plot(ts_df.index, ts_df['MA_30'], label='30天移动平均')
    plt.title('移动平均平滑')
    plt.xlabel('日期')
    plt.ylabel('销售额')
    plt.legend()
    plt.grid(True, alpha=0.3)
    
    # 4. 季节性分解(简化版)
    from statsmodels.tsa.seasonal import seasonal_decompose
    
    # 使用月度数据进行分析
    monthly_data = ts_df['销售额'].resample('M').mean()
    
    # 季节性分解
    decomposition = seasonal_decompose(monthly_data, model='additive', period=12)
    
    plt.subplot(3, 2, 4)
    decomposition.trend.plot()
    plt.title('趋势成分')
    plt.xlabel('日期')
    plt.ylabel('趋势')
    plt.grid(True, alpha=0.3)
    
    plt.subplot(3, 2, 5)
    decomposition.seasonal.plot()
    plt.title('季节性成分')
    plt.xlabel('日期')
    plt.ylabel('季节性')
    plt.grid(True, alpha=0.3)
    
    plt.subplot(3, 2, 6)
    decomposition.resid.plot()
    plt.title('残差成分')
    plt.xlabel('日期')
    plt.ylabel('残差')
    plt.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()
    
    # 时间序列预测(使用简单方法)
    print("
=== 时间序列预测 ===")
    
    # 划分训练集和测试集
    train_size = int(len(monthly_data) * 0.8)
    train, test = monthly_data[:train_size], monthly_data[train_size:]
    
    # 简单预测方法:使用最后一个值作为预测
    last_value = train.iloc[-1]
    predictions = pd.Series([last_value] * len(test), index=test.index)
    
    # 计算预测误差
    mse = ((predictions - test) ** 2).mean()
    mae = (predictions - test).abs().mean()
    
    print(f"预测误差:")
    print(f"均方误差 (MSE): {mse:.2f}")
    print(f"平均绝对误差 (MAE): {mae:.2f}")
    
    # 预测可视化
    plt.figure(figsize=(12, 6))
    plt.plot(train.index, train, label='训练数据')
    plt.plot(test.index, test, label='实际值')
    plt.plot(predictions.index, predictions, label='预测值', linestyle='--')
    plt.title('时间序列预测')
    plt.xlabel('日期')
    plt.ylabel('销售额')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.show()

time_series_analysis()

练习7:地理数据可视化

import geopandas as gpd
import contextily as ctx

def geo_visualization():
    """地理数据可视化"""
    print("=== 地理数据可视化 ===")
    
    try:
        # 创建模拟的地理数据
        cities = pd.DataFrame({
            '城市': ['北京', '上海', '广州', '深圳', '杭州', '成都', '武汉', '西安'],
            '经度': [116.40, 121.47, 113.23, 114.07, 120.15, 104.06, 114.31, 108.94],
            '纬度': [39.90, 31.23, 23.16, 22.62, 30.28, 30.67, 30.52, 34.26],
            '人口(万)': [2189, 2428, 1530, 1303, 981, 1658, 1121, 1020],
            'GDP(亿元)': [36103, 38701, 25019, 27670, 16106, 17717, 15616, 10020]
        })
        
        # 创建GeoDataFrame
        gdf = gpd.GeoDataFrame(
            cities, 
            geometry=gpd.points_from_xy(cities.经度, cities.纬度),
            crs="EPSG:4326"  # WGS84坐标系
        )
        
        print("地理数据:")
        print(gdf.head())
        
        # 地理可视化
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
        
        # 1. 人口分布图
        gdf.plot(ax=ax1, 
                column='人口(万)', 
                cmap='Reds', 
                legend=True,
                markersize=gdf['人口(万)']/100,  # 根据人口调整点大小
                alpha=0.7)
        
        ax1.set_title('中国主要城市人口分布')
        ax1.set_xlabel('经度')
        ax1.set_ylabel('纬度')
        
        # 添加城市标签
        for idx, row in gdf.iterrows():
            ax1.annotate(row['城市'], (row['经度'], row['纬度']), 
                        xytext=(5, 5), textcoords='offset points', fontsize=8)
        
        # 2. GDP分布图
        gdf.plot(ax=ax2, 
                column='GDP(亿元)', 
                cmap='Blues', 
                legend=True,
                markersize=gdf['GDP(亿元)']/1000,  # 根据GDP调整点大小
                alpha=0.7)
        
        ax2.set_title('中国主要城市GDP分布')
        ax2.set_xlabel('经度')
        ax2.set_ylabel('纬度')
        
        # 添加城市标签
        for idx, row in gdf.iterrows():
            ax2.annotate(row['城市'], (row['经度'], row['纬度']), 
                        xytext=(5, 5), textcoords='offset points', fontsize=8)
        
        plt.tight_layout()
        plt.show()
        
    except ImportError:
        print("geopandas或contextily库未安装,跳过地理可视化")
        print("请安装: pip install geopandas contextily")

geo_visualization()

今日挑战:

创建一个完整的数据分析报告,包含数据清洗、探索性分析、统计建模和可视化。

# 挑战练习:完整的数据分析报告
def comprehensive_data_analysis():
    """完整的数据分析报告"""
    print("=== 完整的数据分析报告 ===")
    
    # 1. 数据准备和清洗
    print("1. 数据准备和清洗")
    
    # 创建综合数据集
    np.random.seed(42)
    n = 1000
    
    data = pd.DataFrame({
        '年龄': np.random.normal(35, 10, n).astype(int),
        '年收入(万)': np.random.normal(15, 5, n),
        '教育年限': np.random.randint(8, 20, n),
        '工作经验': np.random.randint(0, 40, n),
        '城市等级': np.random.choice([1, 2, 3], n, p=[0.2, 0.5, 0.3]),  # 1-一线, 2-二线, 3-三线
        '行业': np.random.choice(['科技', '金融', '制造', '教育', '医疗'], n),
        '婚姻状况': np.random.choice(['未婚', '已婚', '离异'], n, p=[0.4, 0.5, 0.1]),
        '是否有房': np.random.choice([0, 1], n, p=[0.3, 0.7]),
        '是否有车': np.random.choice([0, 1], n, p=[0.4, 0.6]),
        '信用评分': np.random.randint(300, 850, n)
    })
    
    # 数据清洗
    # 确保年龄在合理范围内
    data['年龄'] = data['年龄'].clip(18, 65)
    
    # 确保收入为正数
    data['年收入(万)'] = data['年收入(万)'].clip(3, 50)
    
    # 添加一些缺失值
    missing_indices = np.random.choice(n, size=50, replace=False)
    data.loc[missing_indices, '年收入(万)'] = np.nan
    
    print("原始数据形状:", data.shape)
    print("缺失值统计:")
    print(data.isnull().sum())
    
    # 处理缺失值
    data_clean = data.copy()
    data_clean['年收入(万)'] = data_clean['年收入(万)'].fillna(data_clean['年收入(万)'].median())
    
    print("
清洗后数据形状:", data_clean.shape)
    print("清洗后缺失值统计:")
    print(data_clean.isnull().sum())
    
    # 2. 探索性数据分析
    print("
2. 探索性数据分析")
    
    # 基本统计
    print("数值变量描述性统计:")
    print(data_clean.describe())
    
    print("
分类变量统计:")
    categorical_cols = ['城市等级', '行业', '婚姻状况', '是否有房', '是否有车']
    for col in categorical_cols:
        print(f"
{col}分布:")
        print(data_clean[col].value_counts())
    
    # 3. 相关性分析
    print("
3. 相关性分析")
    
    # 计算相关系数矩阵
    numeric_cols = ['年龄', '年收入(万)', '教育年限', '工作经验', '信用评分']
    correlation_matrix = data_clean[numeric_cols].corr()
    
    plt.figure(figsize=(10, 8))
    sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0, square=True)
    plt.title('变量相关性热力图')
    plt.tight_layout()
    plt.show()
    
    # 4. 多维度可视化分析
    print("
4. 多维度可视化分析")
    
    fig = plt.figure(figsize=(18, 12))
    
    # 4.1 收入分布
    plt.subplot(2, 3, 1)
    plt.hist(data_clean['年收入(万)'], bins=30, alpha=0.7, color='skyblue', edgecolor='black')
    plt.title('年收入分布')
    plt.xlabel('年收入(万)')
    plt.ylabel('频数')
    
    # 4.2 收入与教育程度关系
    plt.subplot(2, 3, 2)
    sns.boxplot(data=data_clean, x='教育年限', y='年收入(万)')
    plt.title('教育程度与收入关系')
    plt.xticks(rotation=45)
    
    # 4.3 行业收入对比
    plt.subplot(2, 3, 3)
    industry_income = data_clean.groupby('行业')['年收入(万)'].mean().sort_values(ascending=False)
    industry_income.plot(kind='bar')
    plt.title('各行业平均收入')
    plt.ylabel('平均年收入(万)')
    plt.xticks(rotation=45)
    
    # 4.4 城市等级与收入
    plt.subplot(2, 3, 4)
    sns.violinplot(data=data_clean, x='城市等级', y='年收入(万)')
    plt.title('不同城市等级收入分布')
    
    # 4.5 婚姻状况与收入
    plt.subplot(2, 3, 5)
    marital_income = data_clean.groupby('婚姻状况')['年收入(万)'].mean()
    marital_income.plot(kind='pie', autopct='%1.1f%%')
    plt.title('婚姻状况收入分布')
    
    # 4.6 房产与收入关系
    plt.subplot(2, 3, 6)
    sns.scatterplot(data=data_clean, x='年龄', y='年收入(万)', hue='是否有房', style='是否有车')
    plt.title('年龄、收入与资产关系')
    
    plt.tight_layout()
    plt.show()
    
    # 5. 统计建模
    print("
5. 统计建模")
    
    from sklearn.linear_model import LinearRegression
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import mean_squared_error, r2_score
    from sklearn.preprocessing import LabelEncoder
    
    # 数据预处理
    modeling_data = data_clean.copy()
    
    # 编码分类变量
    label_encoders = {}
    for col in ['行业', '婚姻状况']:
        le = LabelEncoder()
        modeling_data[col] = le.fit_transform(modeling_data[col])
        label_encoders[col] = le
    
    # 准备特征和目标变量
    X = modeling_data.drop('年收入(万)', axis=1)
    y = modeling_data['年收入(万)']
    
    # 划分训练集和测试集
    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:.2f}")
    
    # 特征重大性
    feature_importance = pd.DataFrame({
        '特征': X.columns,
        '系数': model.coef_
    }).sort_values('系数', key=abs, ascending=False)
    
    print("
特征重大性:")
    print(feature_importance)
    
    # 6. 预测结果可视化
    plt.figure(figsize=(12, 5))
    
    plt.subplot(1, 2, 1)
    plt.scatter(y_test, y_pred, alpha=0.5)
    plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--')
    plt.xlabel('实际值')
    plt.ylabel('预测值')
    plt.title('预测 vs 实际值')
    
    plt.subplot(1, 2, 2)
    residuals = y_test - y_pred
    plt.scatter(y_pred, residuals, alpha=0.5)
    plt.axhline(y=0, color='r', linestyle='--')
    plt.xlabel('预测值')
    plt.ylabel('残差')
    plt.title('残差分析')
    
    plt.tight_layout()
    plt.show()
    
    # 7. 生成分析报告摘要
    print("
" + "="*50)
    print("数据分析报告摘要")
    print("="*50)
    
    print(f"数据集大小: {data_clean.shape}")
    print(f"平均年龄: {data_clean['年龄'].mean():.1f}岁")
    print(f"平均年收入: {data_clean['年收入(万)'].mean():.1f}万元")
    print(f"最高收入行业: {industry_income.index[0]} ({industry_income.iloc[0]:.1f}万元)")
    print(f"模型预测准确度 (R²): {r2:.3f}")
    
    # 关键发现
    print("
关键发现:")
    print("1. 教育程度与收入呈正相关关系")
    print("2. 不同行业间存在明显的收入差异")
    print("3. 一线城市收入水平显著高于其他城市")
    print("4. 模型能够较好地预测收入水平")
    
    # 提议
    print("
提议:")
    print("1. 重点关注高收入行业的人才培养")
    print("2. 加强职业教育和继续教育")
    print("3. 优化区域人才发展政策")
    print("4. 基于模型结果优化人力资源配置")

# 运行完整的数据分析
comprehensive_data_analysis()

学习提示:

  1. NumPy:数值计算基础,数组操作和数学函数
  2. Pandas:数据处理核心,数据清洗、转换和分析
  3. Matplotlib:基础可视化,创建各种静态图表
  4. Seaborn:统计可视化,基于Matplotlib的高级接口
  5. 数据清洗:处理缺失值、异常值、数据类型转换
  6. 探索性分析:统计描述、相关性分析、分布分析
  7. 统计建模:回归分析、分类模型、模型评估
  8. 报告生成:结果解释、可视化展示、业务洞察

明天我们将学习机器学习和人工智能基础!坚持练习,你的数据分析能力会越来越强!

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
张小雅的头像 - 宋马
评论 抢沙发

请登录后发表评论

    暂无评论内容