Day 7 编程实战:第一周复习与多模型综合比较

实战目标

  1. 使用同一金融数据集训练4个模型
  2. 系统性地比较模型性能
  3. 分析不同模型的优缺点
  4. 撰写综合评估报告
  5. 总结第一周学习成果

1. 导入必要的库

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import time
from pathlib import Path
from sklearn.model_selection import train_test_split, TimeSeriesSplit, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, LogisticRegression, Ridge, Lasso
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import (
    accuracy_score, precision_score, recall_score, f1_score,
    roc_auc_score, roc_curve, confusion_matrix, classification_report,
    mean_squared_error, mean_absolute_error, r2_score
)
from sklearn.pipeline import Pipeline
import warnings
warnings.filterwarnings('ignore')

# 启用LaTeX渲染(如果系统安装了LaTeX)
plt.rcParams['text.usetex'] = False  # 设为False避免LaTeX依赖
# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

2. 获取金融数据集

2.1 获取股票数据

def generate_stock_data(ts_code):
    """加载测试股票数据"""
    data_path = Path(r"E:\AppData\quant_trade\klines\kline2014-2024")
    kline_file = data_path / f"{ts_code}.csv"
    
    df = pd.read_csv(kline_file, usecols=["trade_date", "close", "vol"],
                     parse_dates=["trade_date"]).sort_values(by=["trade_date"]).reset_index(drop=True)
    
    # 计算收益率
    df['return'] = df['close'].pct_change()
    
    # RSI
    delta = df['return'].fillna(0)
    gain = delta.where(delta > 0, 0).rolling(14).mean()
    loss = -delta.where(delta < 0, 0).rolling(14).mean()
    rs = gain / (loss + 1e-10)
    df['rsi'] = 100 - (100 / (1 + rs))
    
    # MACD
    ema12 = df['close'].ewm(span=12, adjust=False).mean()
    ema26 = df['close'].ewm(span=26, adjust=False).mean()
    df['macd'] = ema12 - ema26
    df['macd_signal'] = df['macd'].ewm(span=9, adjust=False).mean()
    
    # 移动平均线
    df['ma5'] = df['close'].rolling(5).mean()
    df['ma20'] = df['close'].rolling(20).mean()
    df['ma_ratio'] = df['ma5'] / df['ma20'] - 1
    
    # 波动率
    df['volatility'] = df['return'].rolling(20).std()
    
    # 成交量指标
    df['volume_ratio'] = df['vol'] / df['vol'].rolling(10).mean()
    
    # 目标变量:次日是否上涨
    df['target'] = (df['return'].shift(-1) > 0).astype(int)
    # df['target'] = (df['close'].shift(-5) > df['close']).astype(int)
    
    # 删除缺失值
    df = df.dropna().reset_index(drop=True)
    
    return df

# 生成数据
df = generate_stock_data("600519.SH")
print(f"数据形状: {df.shape}")
print(f"时间范围: {len(df)} 个交易日")
print(f"目标分布: \n{df['target'].value_counts(normalize=True)}")

# 显示数据样例
df.head()
数据形状: (2452, 13)
时间范围: 2452 个交易日
目标分布: 
target
1    0.505302
0    0.494698
Name: proportion, dtype: float64
trade_date close vol return rsi macd macd_signal ma5 ma20 ma_ratio volatility volume_ratio target
0 2014-01-30 91.1718 37223.44 -0.035108 67.868916 2.271166 1.337153 94.43802 87.318400 0.081536 0.024872 0.798406 1
1 2014-02-07 92.3373 23865.61 0.012784 68.653904 2.206979 1.511118 94.21594 87.660120 0.074787 0.024569 0.521398 0
2 2014-02-10 91.6270 36251.74 -0.007692 65.717807 2.074878 1.623870 93.12768 88.078395 0.057327 0.023698 0.835515 1
3 2014-02-11 92.4408 43006.94 0.008882 71.448630 2.012653 1.701627 92.41320 88.543220 0.043707 0.023662 0.974138 1
4 2014-02-12 92.5167 19283.48 0.000821 68.636501 1.947019 1.750705 92.01872 89.051840 0.033316 0.023423 0.498149 1

