Initial commit: BTC 1h prediction model (53.10% accuracy)
🎯 项目成果: - 准确率: 53.10% (2026年测试集) - 任务类型: 二分类 (预测涨/跌) - 特征: OHLCV + RSI + MACD (9个特征) - 训练数据: 2020-2025年BTC小时数据 (52,351序列) - 测试数据: 2026年1-29日 (484序列) 📊 性能指标: - 精确率: 51.79% - 召回率: 49.36% - F1分数: 0.5054 - 预测分布: 非常平衡 (偏差仅-11个) 🔬 实验历史: - 尝试了5种方案 (回归/分类, 不同数据划分) - 分类任务优于回归任务 (53.10% vs 49.5%) - 全量训练避免了过拟合问题 📦 主要模型文件: - models/checkpoints/dlinear_classification_2026/ - best_model.pt (最佳模型) - preprocessor.pkl (预处理器) - test_2026_results.json (测试结果) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
commit
9bbdc8d42b
82 files changed
+8742
No files matched your search
@@ -0,0 +1,244 @@
|
||||
"""详细对比二分类和回归任务在加密货币预测中的差异"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from data.fetcher import BinanceDataFetcher
|
||||
from data.preprocessor import CryptoPreprocessor
|
||||
|
||||
def compare_classification_vs_regression():
|
||||
print("="*80)
|
||||
print("二分类 vs 回归任务详细对比")
|
||||
print("="*80)
|
||||
|
||||
# 获取少量数据用于演示
|
||||
print("\n[1/3] 获取示例数据...")
|
||||
fetcher = BinanceDataFetcher()
|
||||
df = fetcher.fetch_ohlcv('BTC', '1h', use_cache=True)
|
||||
df_sample = df.tail(200).copy() # 只取最近200小时
|
||||
|
||||
print(f"✓ 样本数据: {len(df_sample)} 行")
|
||||
print(f"✓ 时间范围: {df_sample['timestamp'].min()} 至 {df_sample['timestamp'].max()}")
|
||||
|
||||
# 对比两种任务
|
||||
print("\n[2/3] 对比两种任务的标签生成...")
|
||||
|
||||
# 二分类任务
|
||||
print("\n" + "="*80)
|
||||
print("📊 任务1: 二分类(Binary Classification)")
|
||||
print("="*80)
|
||||
|
||||
preprocessor_cls = CryptoPreprocessor(
|
||||
lookback=24,
|
||||
forecast_horizon=1,
|
||||
price_change_threshold=0.0
|
||||
)
|
||||
|
||||
# 创建标签
|
||||
df_sample['future_price'] = df_sample['close'].shift(-1)
|
||||
df_sample['future_return'] = (df_sample['future_price'] - df_sample['close']) / df_sample['close']
|
||||
df_sample['label_classification'] = (df_sample['future_return'] > 0).astype(int)
|
||||
|
||||
print(f"\n目标: 预测价格会上涨(1)还是下跌(0)")
|
||||
print(f"\n标签生成公式:")
|
||||
print(f" future_return = (未来价格 - 当前价格) / 当前价格")
|
||||
print(f" label = 1 if future_return > 0 else 0")
|
||||
|
||||
print(f"\n具体例子(前10个样本):")
|
||||
print(f"{'时间':<20} {'当前价格':<12} {'未来价格':<12} {'收益率':<10} {'标签':<8}")
|
||||
print("-"*80)
|
||||
for i in range(10):
|
||||
row = df_sample.iloc[i]
|
||||
if pd.notna(row['future_return']):
|
||||
label = "上涨(1)" if row['label_classification'] == 1 else "下跌(0)"
|
||||
print(f"{str(row['timestamp']):<20} ${row['close']:<11,.2f} ${row['future_price']:<11,.2f} "
|
||||
f"{row['future_return']*100:>7.2f}% {label:<8}")
|
||||
|
||||
print(f"\n标签统计:")
|
||||
n_up = df_sample['label_classification'].sum()
|
||||
n_down = len(df_sample) - n_up - df_sample['label_classification'].isna().sum()
|
||||
print(f" 上涨(1): {n_up} 个")
|
||||
print(f" 下跌(0): {n_down} 个")
|
||||
print(f" 比例: {n_up/(n_up+n_down)*100:.1f}% vs {n_down/(n_up+n_down)*100:.1f}%")
|
||||
|
||||
print(f"\n模型输出:")
|
||||
print(f" 格式: 0-1之间的概率值")
|
||||
print(f" 例如: 0.73 表示 73% 概率上涨")
|
||||
print(f" 决策: 如果概率 > 0.5 → 预测上涨")
|
||||
print(f" 如果概率 < 0.5 → 预测下跌")
|
||||
|
||||
print(f"\n评估指标:")
|
||||
print(f" - 准确率 (Accuracy)")
|
||||
print(f" - 精确率 (Precision)")
|
||||
print(f" - 召回率 (Recall)")
|
||||
print(f" - F1分数")
|
||||
print(f" - 混淆矩阵")
|
||||
|
||||
print(f"\n优点:")
|
||||
print(f" ✅ 简单直观(涨/跌二选一)")
|
||||
print(f" ✅ 评估指标清晰")
|
||||
print(f" ✅ 适合交易决策(做多/做空)")
|
||||
|
||||
print(f"\n缺点:")
|
||||
print(f" ❌ 丢失了涨跌幅度信息")
|
||||
print(f" ❌ 涨0.1%和涨10%被视为一样")
|
||||
print(f" ❌ 无法评估风险收益比")
|
||||
|
||||
# 回归任务
|
||||
print("\n" + "="*80)
|
||||
print("📈 任务2: 回归(Regression)")
|
||||
print("="*80)
|
||||
|
||||
df_sample['label_regression'] = df_sample['future_return']
|
||||
|
||||
print(f"\n目标: 预测价格变化的百分比")
|
||||
print(f"\n标签生成公式:")
|
||||
print(f" label = (未来价格 - 当前价格) / 当前价格")
|
||||
print(f" 直接预测收益率(可正可负)")
|
||||
|
||||
print(f"\n具体例子(前10个样本):")
|
||||
print(f"{'时间':<20} {'当前价格':<12} {'未来价格':<12} {'收益率(标签)':<15}")
|
||||
print("-"*80)
|
||||
for i in range(10):
|
||||
row = df_sample.iloc[i]
|
||||
if pd.notna(row['future_return']):
|
||||
print(f"{str(row['timestamp']):<20} ${row['close']:<11,.2f} ${row['future_price']:<11,.2f} "
|
||||
f"{row['label_regression']*100:>12.4f}%")
|
||||
|
||||
print(f"\n标签统计:")
|
||||
valid_returns = df_sample['label_regression'].dropna()
|
||||
print(f" 最小值: {valid_returns.min()*100:.4f}%")
|
||||
print(f" 最大值: {valid_returns.max()*100:.4f}%")
|
||||
print(f" 均值: {valid_returns.mean()*100:.4f}%")
|
||||
print(f" 标准差: {valid_returns.std()*100:.4f}%")
|
||||
print(f" 中位数: {valid_returns.median()*100:.4f}%")
|
||||
|
||||
print(f"\n模型输出:")
|
||||
print(f" 格式: 连续的数值(收益率)")
|
||||
print(f" 例如: 0.0235 表示预测上涨 2.35%")
|
||||
print(f" -0.0178 表示预测下跌 1.78%")
|
||||
print(f" 决策: 根据预测值大小决定仓位")
|
||||
print(f" 预测+5% → 大仓位做多")
|
||||
print(f" 预测+0.5% → 小仓位做多")
|
||||
|
||||
print(f"\n评估指标:")
|
||||
print(f" - RMSE (均方根误差)")
|
||||
print(f" - MAE (平均绝对误差)")
|
||||
print(f" - MAPE (平均绝对百分比误差)")
|
||||
print(f" - 方向准确率 (预测方向是否正确)")
|
||||
print(f" - R² (决定系数)")
|
||||
|
||||
print(f"\n优点:")
|
||||
print(f" ✅ 保留了涨跌幅度信息")
|
||||
print(f" ✅ 可以评估风险收益比")
|
||||
print(f" ✅ 支持动态仓位管理")
|
||||
print(f" ✅ 提供更精细的预测")
|
||||
|
||||
print(f"\n缺点:")
|
||||
print(f" ❌ 预测难度更高")
|
||||
print(f" ❌ 容易过拟合")
|
||||
print(f" ❌ 对异常值敏感")
|
||||
|
||||
# 对比分析
|
||||
print("\n[3/3] 详细对比分析...")
|
||||
print("\n" + "="*80)
|
||||
print("🔍 详细对比")
|
||||
print("="*80)
|
||||
|
||||
comparison = [
|
||||
["维度", "二分类", "回归"],
|
||||
["-"*30, "-"*40, "-"*40],
|
||||
["预测目标", "方向(涨/跌)", "具体涨跌幅度"],
|
||||
["输出范围", "0-1(概率)", "-∞ to +∞(收益率)"],
|
||||
["输出示例", "0.73(73%概率上涨)", "+0.0235(预测涨2.35%)"],
|
||||
["标签类型", "离散(0或1)", "连续(实数)"],
|
||||
["损失函数", "BCEWithLogitsLoss", "MSELoss / MAELoss"],
|
||||
["评估指标", "准确率、F1分数", "RMSE、MAE、MAPE"],
|
||||
["决策方式", "二元(做多/做空)", "连续(仓位大小)"],
|
||||
["信息量", "少(只有方向)", "多(方向+幅度)"],
|
||||
["预测难度", "中等", "困难"],
|
||||
["适用场景", "简单交易策略", "精细化资金管理"],
|
||||
]
|
||||
|
||||
for row in comparison:
|
||||
print(f"{row[0]:<30} {row[1]:<40} {row[2]:<40}")
|
||||
|
||||
# 实际应用对比
|
||||
print("\n" + "="*80)
|
||||
print("💰 实际交易应用对比")
|
||||
print("="*80)
|
||||
|
||||
print("\n场景1: 预测未来1小时BTC会上涨")
|
||||
print("\n二分类模型:")
|
||||
print(" 输出: 0.68 (68%概率上涨)")
|
||||
print(" 决策: 概率>0.5,买入BTC")
|
||||
print(" 行动: 全仓做多(或固定仓位如50%)")
|
||||
print(" 问题: 不知道预期涨多少,无法评估风险")
|
||||
|
||||
print("\n回归模型:")
|
||||
print(" 输出: +0.0023 (预测上涨0.23%)")
|
||||
print(" 决策: 预测值>0,买入BTC")
|
||||
print(" 行动: 根据预测幅度调整仓位(0.23%很小,可能只用10%仓位)")
|
||||
print(" 优势: 知道预期收益,可以计算风险收益比")
|
||||
|
||||
print("\n场景2: 预测未来1小时BTC大涨")
|
||||
print("\n二分类模型:")
|
||||
print(" 输出: 0.72 (72%概率上涨)")
|
||||
print(" 决策: 买入BTC")
|
||||
print(" 问题: 72%概率可能是涨0.1%,也可能是涨5%,无法区分")
|
||||
|
||||
print("\n回归模型:")
|
||||
print(" 输出: +0.0480 (预测上涨4.8%)")
|
||||
print(" 决策: 买入BTC")
|
||||
print(" 行动: 预期涨幅大,可以加大仓位(如80%)")
|
||||
print(" 优势: 可以根据预期收益调整风险敞口")
|
||||
|
||||
# 性能对比
|
||||
print("\n" + "="*80)
|
||||
print("📊 当前项目的实际性能对比")
|
||||
print("="*80)
|
||||
|
||||
print("\n二分类任务(当前已实现):")
|
||||
print(" 准确率: 49.76%(接近随机)")
|
||||
print(" F1分数: 0.3898")
|
||||
print(" 召回率: 31.85%")
|
||||
print(" 问题: 预测能力极弱")
|
||||
|
||||
print("\n回归任务(未实现):")
|
||||
print(" 预期性能: 可能更差")
|
||||
print(" 原因: 预测具体数值比预测方向更难")
|
||||
print(" 但优势: 即使方向准确率50%,如果能准确预测幅度,仍可盈利")
|
||||
|
||||
# 建议
|
||||
print("\n" + "="*80)
|
||||
print("💡 建议")
|
||||
print("="*80)
|
||||
|
||||
print("\n选择二分类的情况:")
|
||||
print(" ✅ 初学者或概念验证")
|
||||
print(" ✅ 简单的做多/做空策略")
|
||||
print(" ✅ 预测周期较长(1天以上)")
|
||||
print(" ✅ 只关心方向,不关心幅度")
|
||||
|
||||
print("\n选择回归的情况:")
|
||||
print(" ✅ 需要精细化资金管理")
|
||||
print(" ✅ 需要评估风险收益比")
|
||||
print(" ✅ 有足够多的训练数据")
|
||||
print(" ✅ 想要更丰富的预测信息")
|
||||
|
||||
print("\n对于1小时BTC预测:")
|
||||
print(" 当前结论: 两者都很难!")
|
||||
print(" 二分类: 准确率49.76%(已验证)")
|
||||
print(" 回归: 预计MAPE会很高(未验证,但大概率也很差)")
|
||||
print("\n 核心问题: 1小时价格变化接近随机游走")
|
||||
print(" 建议: 延长预测周期到24小时或更长")
|
||||
|
||||
print("\n" + "="*80)
|
||||
print("✓ 对比分析完成")
|
||||
print("="*80)
|
||||
|
||||
if __name__ == "__main__":
|
||||
compare_classification_vs_regression()
|
||||
Reference in new issue
Block a user