2.2 数据可视化

fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 价格走势
axes[0, 0].plot(df['close'].values[-500:], linewidth=1)
axes[0, 0].set_title('股价走势(最近500天)')
axes[0, 0].set_xlabel('时间')
axes[0, 0].set_ylabel('价格')
axes[0, 0].grid(True, alpha=0.3)

# 收益率分布
axes[0, 1].hist(df['return'], bins=50, edgecolor='black', alpha=0.7)
axes[0, 1].set_title('日收益率分布')
axes[0, 1].set_xlabel('收益率')
axes[0, 1].set_ylabel('频数')
axes[0, 1].grid(True, alpha=0.3)

# 技术指标
axes[1, 0].plot(df['rsi'].values[-200:], label='RSI', linewidth=1)
axes[1, 0].axhline(y=70, color='r', linestyle='--', alpha=0.5, label='超买(70)')
axes[1, 0].axhline(y=30, color='g', linestyle='--', alpha=0.5, label='超卖(30)')
axes[1, 0].set_title('RSI指标(最近200天)')
axes[1, 0].set_ylim(0, 100)
axes[1, 0].legend()
axes[1, 0].grid(True, alpha=0.3)

# 相关性热图
feature_cols = ['rsi', 'macd', 'ma_ratio', 'volatility', 'volume_ratio', 'return']
corr_matrix = df[feature_cols + ['target']].corr()
sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='coolwarm', 
            center=0, ax=axes[1, 1])
axes[1, 1].set_title('特征相关性矩阵')

plt.tight_layout()
plt.show()

数据可视化

3. 数据准备

3.1 特征选择

# 选择特征
feature_cols = ['rsi', 'macd', 'ma_ratio', 'volatility', 'volume_ratio', 'return']
X = df[feature_cols]
y = df['target']

print("特征说明:")
print("-" * 40)
feature_descriptions = {
    'rsi': '相对强弱指标,衡量超买超卖',
    'macd': '异同移动平均线,趋势指标',
    'ma_ratio': '均线比率,短期vs长期趋势',
    'volatility': '波动率,风险度量',
    'volume_ratio': '成交量比率,量能变化',
    'return': '当日收益率'
}
for col in feature_cols:
    print(f"{col}: {feature_descriptions[col]}")

特征说明:
----------------------------------------
rsi: 相对强弱指标,衡量超买超卖
macd: 异同移动平均线,趋势指标
ma_ratio: 均线比率,短期vs长期趋势
volatility: 波动率,风险度量
volume_ratio: 成交量比率,量能变化
return: 当日收益率

3.2 时间序列划分

# 按时间顺序划分(70%训练,30%测试)
split_idx = int(len(X) * 0.7)
X_train = X[:split_idx]
X_test = X[split_idx:]
y_train = y[:split_idx]
y_test = y[split_idx:]

print("数据划分结果:")
print(f"训练集: {len(X_train)} 样本 ({split_idx/len(X):.0%})")
print(f"测试集: {len(X_test)} 样本 ({1-split_idx/len(X):.0%})")
print(f"训练集正样本比例: {y_train.mean():.2%}")
print(f"测试集正样本比例: {y_test.mean():.2%}")
数据划分结果:
训练集: 1716 样本 (70%)
测试集: 736 样本 (30%)
训练集正样本比例: 51.98%
测试集正样本比例: 47.15%

3.3 特征标准化

# 标准化(KNN和逻辑回归需要,决策树不需要但为了公平统一处理)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 保留原始数据用于决策树(树模型不需要标准化)
X_train_raw = X_train.values
X_test_raw = X_test.values

print("特征标准化完成")
print(f"训练集均值: {X_train_scaled.mean(axis=0)}")
print(f"训练集标准差: {X_train_scaled.std(axis=0)}")
特征标准化完成
训练集均值: [ 4.24420923e-16  0.00000000e+00 -4.55476113e-17 -2.65004284e-16
 -1.29914209e-16  5.17586492e-19]
训练集标准差: [1. 1. 1. 1. 1. 1.]

4. 模型训练与评估

4.1 定义评估函数

def evaluate_model(model, X_train, X_test, y_train, y_test, model_name, use_proba=True):
    """全面评估模型性能"""
    
    # 计时
    start_time = time.time()
    model.fit(X_train, y_train)
    train_time = time.time() - start_time
    
    start_time = time.time()
    if use_proba and hasattr(model, 'predict_proba'):
        y_pred = model.predict(X_test)
        y_proba = model.predict_proba(X_test)[:, 1]
    else:
        y_pred = model.predict(X_test)
        y_proba = None
    predict_time = time.time() - start_time
    
    # 计算指标
    results = {
        'Model': model_name,
        'Train Time (s)': train_time,
        'Predict Time (s)': predict_time,
        'Accuracy': accuracy_score(y_test, y_pred),
        'Precision': precision_score(y_test, y_pred),
        'Recall': recall_score(y_test, y_pred),
        'F1': f1_score(y_test, y_pred)
    }
    
    if y_proba is not None:
        results['AUC'] = roc_auc_score(y_test, y_proba)
    else:
        results['AUC'] = None
    
    # 交叉验证(使用训练集)
    cv_scores = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc')
    results['CV AUC Mean'] = cv_scores.mean()
    results['CV AUC Std'] = cv_scores.std()
    
    return results, y_pred, y_proba

4.2 训练逻辑回归

print("="*60)
print("1. 逻辑回归模型")
print("="*60)

lr_model = LogisticRegression(C=1.0, max_iter=1000, random_state=42)
lr_results, lr_pred, lr_proba = evaluate_model(
    lr_model, X_train_scaled, X_test_scaled, y_train, y_test, 
    "逻辑回归", use_proba=True
)

print(f"准确率: {lr_results['Accuracy']:.4f}")
print(f"AUC: {lr_results['AUC']:.4f}")
print(f"训练时间: {lr_results['Train Time (s)']:.3f}s")
============================================================
1. 逻辑回归模型
============================================================
准确率: 0.4946
AUC: 0.4796
训练时间: 3.440s

4.3 训练KNN

print("="*60)
print("2. KNN模型")
print("="*60)

# 寻找最佳K值
knn_best = None
best_score = 0
for k in [3, 5, 7, 9, 11, 15]:
    knn_test = KNeighborsClassifier(n_neighbors=k)
    knn_test.fit(X_train_scaled, y_train)
    score = accuracy_score(y_test, knn_test.predict(X_test_scaled))
    if score > best_score:
        best_score = score
        knn_best = knn_test
        best_k = k

print(f"最佳K值: {best_k}")
knn_model = KNeighborsClassifier(n_neighbors=best_k)
knn_results, knn_pred, knn_proba = evaluate_model(
    knn_model, X_train_scaled, X_test_scaled, y_train, y_test,
    "KNN", use_proba=True
)

print(f"准确率: {knn_results['Accuracy']:.4f}")
print(f"AUC: {knn_results['AUC']:.4f}")
============================================================
2. KNN模型
============================================================
最佳K值: 11
准确率: 0.5231
AUC: 0.5168

4.4 训练决策树

print("="*60)
print("3. 决策树模型")
print("="*60)

# 寻找最佳深度
dt_best = None
best_score = 0
for depth in [3, 5, 7, 10, 15]:
    dt_test = DecisionTreeClassifier(max_depth=depth, random_state=42)
    dt_test.fit(X_train_raw, y_train)
    score = accuracy_score(y_test, dt_test.predict(X_test_raw))
    if score > best_score:
        best_score = score
        dt_best = dt_test
        best_depth = depth

print(f"最佳深度: {best_depth}")
dt_model = DecisionTreeClassifier(max_depth=best_depth, random_state=42)
dt_results, dt_pred, dt_proba = evaluate_model(
    dt_model, X_train_raw, X_test_raw, y_train, y_test,
    "决策树", use_proba=True
)

print(f"准确率: {dt_results['Accuracy']:.4f}")
print(f"AUC: {dt_results['AUC']:.4f}")
============================================================
3. 决策树模型
============================================================
最佳深度: 3
准确率: 0.5082
AUC: 0.5220

4.5 训练线性回归(作为回归基准)

print("="*60)
print("4. 线性回归(回归任务基准)")
print("="*60)

# 对于回归,我们预测收益率数值
df_reg = df.copy()
df_reg['target_reg'] = df_reg['return'].shift(-1)  # 预测次日收益率
df_reg = df_reg.dropna()

X_reg = df_reg[feature_cols]
y_reg = df_reg['target_reg']

split_idx_reg = int(len(X_reg) * 0.7)
X_train_reg = X_reg[:split_idx_reg]
X_test_reg = X_reg[split_idx_reg:]
y_train_reg = y_reg[:split_idx_reg]
y_test_reg = y_reg[split_idx_reg:]

# 标准化
X_train_reg_scaled = scaler.fit_transform(X_train_reg)
X_test_reg_scaled = scaler.transform(X_test_reg)

# 训练线性回归
lr_reg = LinearRegression()
lr_reg.fit(X_train_reg_scaled, y_train_reg)
y_pred_reg = lr_reg.predict(X_test_reg_scaled)

# 评估
mse = mean_squared_error(y_test_reg, y_pred_reg)
mae = mean_absolute_error(y_test_reg, y_pred_reg)
r2 = r2_score(y_test_reg, y_pred_reg)

print(f"MSE: {mse:.6f}")
print(f"MAE: {mae:.6f}")
print(f"R²: {r2:.4f}")

# 线性回归也可以用于分类(阈值化)
y_pred_class = (y_pred_reg > 0).astype(int)
lr_reg_class_acc = accuracy_score((y_test_reg > 0).astype(int), y_pred_class)
print(f"转换为分类后的准确率: {lr_reg_class_acc:.4f}")
============================================================
4. 线性回归(回归任务基准)
============================================================
MSE: 0.000347
MAE: 0.013502
R²: -0.0223
转换为分类后的准确率: 0.4728

5. 模型性能对比

5.1 综合性能表格

# 收集所有分类模型结果
results_list = [lr_results, knn_results, dt_results]
results_df = pd.DataFrame(results_list)

# 格式化输出
print("="*80)
print("模型性能综合对比")
print("="*80)
print(results_df.to_string(index=False))

# 突出最佳模型
print("\n" + "="*80)
print("各指标最佳模型")
print("="*80)
for col in ['Accuracy', 'Precision', 'Recall', 'F1', 'AUC']:
    best_idx = results_df[col].idxmax()
    best_model = results_df.loc[best_idx, 'Model']
    best_value = results_df.loc[best_idx, col]
    print(f"{col:12s}: {best_model:10s} ({best_value:.4f})")

================================================================================
模型性能综合对比
================================================================================
模型 训练时间 (s) 预测时间 (s) 准确率 精确率 召回率 F1 分数 AUC CV AUC 均值 CV AUC 标准差
逻辑回归 3.440242 0.001105 0.494565 0.478992 0.821326 0.605096 0.479631 0.523948 0.025267
KNN 0.002640 0.055981 0.523098 0.495781 0.677233 0.572473 0.516780 0.501289 0.018934
决策树 0.005999 0.000514 0.508152 0.485714 0.734870 0.584862 0.522036 0.504558 0.014741
================================================================================
各指标最佳模型
================================================================================
Accuracy    : KNN			(0.5231)
Precision   : KNN			(0.4958)
Recall      : 逻辑回归		(0.8213)
F1          : 逻辑回归 		(0.6051)
AUC         : 决策树 		(0.5220)

5.2 可视化对比

# 雷达图对比
from math import pi

def radar_chart_comparison(results_df):
    """绘制雷达图对比模型性能"""
    # 选择要对比的指标
    metrics = ['Accuracy', 'Precision', 'Recall', 'F1', 'AUC']
    
    # 归一化(0-1之间)
    normalized = results_df[metrics].copy()
    for col in metrics:
        normalized[col] = (normalized[col] - normalized[col].min()) / (normalized[col].max() - normalized[col].min() + 1e-10)
    
    # 设置角度
    angles = [n / len(metrics) * 2 * pi for n in range(len(metrics))]
    angles += angles[:1]
    
    fig, ax = plt.subplots(figsize=(6, 5), subplot_kw={'projection': 'polar'})
    
    colors = ['blue', 'red', 'green']
    for idx, (_, row) in enumerate(results_df.iterrows()):
        values = normalized.loc[idx, metrics].tolist()
        values += values[:1]
        ax.plot(angles, values, 'o-', linewidth=2, label=row['Model'], color=colors[idx])
        ax.fill(angles, values, alpha=0.1, color=colors[idx])
    
    ax.set_xticks(angles[:-1])
    ax.set_xticklabels(metrics)
    ax.set_ylim(0, 1)
    ax.set_title('模型性能雷达图', size=15, pad=20)
    ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1.0))
    plt.show()

radar_chart_comparison(results_df)

模型性能雷达图

# 条形图对比
def bar_chart_comparison(results_df):
    """绘制条形图对比"""
    metrics = ['Accuracy', 'Precision', 'Recall', 'F1', 'AUC']
    models = results_df['Model'].tolist()
    
    fig, axes = plt.subplots(2, 3, figsize=(12, 8))
    axes = axes.ravel()
    
    for idx, metric in enumerate(metrics):
        ax = axes[idx]
        bars = ax.bar(models, results_df[metric], color=['blue', 'red', 'green'])
        ax.set_title(metric)
        ax.set_ylim(0, 1)
        ax.set_ylabel('分数')
        # 添加数值标签
        for bar in bars:
            height = bar.get_height()
            ax.text(bar.get_x() + bar.get_width()/2., height + 0.01,
                   f'{height:.3f}', ha='center', va='bottom')
    
    # 隐藏多余的子图
    axes[5].set_visible(False)
    
    plt.suptitle('模型性能对比', fontsize=14)
    plt.tight_layout()
    plt.show()

bar_chart_comparison(results_df)

在这里插入图片描述

5.3 ROC曲线对比

plt.figure(figsize=(6, 4))

models_roc = [
    (lr_proba, '逻辑回归', 'blue'),
    (knn_proba, 'KNN', 'red'),
    (dt_proba, '决策树', 'green')
]

for proba, name, color in models_roc:
    fpr, tpr, _ = roc_curve(y_test, proba)
    auc = roc_auc_score(y_test, proba)
    plt.plot(fpr, tpr, color=color, linewidth=2, label=f'{name} (AUC={auc:.4f})')

plt.plot([0, 1], [0, 1], 'k--', linewidth=1, label='随机分类器')
plt.xlabel('假阳性率 (FPR)', fontsize=12)
plt.ylabel('真阳性率 (TPR)', fontsize=12)
plt.title('ROC曲线对比', fontsize=14)
plt.legend(loc='lower right')
plt.grid(True, alpha=0.3)
plt.show()

在这里插入图片描述

5.4 混淆矩阵对比

fig, axes = plt.subplots(1, 3, figsize=(10, 3))

models_cm = [
    (lr_pred, '逻辑回归'),
    (knn_pred, 'KNN'),
    (dt_pred, '决策树')
]

for idx, (pred, name) in enumerate(models_cm):
    cm = confusion_matrix(y_test, pred)
    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', ax=axes[idx],
                xticklabels=['下跌', '上涨'], yticklabels=['下跌', '上涨'])
    axes[idx].set_title(f'{name}\n准确率: {accuracy_score(y_test, pred):.4f}')
    axes[idx].set_xlabel('预测')
    axes[idx].set_ylabel('真实')

plt.tight_layout()
plt.show()

在这里插入图片描述

6. 深度分析

6.1 错误分析`

def error_analysis(y_true, y_pred, y_proba, X_test, feature_names, model_name):
    """分析模型预测错误的情况"""
    
    # 找出错误预测
    errors = y_true != y_pred
    error_indices = np.where(errors)[0]
    correct_indices = np.where(~errors)[0]
    
    # 错误类型
    false_positives = np.where((y_true == 0) & (y_pred == 1))[0]
    false_negatives = np.where((y_true == 1) & (y_pred == 0))[0]
    
    print(f"\n{model_name} 错误分析:")
    print("-" * 40)
    print(f"总预测错误数: {len(error_indices)}/{len(y_true)} ({len(error_indices)/len(y_true):.2%})")
    print(f"假阳性(误报): {len(false_positives)}")
    print(f"假阴性(漏报): {len(false_negatives)}")
    
    # 分析错误样本的特征分布
    if len(error_indices) > 0:
        print("\n错误样本的特征平均值:")
        error_features_mean = X_test[error_indices].mean(axis=0)
        correct_features_mean = X_test[correct_indices].mean(axis=0)
        
        for i, feat in enumerate(feature_names):
            diff = error_features_mean[i] - correct_features_mean[i]
            print(f"  {feat}: 错误样本={error_features_mean[i]:.3f}, "
                  f"正确样本={correct_features_mean[i]:.3f}, 差异={diff:+.3f}")
    
    # 分析置信度分布
    if y_proba is not None:
        print(f"\n预测置信度分析:")
        correct_conf = y_proba[correct_indices]
        error_conf = y_proba[error_indices]
        print(f"  正确预测平均置信度: {correct_conf.mean():.3f}")
        print(f"  错误预测平均置信度: {error_conf.mean():.3f}")

# 对每个模型进行错误分析
error_analysis(y_test, lr_pred, lr_proba, X_test_scaled, feature_cols, "逻辑回归")
error_analysis(y_test, knn_pred, knn_proba, X_test_scaled, feature_cols, "KNN")
error_analysis(y_test, dt_pred, dt_proba, X_test_raw, feature_cols, "决策树")

逻辑回归 错误分析:
----------------------------------------
总预测错误数: 372/736 (50.54%)
假阳性(误报): 310
假阴性(漏报): 62

错误样本的特征平均值:
  rsi:			错误样本=-0.435,	正确样本=-0.506,	差异=+0.071
  macd:			错误样本=-0.695,	正确样本=-0.628,	差异=-0.067
  ma_ratio:		错误样本=-0.474,	正确样本=-0.437,	差异=-0.036
  volatility:	错误样本=-0.276,	正确样本=-0.161,	差异=-0.115
  volume_ratio:	错误样本=-0.076,	正确样本=0.050,	差异=-0.126
  return:		错误样本=-0.129,	正确样本=-0.104,	差异=-0.026

预测置信度分析:
  正确预测平均置信度: 0.525
  错误预测平均置信度: 0.532

KNN 错误分析:
----------------------------------------
总预测错误数: 351/736 (47.69%)
假阳性(误报): 239
假阴性(漏报): 112

错误样本的特征平均值:
  rsi:			错误样本=-0.419, 正确样本=-0.517,	差异=+0.098
  macd:			错误样本=-0.646, 正确样本=-0.676,	差异=+0.030
  ma_ratio:		错误样本=-0.449, 正确样本=-0.462,	差异=+0.013
  volatility:	错误样本=-0.228, 正确样本=-0.211,	差异=-0.018
  volume_ratio:	错误样本=-0.082, 正确样本=0.048,		差异=-0.130
  return:		错误样本=-0.108, 正确样本=-0.124,	差异=+0.016

预测置信度分析:
  正确预测平均置信度: 0.542
  错误预测平均置信度: 0.563

决策树 错误分析:
----------------------------------------
总预测错误数: 362/736 (49.18%)
假阳性(误报): 270
假阴性(漏报): 92

错误样本的特征平均值:
  rsi: 			错误样本=49.701,	正确样本=50.110,	差异=-0.410
  macd:			错误样本=-2.283,	正确样本=-3.728,	差异=+1.446
  ma_ratio:		错误样本=-0.003,	正确样本=-0.001,	差异=-0.001
  volatility:	错误样本=0.017,	正确样本=0.018,	差异=-0.001
  volume_ratio:	错误样本=0.975,	正确样本=1.030,	差异=-0.055
  return:		错误样本=-0.001,	正确样本=0.001,	差异=-0.002

预测置信度分析:
  正确预测平均置信度: 0.529
  错误预测平均置信度: 0.545

6.2 特征重要性分析(决策树)

# 决策树特征重要性
importances = dt_model.feature_importances_
feature_importance_df = pd.DataFrame({
    'Feature': feature_cols,
    'Importance': importances
}).sort_values('Importance', ascending=False)

plt.figure(figsize=(5, 3))
plt.barh(feature_importance_df['Feature'], feature_importance_df['Importance'])
plt.xlabel('重要性')
plt.title('决策树特征重要性')
for i, (_, row) in enumerate(feature_importance_df.iterrows()):
    plt.text(row['Importance'] + 0.01, i, f"{row['Importance']:.3f}", va='center')
plt.grid(True, alpha=0.3)
plt.show()

print("决策树特征重要性排序:")
print(feature_importance_df.to_string(index=False))

在这里插入图片描述

决策树特征重要性排序:
     Feature  Importance
volume_ratio    0.482601
      return    0.264460
    ma_ratio    0.164349
  volatility    0.088591
        macd    0.000000
         rsi    0.000000

6.3 逻辑回归系数分析

# 逻辑回归系数
lr_coef = lr_model.coef_[0]
coef_df = pd.DataFrame({
    'Feature': feature_cols,
    'Coefficient': lr_coef,
    'Abs_Coefficient': np.abs(lr_coef)
}).sort_values('Abs_Coefficient', ascending=False)

plt.figure(figsize=(5, 3))
colors = ['red' if c < 0 else 'green' for c in coef_df['Coefficient']]
plt.barh(coef_df['Feature'], coef_df['Coefficient'], color=colors)
plt.xlabel('系数值')
plt.title('逻辑回归系数(正=促进上涨,负=促进下跌)')
plt.axvline(x=0, color='black', linestyle='-', linewidth=0.5)
plt.grid(True, alpha=0.3)
plt.show()

print("逻辑回归系数:")
print(coef_df.to_string(index=False))

在这里插入图片描述

逻辑回归系数:
     Feature  Coefficient  Abs_Coefficient
    ma_ratio    -0.183150         0.183150
         rsi     0.175008         0.175008
      return    -0.157647         0.157647
  volatility    -0.034489         0.034489
        macd    -0.012320         0.012320
volume_ratio     0.000216         0.000216

7. 模型选择建议

7.1 综合评分

# 计算综合得分(加权平均)
def calculate_composite_score(results_df, weights=None):
    """计算综合得分"""
    if weights is None:
        # 默认权重:AUC最重要
        weights = {
            'Accuracy': 0.2,
            'Precision': 0.15,
            'Recall': 0.15,
            'F1': 0.2,
            'AUC': 0.3
        }
    
    composite_scores = []
    for _, row in results_df.iterrows():
        score = sum(row[metric] * weights[metric] for metric in weights.keys())
        composite_scores.append(score)
    
    results_df['Composite Score'] = composite_scores
    return results_df.sort_values('Composite Score', ascending=False)

results_with_score = calculate_composite_score(results_df.copy())
print("综合评分结果:")
print(results_with_score[['Model', 'Composite Score'] + 
      ['Accuracy', 'Precision', 'Recall', 'F1', 'AUC']].to_string(index=False))
综合评分结果:
Model  Composite Score  Accuracy  Precision   Recall       F1      AUC
 逻辑回归         0.558869  0.494565   0.478992 0.821326 0.605096 0.479631
  决策树         0.558301  0.508152   0.485714 0.734870 0.584862 0.522036
  KNN         0.550100  0.523098   0.495781 0.677233 0.572473 0.516780

7.2 选择建议

print("="*70)
print("模型选择建议")
print("="*70)

recommendations = {
    '追求最高预测准确率': results_df.loc[results_df['Accuracy'].idxmax(), 'Model'],
    '追求最高AUC': results_df.loc[results_df['AUC'].idxmax(), 'Model'],
    '追求可解释性': '逻辑回归 或 决策树',
    '追求预测速度': '决策树(推理最快)',
    '追求稳定性(CV方差小)': results_df.loc[results_df['CV AUC Std'].idxmin(), 'Model'],
    '综合评分最高': results_with_score.iloc[0]['Model']
}

for scenario, model in recommendations.items():
    print(f"{scenario:20s}: {model}")

======================================================================
模型选择建议
======================================================================
追求最高预测准确率           : KNN
追求最高AUC             : 决策树
追求可解释性              : 逻辑回归 或 决策树
追求预测速度              : 决策树(推理最快)
追求稳定性(CV方差小)        : 决策树
综合评分最高              : 逻辑回归
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