From 8b85a0200369a55768c2763dd925a36a1b69b451 Mon Sep 17 00:00:00 2001 From: liaozhaorun <1300336796@qq.com> Date: Fri, 6 Mar 2026 20:57:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20LightGBM=20?= =?UTF-8?q?=E5=9B=9E=E5=BD=92=E8=AE=AD=E7=BB=83=E7=A4=BA=E4=BE=8B=20Notebo?= =?UTF-8?q?ok?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/experiment/regression.ipynb | 1257 +++++++++++++++++++++++++++++++ 1 file changed, 1257 insertions(+) create mode 100644 src/experiment/regression.ipynb diff --git a/src/experiment/regression.ipynb b/src/experiment/regression.ipynb new file mode 100644 index 0000000..0942c43 --- /dev/null +++ b/src/experiment/regression.ipynb @@ -0,0 +1,1257 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# LightGBM 回归训练示例 - 使用因子字符串表达式\n", + "\n", + "使用字符串表达式定义因子,训练 LightGBM 回归模型预测未来5日收益率。\n", + "\n", + "**Label**: return_5 = (ts_delay(close, -5) / close) - 1 # 未来5日收益率" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. 导入依赖" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:54:34.025295Z", + "start_time": "2026-03-05T15:54:33.223817Z" + } + }, + "source": [ + "import os\n", + "from datetime import datetime\n", + "from typing import List\n", + "\n", + "import polars as pl\n", + "\n", + "from src.factors import FactorEngine\n", + "from src.training import (\n", + " DateSplitter,\n", + " LightGBMModel,\n", + " STFilter,\n", + " StandardScaler,\n", + " StockFilterConfig,\n", + " StockPoolManager,\n", + " Trainer,\n", + " Winsorizer,\n", + " NullFiller,\n", + ")\n", + "from src.training.config import TrainingConfig" + ], + "outputs": [], + "execution_count": 1 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. 定义辅助函数" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:54:34.040804Z", + "start_time": "2026-03-05T15:54:34.036138Z" + } + }, + "cell_type": "code", + "source": [ + "def create_factors_with_strings(engine: FactorEngine, factor_definitions: dict, label_factor: dict) -> List[str]:\n", + " print(\"=\" * 80)\n", + " print(\"使用字符串表达式定义因子\")\n", + " print(\"=\" * 80)\n", + "\n", + " # 注册所有特征因子\n", + " print(\"\\n注册特征因子:\")\n", + " for name, expr in factor_definitions.items():\n", + " engine.add_factor(name, expr)\n", + " print(f\" - {name}: {expr}\")\n", + "\n", + " # 注册 label 因子\n", + " print(\"\\n注册 Label 因子:\")\n", + " for name, expr in label_factor.items():\n", + " engine.add_factor(name, expr)\n", + " print(f\" - {name}: {expr}\")\n", + "\n", + " # 从字典自动获取特征列\n", + " feature_cols = list(factor_definitions.keys())\n", + "\n", + " print(f\"\\n特征因子数: {len(feature_cols)}\")\n", + " print(f\"Label: {list(label_factor.keys())[0]}\")\n", + " print(f\"已注册因子总数: {len(engine.list_registered())}\")\n", + "\n", + " return feature_cols\n", + "\n", + "\n", + "def prepare_data(\n", + " engine: FactorEngine,\n", + " feature_cols: List[str],\n", + " start_date: str,\n", + " end_date: str,\n", + ") -> pl.DataFrame:\n", + " print(\"\\n\" + \"=\" * 80)\n", + " print(\"准备数据\")\n", + " print(\"=\" * 80)\n", + "\n", + " # 计算因子(全市场数据)\n", + " print(f\"\\n计算因子: {start_date} - {end_date}\")\n", + " factor_names = feature_cols + [\"return_5\"] # 包含 label\n", + "\n", + " data = engine.compute(\n", + " factor_names=factor_names,\n", + " start_date=start_date,\n", + " end_date=end_date,\n", + " )\n", + "\n", + " print(f\"数据形状: {data.shape}\")\n", + " print(f\"数据列: {data.columns}\")\n", + " print(f\"\\n前5行预览:\")\n", + " print(data.head())\n", + "\n", + " return data" + ], + "outputs": [], + "execution_count": 2 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. 配置参数\n", + "\n", + "### 3.1 因子定义" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:54:34.050475Z", + "start_time": "2026-03-05T15:54:34.045956Z" + } + }, + "cell_type": "code", + "source": [ + "# 特征因子定义字典:新增因子只需在此处添加一行\n", + "FACTOR_DEFINITIONS = {\n", + " # 1. 价格动量因子\n", + " \"ma5\": \"ts_mean(close, 5)\",\n", + " \"ma10\": \"ts_mean(close, 10)\",\n", + " \"ma20\": \"ts_mean(close, 20)\",\n", + " \"ma_ratio\": \"ts_mean(close, 5) / ts_mean(close, 20) - 1\",\n", + " # 2. 波动率因子\n", + " \"volatility_5\": \"ts_std(close, 5)\",\n", + " \"volatility_20\": \"ts_std(close, 20)\",\n", + " \"vol_ratio\": \"ts_std(close, 5) / (ts_std(close, 20) + 1e-8)\",\n", + " # 3. 收益率动量因子\n", + " \"return_10\": \"(close / ts_delay(close, 10)) - 1\",\n", + " \"return_20\": \"(close / ts_delay(close, 20)) - 1\",\n", + " # 4. 收益率变化因子\n", + " \"return_diff\": \"(close / ts_delay(close, 5)) - 1 - ((close / ts_delay(close, 10)) - 1)\",\n", + " # 5. 成交量因子\n", + " \"vol_ma5\": \"ts_mean(vol, 5)\",\n", + " \"vol_ma20\": \"ts_mean(vol, 20)\",\n", + " \"vol_ratio\": \"ts_mean(vol, 5) / (ts_mean(vol, 20) + 1e-8)\",\n", + " # 6. 市值因子(截面排名)\n", + " \"market_cap_rank\": \"cs_rank(total_mv)\",\n", + " # 7. 价格位置因子\n", + " \"high_low_ratio\": \"(close - ts_min(low, 20)) / (ts_max(high, 20) - ts_min(low, 20) + 1e-8)\",\n", + " \"n_income\": \"cs_rank(n_income)\",\n", + "}\n", + "\n", + "# Label 因子定义(不参与训练,用于计算目标)\n", + "LABEL_FACTOR = {\n", + " \"return_5\": \"(ts_delay(close, -5) / close) - 1\", # 未来5日收益率\n", + "}" + ], + "outputs": [], + "execution_count": 3 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3.2 训练参数配置" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:54:34.069686Z", + "start_time": "2026-03-05T15:54:34.065755Z" + } + }, + "source": [ + "# 日期范围配置\n", + "TRAIN_START = \"20200101\"\n", + "TRAIN_END = \"20241231\"\n", + "TEST_START = \"20250101\"\n", + "TEST_END = \"20251231\"\n", + "\n", + "# 模型参数配置\n", + "MODEL_PARAMS = {\n", + " \"objective\": \"regression\",\n", + " \"metric\": \"mae\", # 改为 MAE,对异常值更稳健\n", + " # 树结构控制(防过拟合核心)\n", + " \"num_leaves\": 20, # 从31降为20,降低模型复杂度\n", + " \"max_depth\": 4, # 显式限制深度,防止过度拟合噪声\n", + " \"min_child_samples\": 50, # 叶子最小样本数,防止学习极端样本\n", + " \"min_child_weight\": 0.001,\n", + " # 学习参数\n", + " \"learning_rate\": 0.01, # 降低学习率,配合更多树\n", + " \"n_estimators\": 1000, # 增加树数量,配合早停\n", + " # 采样策略(关键防过拟合)\n", + " \"subsample\": 0.8, # 每棵树随机采样80%数据(行采样)\n", + " \"subsample_freq\": 5, # 每5轮迭代进行一次 subsample\n", + " \"colsample_bytree\": 0.8, # 每棵树随机选择80%特征(列采样)\n", + " # 正则化\n", + " \"reg_alpha\": 0.1, # L1正则,增加稀疏性\n", + " \"reg_lambda\": 1.0, # L2正则,平滑权重\n", + " # 数值稳定性\n", + " \"verbose\": -1,\n", + " \"random_state\": 42,\n", + "}\n", + "\n", + "# 数据处理器配置\n", + "PROCESSOR_CONFIGS = [\n", + " {\"name\": \"winsorizer\", \"params\": {\"lower\": 0.01, \"upper\": 0.99}},\n", + " {\"name\": \"cs_standard_scaler\", \"params\": {}},\n", + "]\n", + "\n", + "# 股票池筛选配置\n", + "STOCK_FILTER_CONFIG = {\n", + " \"exclude_cyb\": True, # 排除创业板\n", + " \"exclude_kcb\": True, # 排除科创板\n", + " \"exclude_bj\": True, # 排除北交所\n", + " \"exclude_st\": True, # 排除ST股票\n", + "}\n", + "\n", + "# 输出配置(相对于本文件所在目录)\n", + "OUTPUT_DIR = \"output\"\n", + "SAVE_PREDICTIONS = True\n", + "PERSIST_MODEL = False" + ], + "outputs": [], + "execution_count": 4 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. 训练流程\n", + "\n", + "### 4.1 初始化组件" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:54:39.199834Z", + "start_time": "2026-03-05T15:54:34.082579Z" + } + }, + "source": [ + "print(\"\\n\" + \"=\" * 80)\n", + "print(\"LightGBM 回归模型训练\")\n", + "print(\"=\" * 80)\n", + "\n", + "# 1. 创建 FactorEngine\n", + "print(\"\\n[1] 创建 FactorEngine\")\n", + "engine = FactorEngine()\n", + "\n", + "# 2. 使用字符串表达式定义因子\n", + "print(\"\\n[2] 定义因子(字符串表达式)\")\n", + "feature_cols = create_factors_with_strings(engine, FACTOR_DEFINITIONS, LABEL_FACTOR)\n", + "target_col = \"return_5\"\n", + "\n", + "# 3. 准备数据(使用模块级别的日期配置)\n", + "print(\"\\n[3] 准备数据\")\n", + "\n", + "data = prepare_data(\n", + " engine=engine,\n", + " feature_cols=feature_cols,\n", + " start_date=TRAIN_START,\n", + " end_date=TEST_END,\n", + ")\n", + "\n", + "# 4. 打印配置信息\n", + "print(f\"\\n[配置] 训练期: {TRAIN_START} - {TRAIN_END}\")\n", + "print(f\"[配置] 测试期: {TEST_START} - {TEST_END}\")\n", + "print(f\"[配置] 特征数: {len(feature_cols)}\")\n", + "print(f\"[配置] 目标变量: {target_col}\")\n", + "\n", + "# 5. 创建模型\n", + "model = LightGBMModel(params=MODEL_PARAMS)\n", + "\n", + "# 6. 创建数据处理器\n", + "processors = [\n", + " NullFiller(strategy=\"mean\"),\n", + " Winsorizer(**PROCESSOR_CONFIGS[0][\"params\"]),\n", + " StandardScaler(exclude_cols=[\"ts_code\", \"trade_date\", target_col]),\n", + "]\n", + "\n", + "# 7. 创建数据划分器\n", + "splitter = DateSplitter(\n", + " train_start=TRAIN_START,\n", + " train_end=TRAIN_END,\n", + " test_start=TEST_START,\n", + " test_end=TEST_END,\n", + ")\n", + "\n", + "# 8. 创建股票池管理器\n", + "pool_manager = StockPoolManager(\n", + " filter_config=StockFilterConfig(**STOCK_FILTER_CONFIG),\n", + " selector_config=None, # 暂时不启用市值选择\n", + " data_router=engine.router,\n", + ")\n", + "\n", + "# 9. 创建 ST 股票过滤器\n", + "st_filter = STFilter(\n", + " data_router=engine.router,\n", + ")\n", + "\n", + "# 10. 创建训练器\n", + "trainer = Trainer(\n", + " model=model,\n", + " pool_manager=pool_manager,\n", + " processors=processors,\n", + " filters=[st_filter],\n", + " splitter=splitter,\n", + " target_col=target_col,\n", + " feature_cols=feature_cols,\n", + " persist_model=PERSIST_MODEL,\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "================================================================================\n", + "LightGBM 回归模型训练\n", + "================================================================================\n", + "\n", + "[1] 创建 FactorEngine\n", + "\n", + "[2] 定义因子(字符串表达式)\n", + "================================================================================\n", + "使用字符串表达式定义因子\n", + "================================================================================\n", + "\n", + "注册特征因子:\n", + " - ma5: ts_mean(close, 5)\n", + " - ma10: ts_mean(close, 10)\n", + " - ma20: ts_mean(close, 20)\n", + " - ma_ratio: ts_mean(close, 5) / ts_mean(close, 20) - 1\n", + " - volatility_5: ts_std(close, 5)\n", + " - volatility_20: ts_std(close, 20)\n", + " - vol_ratio: ts_mean(vol, 5) / (ts_mean(vol, 20) + 1e-8)\n", + " - return_10: (close / ts_delay(close, 10)) - 1\n", + " - return_20: (close / ts_delay(close, 20)) - 1\n", + " - return_diff: (close / ts_delay(close, 5)) - 1 - ((close / ts_delay(close, 10)) - 1)\n", + " - vol_ma5: ts_mean(vol, 5)\n", + " - vol_ma20: ts_mean(vol, 20)\n", + " - market_cap_rank: cs_rank(total_mv)\n", + " - high_low_ratio: (close - ts_min(low, 20)) / (ts_max(high, 20) - ts_min(low, 20) + 1e-8)\n", + " - n_income: cs_rank(n_income)\n", + "\n", + "注册 Label 因子:\n", + " - return_5: (ts_delay(close, -5) / close) - 1\n", + "\n", + "特征因子数: 15\n", + "Label: return_5\n", + "已注册因子总数: 16\n", + "\n", + "[3] 准备数据\n", + "\n", + "================================================================================\n", + "准备数据\n", + "================================================================================\n", + "\n", + "计算因子: 20200101 - 20251231\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "D:\\PyProject\\ProStock\\src\\data\\financial_loader.py:123: UserWarning: Sortedness of columns cannot be checked when 'by' groups provided\n", + " merged = df_price.join_asof(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "数据形状: (7044952, 24)\n", + "数据列: ['ts_code', 'trade_date', 'high', 'vol', 'close', 'low', 'total_mv', 'f_ann_date', 'n_income', 'ma5', 'ma10', 'ma20', 'ma_ratio', 'volatility_5', 'volatility_20', 'vol_ratio', 'return_10', 'return_20', 'return_diff', 'vol_ma5', 'vol_ma20', 'market_cap_rank', 'high_low_ratio', 'return_5']\n", + "\n", + "前5行预览:\n", + "shape: (5, 24)\n", + "┌───────────┬────────────┬─────────┬───────────┬───┬──────────┬────────────┬───────────┬───────────┐\n", + "│ ts_code ┆ trade_date ┆ high ┆ vol ┆ … ┆ vol_ma20 ┆ market_cap ┆ high_low_ ┆ return_5 │\n", + "│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ _rank ┆ ratio ┆ --- │\n", + "│ str ┆ str ┆ f64 ┆ f64 ┆ ┆ f64 ┆ --- ┆ --- ┆ f64 │\n", + "│ ┆ ┆ ┆ ┆ ┆ ┆ f64 ┆ f64 ┆ │\n", + "╞═══════════╪════════════╪═════════╪═══════════╪═══╪══════════╪════════════╪═══════════╪═══════════╡\n", + "│ 000001.SZ ┆ 20200102 ┆ 1850.42 ┆ 1.5302e6 ┆ … ┆ null ┆ 0.993583 ┆ null ┆ -0.004746 │\n", + "│ 000001.SZ ┆ 20200103 ┆ 1889.72 ┆ 1.1162e6 ┆ … ┆ null ┆ 0.993585 ┆ null ┆ -0.02852 │\n", + "│ 000001.SZ ┆ 20200106 ┆ 1893.0 ┆ 862083.5 ┆ … ┆ null ┆ 0.993588 ┆ null ┆ -0.004685 │\n", + "│ 000001.SZ ┆ 20200107 ┆ 1886.45 ┆ 728607.56 ┆ … ┆ null ┆ 0.993588 ┆ null ┆ -0.022743 │\n", + "│ 000001.SZ ┆ 20200108 ┆ 1861.34 ┆ 847824.12 ┆ … ┆ null ┆ 0.993586 ┆ null ┆ -0.008401 │\n", + "└───────────┴────────────┴─────────┴───────────┴───┴──────────┴────────────┴───────────┴───────────┘\n", + "\n", + "[配置] 训练期: 20200101 - 20241231\n", + "[配置] 测试期: 20250101 - 20251231\n", + "[配置] 特征数: 15\n", + "[配置] 目标变量: return_5\n" + ] + } + ], + "execution_count": 5 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.2 执行训练" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:54:45.542301Z", + "start_time": "2026-03-05T15:54:39.210579Z" + } + }, + "source": [ + "print(\"\\n\" + \"=\" * 80)\n", + "print(\"开始训练\")\n", + "print(\"=\" * 80)\n", + "\n", + "# 步骤 1: 股票池筛选\n", + "print(\"\\n[步骤 1/6] 股票池筛选\")\n", + "print(\"-\" * 60)\n", + "if pool_manager:\n", + " print(\" 执行每日独立筛选股票池...\")\n", + " filtered_data = pool_manager.filter_and_select_daily(data)\n", + " print(f\" 筛选前数据规模: {data.shape}\")\n", + " print(f\" 筛选后数据规模: {filtered_data.shape}\")\n", + " print(f\" 筛选前股票数: {data['ts_code'].n_unique()}\")\n", + " print(f\" 筛选后股票数: {filtered_data['ts_code'].n_unique()}\")\n", + " print(f\" 删除记录数: {len(data) - len(filtered_data)}\")\n", + "else:\n", + " filtered_data = data\n", + " print(\" 未配置股票池管理器,跳过筛选\")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "================================================================================\n", + "开始训练\n", + "================================================================================\n", + "\n", + "[步骤 1/6] 股票池筛选\n", + "------------------------------------------------------------\n", + " 执行每日独立筛选股票池...\n", + " 筛选前数据规模: (7044952, 24)\n", + " 筛选后数据规模: (4532198, 24)\n", + " 筛选前股票数: 5678\n", + " 筛选后股票数: 3359\n", + " 删除记录数: 2512754\n" + ] + } + ], + "execution_count": 6 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:54:46.133946Z", + "start_time": "2026-03-05T15:54:45.552454Z" + } + }, + "source": [ + "# 步骤 2: 划分训练/测试集\n", + "print(\"\\n[步骤 2/6] 划分训练集和测试集\")\n", + "print(\"-\" * 60)\n", + "if splitter:\n", + " train_data, test_data = splitter.split(filtered_data)\n", + " print(f\" 训练集数据规模: {train_data.shape}\")\n", + " print(f\" 测试集数据规模: {test_data.shape}\")\n", + " print(f\" 训练集股票数: {train_data['ts_code'].n_unique()}\")\n", + " print(f\" 测试集股票数: {test_data['ts_code'].n_unique()}\")\n", + " print(\n", + " f\" 训练集日期范围: {train_data['trade_date'].min()} - {train_data['trade_date'].max()}\"\n", + " )\n", + " print(\n", + " f\" 测试集日期范围: {test_data['trade_date'].min()} - {test_data['trade_date'].max()}\"\n", + " )\n", + "\n", + " print(\"\\n 训练集前5行预览:\")\n", + " print(train_data.head())\n", + " print(\"\\n 测试集前5行预览:\")\n", + " print(test_data.head())\n", + "else:\n", + " train_data = filtered_data\n", + " test_data = filtered_data\n", + " print(\" 未配置划分器,全部作为训练集\")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "[步骤 2/6] 划分训练集和测试集\n", + "------------------------------------------------------------\n", + " 训练集数据规模: (3760991, 24)\n", + " 测试集数据规模: (771207, 24)\n", + " 训练集股票数: 3321\n", + " 测试集股票数: 3215\n", + " 训练集日期范围: 20200102 - 20241231\n", + " 测试集日期范围: 20250102 - 20251231\n", + "\n", + " 训练集前5行预览:\n", + "shape: (5, 24)\n", + "┌───────────┬────────────┬─────────┬───────────┬───┬──────────┬────────────┬───────────┬───────────┐\n", + "│ ts_code ┆ trade_date ┆ high ┆ vol ┆ … ┆ vol_ma20 ┆ market_cap ┆ high_low_ ┆ return_5 │\n", + "│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ _rank ┆ ratio ┆ --- │\n", + "│ str ┆ str ┆ f64 ┆ f64 ┆ ┆ f64 ┆ --- ┆ --- ┆ f64 │\n", + "│ ┆ ┆ ┆ ┆ ┆ ┆ f64 ┆ f64 ┆ │\n", + "╞═══════════╪════════════╪═════════╪═══════════╪═══╪══════════╪════════════╪═══════════╪═══════════╡\n", + "│ 000001.SZ ┆ 20200102 ┆ 1850.42 ┆ 1.5302e6 ┆ … ┆ null ┆ 0.993583 ┆ null ┆ -0.004746 │\n", + "│ 000002.SZ ┆ 20200102 ┆ 4986.64 ┆ 1012130.4 ┆ … ┆ null ┆ 0.99492 ┆ null ┆ -0.011057 │\n", + "│ 000004.SZ ┆ 20200102 ┆ 93.06 ┆ 17853.2 ┆ … ┆ null ┆ 0.057219 ┆ null ┆ -0.000441 │\n", + "│ 000005.SZ ┆ 20200102 ┆ 29.19 ┆ 104134.12 ┆ … ┆ null ┆ 0.28984 ┆ null ┆ 0.022337 │\n", + "│ 000006.SZ ┆ 20200102 ┆ 193.07 ┆ 124751.76 ┆ … ┆ null ┆ 0.631551 ┆ null ┆ 0.012964 │\n", + "└───────────┴────────────┴─────────┴───────────┴───┴──────────┴────────────┴───────────┴───────────┘\n", + "\n", + " 测试集前5行预览:\n", + "shape: (5, 24)\n", + "┌───────────┬────────────┬─────────┬───────────┬───┬───────────┬───────────┬───────────┬───────────┐\n", + "│ ts_code ┆ trade_date ┆ high ┆ vol ┆ … ┆ vol_ma20 ┆ market_ca ┆ high_low_ ┆ return_5 │\n", + "│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ p_rank ┆ ratio ┆ --- │\n", + "│ str ┆ str ┆ f64 ┆ f64 ┆ ┆ f64 ┆ --- ┆ --- ┆ f64 │\n", + "│ ┆ ┆ ┆ ┆ ┆ ┆ f64 ┆ f64 ┆ │\n", + "╞═══════════╪════════════╪═════════╪═══════════╪═══╪═══════════╪═══════════╪═══════════╪═══════════╡\n", + "│ 000001.SZ ┆ 20250102 ┆ 1504.02 ┆ 1.8196e6 ┆ … ┆ 1.2151e6 ┆ 0.991617 ┆ 0.063478 ┆ -0.002622 │\n", + "│ 000002.SZ ┆ 20250102 ┆ 1337.34 ┆ 1.1827e6 ┆ … ┆ 1.2839e6 ┆ 0.970007 ┆ 0.020839 ┆ -0.022509 │\n", + "│ 000004.SZ ┆ 20250102 ┆ 58.48 ┆ 119760.37 ┆ … ┆ 159807.91 ┆ 0.099106 ┆ 0.131858 ┆ -0.064897 │\n", + "│ ┆ ┆ ┆ ┆ ┆ 8 ┆ ┆ ┆ │\n", + "│ 000006.SZ ┆ 20250102 ┆ 298.84 ┆ 307195.1 ┆ … ┆ 404264.21 ┆ 0.72392 ┆ 0.028423 ┆ -0.048278 │\n", + "│ ┆ ┆ ┆ ┆ ┆ 1 ┆ ┆ ┆ │\n", + "│ 000007.SZ ┆ 20250102 ┆ 60.22 ┆ 68219.01 ┆ … ┆ 88380.284 ┆ 0.183495 ┆ 0.391829 ┆ 0.015649 │\n", + "│ ┆ ┆ ┆ ┆ ┆ 5 ┆ ┆ ┆ │\n", + "└───────────┴────────────┴─────────┴───────────┴───┴───────────┴───────────┴───────────┴───────────┘\n" + ] + } + ], + "execution_count": 7 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:54:46.983171Z", + "start_time": "2026-03-05T15:54:46.145439Z" + } + }, + "source": [ + "# 步骤 3: 训练集数据处理\n", + "print(\"\\n[步骤 3/6] 训练集数据处理\")\n", + "print(\"-\" * 60)\n", + "fitted_processors = []\n", + "if processors:\n", + " for i, processor in enumerate(processors, 1):\n", + " print(\n", + " f\" [{i}/{len(processors)}] 应用处理器: {processor.__class__.__name__}\"\n", + " )\n", + " train_data_before = len(train_data)\n", + " train_data = processor.fit_transform(train_data)\n", + " train_data_after = len(train_data)\n", + " fitted_processors.append(processor)\n", + " print(f\" 处理前记录数: {train_data_before}\")\n", + " print(f\" 处理后记录数: {train_data_after}\")\n", + " if train_data_before != train_data_after:\n", + " print(f\" 删除记录数: {train_data_before - train_data_after}\")\n", + "\n", + "print(\"\\n 训练集处理后前5行预览:\")\n", + "print(train_data.head())\n", + "print(f\"\\n 训练集特征统计:\")\n", + "print(f\" 特征数: {len(feature_cols)}\")\n", + "print(f\" 样本数: {len(train_data)}\")\n", + "print(f\" 缺失值统计:\")\n", + "for col in feature_cols[:5]: # 只显示前5个特征的缺失值\n", + " null_count = train_data[col].null_count()\n", + " if null_count > 0:\n", + " print(\n", + " f\" {col}: {null_count} ({null_count / len(train_data) * 100:.2f}%)\"\n", + " )" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "[步骤 3/6] 训练集数据处理\n", + "------------------------------------------------------------\n", + " [1/3] 应用处理器: NullFiller\n", + " 处理前记录数: 3760991\n", + " 处理后记录数: 3760991\n", + " [2/3] 应用处理器: Winsorizer\n", + " 处理前记录数: 3760991\n", + " 处理后记录数: 3760991\n", + " [3/3] 应用处理器: StandardScaler\n", + " 处理前记录数: 3760991\n", + " 处理后记录数: 3760991\n", + "\n", + " 训练集处理后前5行预览:\n", + "shape: (5, 24)\n", + "┌───────────┬────────────┬──────────┬───────────┬───┬──────────┬───────────┬───────────┬───────────┐\n", + "│ ts_code ┆ trade_date ┆ high ┆ vol ┆ … ┆ vol_ma20 ┆ market_ca ┆ high_low_ ┆ return_5 │\n", + "│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ p_rank ┆ ratio ┆ --- │\n", + "│ str ┆ str ┆ f64 ┆ f64 ┆ ┆ f64 ┆ --- ┆ --- ┆ f64 │\n", + "│ ┆ ┆ ┆ ┆ ┆ ┆ f64 ┆ f64 ┆ │\n", + "╞═══════════╪════════════╪══════════╪═══════════╪═══╪══════════╪═══════════╪═══════════╪═══════════╡\n", + "│ 000001.SZ ┆ 20200102 ┆ 7.219126 ┆ 4.505425 ┆ … ┆ null ┆ 1.579213 ┆ null ┆ -0.004746 │\n", + "│ 000002.SZ ┆ 20200102 ┆ 7.219126 ┆ 2.764839 ┆ … ┆ null ┆ 1.579213 ┆ null ┆ -0.011057 │\n", + "│ 000004.SZ ┆ 20200102 ┆ 0.115067 ┆ -0.575482 ┆ … ┆ null ┆ -1.671014 ┆ null ┆ -0.000441 │\n", + "│ 000005.SZ ┆ 20200102 ┆ -0.29753 ┆ -0.285617 ┆ … ┆ null ┆ -0.862878 ┆ null ┆ 0.022337 │\n", + "│ 000006.SZ ┆ 20200102 ┆ 0.761125 ┆ -0.216351 ┆ … ┆ null ┆ 0.324248 ┆ null ┆ 0.012964 │\n", + "└───────────┴────────────┴──────────┴───────────┴───┴──────────┴───────────┴───────────┴───────────┘\n", + "\n", + " 训练集特征统计:\n", + " 特征数: 15\n", + " 样本数: 3760991\n", + " 缺失值统计:\n", + " ma5: 11541 (0.31%)\n", + " ma10: 25950 (0.69%)\n", + " ma20: 54850 (1.46%)\n", + " ma_ratio: 54850 (1.46%)\n", + " volatility_5: 11541 (0.31%)\n" + ] + } + ], + "execution_count": 8 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:55:04.341897Z", + "start_time": "2026-03-05T15:54:46.988330Z" + } + }, + "source": [ + "# 步骤 4: 训练模型\n", + "print(\"\\n[步骤 4/6] 训练模型\")\n", + "print(\"-\" * 60)\n", + "print(f\" 模型类型: LightGBM\")\n", + "print(f\" 训练样本数: {len(train_data)}\")\n", + "print(f\" 特征数: {len(feature_cols)}\")\n", + "print(f\" 目标变量: {target_col}\")\n", + "\n", + "X_train = train_data.select(feature_cols)\n", + "y_train = train_data.select(target_col).to_series()\n", + "\n", + "print(f\"\\n 目标变量统计:\")\n", + "print(f\" 均值: {y_train.mean():.6f}\")\n", + "print(f\" 标准差: {y_train.std():.6f}\")\n", + "print(f\" 最小值: {y_train.min():.6f}\")\n", + "print(f\" 最大值: {y_train.max():.6f}\")\n", + "print(f\" 缺失值: {y_train.null_count()}\")\n", + "\n", + "print(\"\\n 开始训练...\")\n", + "model.fit(X_train, y_train)\n", + "print(\" 训练完成!\")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "[步骤 4/6] 训练模型\n", + "------------------------------------------------------------\n", + " 模型类型: LightGBM\n", + " 训练样本数: 3760991\n", + " 特征数: 15\n", + " 目标变量: return_5\n", + "\n", + " 目标变量统计:\n", + " 均值: 0.001511\n", + " 标准差: 0.062515\n", + " 最小值: -0.165141\n", + " 最大值: 0.225065\n", + " 缺失值: 0\n", + "\n", + " 开始训练...\n", + " 训练完成!\n" + ] + } + ], + "execution_count": 9 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:55:04.405805Z", + "start_time": "2026-03-05T15:55:04.349104Z" + } + }, + "source": [ + "# 步骤 5: 测试集数据处理\n", + "print(\"\\n[步骤 5/6] 测试集数据处理\")\n", + "print(\"-\" * 60)\n", + "if processors and test_data is not train_data:\n", + " for i, processor in enumerate(fitted_processors, 1):\n", + " print(\n", + " f\" [{i}/{len(fitted_processors)}] 应用处理器: {processor.__class__.__name__}\"\n", + " )\n", + " test_data_before = len(test_data)\n", + " test_data = processor.transform(test_data)\n", + " test_data_after = len(test_data)\n", + " print(f\" 处理前记录数: {test_data_before}\")\n", + " print(f\" 处理后记录数: {test_data_after}\")\n", + "else:\n", + " print(\" 跳过测试集处理\")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "[步骤 5/6] 测试集数据处理\n", + "------------------------------------------------------------\n", + " [1/3] 应用处理器: NullFiller\n", + " 处理前记录数: 771207\n", + " 处理后记录数: 771207\n", + " [2/3] 应用处理器: Winsorizer\n", + " 处理前记录数: 771207\n", + " 处理后记录数: 771207\n", + " [3/3] 应用处理器: StandardScaler\n", + " 处理前记录数: 771207\n", + " 处理后记录数: 771207\n" + ] + } + ], + "execution_count": 10 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:55:05.493456Z", + "start_time": "2026-03-05T15:55:04.412467Z" + } + }, + "source": [ + "# 步骤 6: 生成预测\n", + "print(\"\\n[步骤 6/6] 生成预测\")\n", + "print(\"-\" * 60)\n", + "X_test = test_data.select(feature_cols)\n", + "print(f\" 测试样本数: {len(X_test)}\")\n", + "print(\" 预测中...\")\n", + "predictions = model.predict(X_test)\n", + "print(f\" 预测完成!\")\n", + "\n", + "print(f\"\\n 预测结果统计:\")\n", + "print(f\" 均值: {predictions.mean():.6f}\")\n", + "print(f\" 标准差: {predictions.std():.6f}\")\n", + "print(f\" 最小值: {predictions.min():.6f}\")\n", + "print(f\" 最大值: {predictions.max():.6f}\")\n", + "\n", + "# 保存结果到 trainer\n", + "trainer.results = test_data.with_columns([pl.Series(\"prediction\", predictions)])" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "[步骤 6/6] 生成预测\n", + "------------------------------------------------------------\n", + " 测试样本数: 771207\n", + " 预测中...\n", + " 预测完成!\n", + "\n", + " 预测结果统计:\n", + " 均值: 0.000637\n", + " 标准差: 0.006533\n", + " 最小值: -0.125675\n", + " 最大值: 0.148845\n" + ] + } + ], + "execution_count": 11 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.3 查看结果" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:55:05.517099Z", + "start_time": "2026-03-05T15:55:05.500111Z" + } + }, + "source": [ + "print(\"\\n\" + \"=\" * 80)\n", + "print(\"训练结果\")\n", + "print(\"=\" * 80)\n", + "\n", + "results = trainer.results\n", + "\n", + "print(f\"\\n结果数据形状: {results.shape}\")\n", + "print(f\"结果列: {results.columns}\")\n", + "print(f\"\\n结果前10行预览:\")\n", + "print(results.head(10))\n", + "print(f\"\\n结果后5行预览:\")\n", + "print(results.tail())\n", + "\n", + "print(f\"\\n每日预测样本数统计:\")\n", + "daily_counts = results.group_by(\"trade_date\").agg(pl.len()).sort(\"trade_date\")\n", + "print(f\" 最小: {daily_counts['len'].min()}\")\n", + "print(f\" 最大: {daily_counts['len'].max()}\")\n", + "print(f\" 平均: {daily_counts['len'].mean():.2f}\")\n", + "\n", + "# 展示某一天的前10个预测结果\n", + "sample_date = results[\"trade_date\"][0]\n", + "sample_data = results.filter(results[\"trade_date\"] == sample_date).head(10)\n", + "print(f\"\\n示例日期 {sample_date} 的前10条预测:\")\n", + "print(sample_data.select([\"ts_code\", \"trade_date\", target_col, \"prediction\"]))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "================================================================================\n", + "训练结果\n", + "================================================================================\n", + "\n", + "结果数据形状: (771207, 25)\n", + "结果列: ['ts_code', 'trade_date', 'high', 'vol', 'close', 'low', 'total_mv', 'f_ann_date', 'n_income', 'ma5', 'ma10', 'ma20', 'ma_ratio', 'volatility_5', 'volatility_20', 'vol_ratio', 'return_10', 'return_20', 'return_diff', 'vol_ma5', 'vol_ma20', 'market_cap_rank', 'high_low_ratio', 'return_5', 'prediction']\n", + "\n", + "结果前10行预览:\n", + "shape: (10, 25)\n", + "┌───────────┬───────────┬───────────┬───────────┬───┬───────────┬───────────┬───────────┬──────────┐\n", + "│ ts_code ┆ trade_dat ┆ high ┆ vol ┆ … ┆ market_ca ┆ high_low_ ┆ return_5 ┆ predicti │\n", + "│ --- ┆ e ┆ --- ┆ --- ┆ ┆ p_rank ┆ ratio ┆ --- ┆ on │\n", + "│ str ┆ --- ┆ f64 ┆ f64 ┆ ┆ --- ┆ --- ┆ f64 ┆ --- │\n", + "│ ┆ str ┆ ┆ ┆ ┆ f64 ┆ f64 ┆ ┆ f64 │\n", + "╞═══════════╪═══════════╪═══════════╪═══════════╪═══╪═══════════╪═══════════╪═══════════╪══════════╡\n", + "│ 000001.SZ ┆ 20250102 ┆ 7.219126 ┆ 5.477561 ┆ … ┆ 1.575139 ┆ -1.347097 ┆ -0.002622 ┆ -0.00447 │\n", + "│ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 3 │\n", + "│ 000002.SZ ┆ 20250102 ┆ 7.219126 ┆ 3.337762 ┆ … ┆ 1.500066 ┆ -1.494802 ┆ -0.022509 ┆ -0.00736 │\n", + "│ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 9 │\n", + "│ 000004.SZ ┆ 20250102 ┆ -0.108318 ┆ -0.23312 ┆ … ┆ -1.525498 ┆ -1.110228 ┆ -0.064897 ┆ 0.017464 │\n", + "│ 000006.SZ ┆ 20250102 ┆ 1.444393 ┆ 0.396576 ┆ … ┆ 0.645142 ┆ -1.46853 ┆ -0.048278 ┆ -0.00465 │\n", + "│ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 7 │\n", + "│ 000007.SZ ┆ 20250102 ┆ -0.097078 ┆ -0.406275 ┆ … ┆ -1.232326 ┆ -0.209675 ┆ 0.015649 ┆ -0.00109 │\n", + "│ 000008.SZ ┆ 20250102 ┆ -0.054701 ┆ 3.045596 ┆ … ┆ 0.410216 ┆ -1.48541 ┆ -0.066939 ┆ -0.00931 │\n", + "│ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 9 │\n", + "│ 000009.SZ ┆ 20250102 ┆ 0.045687 ┆ 0.167823 ┆ … ┆ 1.197186 ┆ -1.358101 ┆ -0.036045 ┆ 0.001988 │\n", + "│ 000010.SZ ┆ 20250102 ┆ -0.289132 ┆ 0.530622 ┆ … ┆ -0.872494 ┆ -1.382331 ┆ 0.092123 ┆ -0.00750 │\n", + "│ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 5 │\n", + "│ 000011.SZ ┆ 20250102 ┆ -0.233641 ┆ -0.493267 ┆ … ┆ -0.098467 ┆ -1.409992 ┆ -0.022094 ┆ -0.00158 │\n", + "│ ┆ ┆ ┆ ┆ ┆ ┆ ┆ ┆ 6 │\n", + "│ 000012.SZ ┆ 20250102 ┆ 0.540518 ┆ -0.084753 ┆ … ┆ 1.006268 ┆ -1.411495 ┆ -0.029188 ┆ 0.000647 │\n", + "└───────────┴───────────┴───────────┴───────────┴───┴───────────┴───────────┴───────────┴──────────┘\n", + "\n", + "结果后5行预览:\n", + "shape: (5, 25)\n", + "┌───────────┬───────────┬───────────┬───────────┬───┬───────────┬───────────┬──────────┬───────────┐\n", + "│ ts_code ┆ trade_dat ┆ high ┆ vol ┆ … ┆ market_ca ┆ high_low_ ┆ return_5 ┆ predictio │\n", + "│ --- ┆ e ┆ --- ┆ --- ┆ ┆ p_rank ┆ ratio ┆ --- ┆ n │\n", + "│ str ┆ --- ┆ f64 ┆ f64 ┆ ┆ --- ┆ --- ┆ f64 ┆ --- │\n", + "│ ┆ str ┆ ┆ ┆ ┆ f64 ┆ f64 ┆ ┆ f64 │\n", + "╞═══════════╪═══════════╪═══════════╪═══════════╪═══╪═══════════╪═══════════╪══════════╪═══════════╡\n", + "│ 605588.SH ┆ 20251231 ┆ -0.155411 ┆ -0.600921 ┆ … ┆ -1.041064 ┆ 0.083361 ┆ null ┆ 0.002664 │\n", + "│ 605589.SH ┆ 20251231 ┆ -0.286677 ┆ -0.172371 ┆ … ┆ 1.082326 ┆ 0.586743 ┆ null ┆ 0.003911 │\n", + "│ 605598.SH ┆ 20251231 ┆ 0.167069 ┆ -0.264286 ┆ … ┆ 0.865913 ┆ 1.46704 ┆ null ┆ -0.004255 │\n", + "│ 605599.SH ┆ 20251231 ┆ -0.361225 ┆ -0.487294 ┆ … ┆ 0.623404 ┆ 1.560273 ┆ null ┆ 0.004604 │\n", + "│ 689009.SH ┆ 20251231 ┆ -0.110062 ┆ -0.485904 ┆ … ┆ 1.304467 ┆ -1.339619 ┆ null ┆ -0.000968 │\n", + "└───────────┴───────────┴───────────┴───────────┴───┴───────────┴───────────┴──────────┴───────────┘\n", + "\n", + "每日预测样本数统计:\n", + " 最小: 3147\n", + " 最大: 3186\n", + " 平均: 3173.69\n", + "\n", + "示例日期 20250102 的前10条预测:\n", + "shape: (10, 4)\n", + "┌───────────┬────────────┬───────────┬────────────┐\n", + "│ ts_code ┆ trade_date ┆ return_5 ┆ prediction │\n", + "│ --- ┆ --- ┆ --- ┆ --- │\n", + "│ str ┆ str ┆ f64 ┆ f64 │\n", + "╞═══════════╪════════════╪═══════════╪════════════╡\n", + "│ 000001.SZ ┆ 20250102 ┆ -0.002622 ┆ -0.004473 │\n", + "│ 000002.SZ ┆ 20250102 ┆ -0.022509 ┆ -0.007369 │\n", + "│ 000004.SZ ┆ 20250102 ┆ -0.064897 ┆ 0.017464 │\n", + "│ 000006.SZ ┆ 20250102 ┆ -0.048278 ┆ -0.004657 │\n", + "│ 000007.SZ ┆ 20250102 ┆ 0.015649 ┆ -0.00109 │\n", + "│ 000008.SZ ┆ 20250102 ┆ -0.066939 ┆ -0.009319 │\n", + "│ 000009.SZ ┆ 20250102 ┆ -0.036045 ┆ 0.001988 │\n", + "│ 000010.SZ ┆ 20250102 ┆ 0.092123 ┆ -0.007505 │\n", + "│ 000011.SZ ┆ 20250102 ┆ -0.022094 ┆ -0.001586 │\n", + "│ 000012.SZ ┆ 20250102 ┆ -0.029188 ┆ 0.000647 │\n", + "└───────────┴────────────┴───────────┴────────────┘\n" + ] + } + ], + "execution_count": 12 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.4 保存结果" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:55:05.827674Z", + "start_time": "2026-03-05T15:55:05.522095Z" + } + }, + "cell_type": "code", + "source": [ + "print(\"\\n\" + \"=\" * 80)\n", + "print(\"保存预测结果\")\n", + "print(\"=\" * 80)\n", + "\n", + "# 确保输出目录存在\n", + "os.makedirs(OUTPUT_DIR, exist_ok=True)\n", + "\n", + "# 生成时间戳\n", + "start_dt = datetime.strptime(TEST_START, \"%Y%m%d\")\n", + "end_dt = datetime.strptime(TEST_END, \"%Y%m%d\")\n", + "date_str = f\"{start_dt.strftime('%Y%m%d')}_{end_dt.strftime('%Y%m%d')}\"\n", + "\n", + "# 保存每日 Top5\n", + "print(\"\\n[1/1] 保存每日 Top5 股票...\")\n", + "top5_output_path = os.path.join(OUTPUT_DIR, f\"top5_{date_str}.csv\")\n", + "\n", + "# 按日期分组,取每日 top5\n", + "top5_by_date = []\n", + "unique_dates = results[\"trade_date\"].unique().sort()\n", + "for date in unique_dates:\n", + " day_data = results.filter(results[\"trade_date\"] == date)\n", + " # 按 prediction 降序排序,取前5\n", + " top5 = day_data.sort(\"prediction\", descending=True).head(5)\n", + " top5_by_date.append(top5)\n", + "\n", + "# 合并所有日期的 top5\n", + "top5_results = pl.concat(top5_by_date)\n", + "\n", + "# 格式化日期并调整列顺序:日期、分数、股票\n", + "top5_to_save = top5_results.select(\n", + " [\n", + " pl.col(\"trade_date\").str.slice(0, 4)\n", + " + \"-\"\n", + " + pl.col(\"trade_date\").str.slice(4, 2)\n", + " + \"-\"\n", + " + pl.col(\"trade_date\").str.slice(6, 2).alias(\"date\"),\n", + " pl.col(\"prediction\").alias(\"score\"),\n", + " pl.col(\"ts_code\"),\n", + " ]\n", + ")\n", + "# top5_to_save.write_csv(top5_output_path, include_header=True)\n", + "print(f\" 保存路径: {top5_output_path}\")\n", + "print(f\" 保存行数: {len(top5_to_save)}({len(unique_dates)}个交易日 × 每日top5)\")\n", + "print(f\"\\n 预览(前15行):\")\n", + "print(top5_to_save.head(15))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "================================================================================\n", + "保存预测结果\n", + "================================================================================\n", + "\n", + "[1/1] 保存每日 Top5 股票...\n", + " 保存路径: output\\top5_20250101_20251231.csv\n", + " 保存行数: 1215(243个交易日 × 每日top5)\n", + "\n", + " 预览(前15行):\n", + "shape: (15, 3)\n", + "┌────────────┬──────────┬───────────┐\n", + "│ trade_date ┆ score ┆ ts_code │\n", + "│ --- ┆ --- ┆ --- │\n", + "│ str ┆ f64 ┆ str │\n", + "╞════════════╪══════════╪═══════════╡\n", + "│ 2025-01-02 ┆ 0.130576 ┆ 603007.SH │\n", + "│ 2025-01-02 ┆ 0.088839 ┆ 603559.SH │\n", + "│ 2025-01-02 ┆ 0.060968 ┆ 000595.SZ │\n", + "│ 2025-01-02 ┆ 0.054302 ┆ 600811.SH │\n", + "│ 2025-01-02 ┆ 0.045811 ┆ 603366.SH │\n", + "│ … ┆ … ┆ … │\n", + "│ 2025-01-06 ┆ 0.143688 ┆ 603007.SH │\n", + "│ 2025-01-06 ┆ 0.063078 ┆ 002691.SZ │\n", + "│ 2025-01-06 ┆ 0.062373 ┆ 603959.SH │\n", + "│ 2025-01-06 ┆ 0.055252 ┆ 000638.SZ │\n", + "│ 2025-01-06 ┆ 0.047705 ┆ 002713.SZ │\n", + "└────────────┴──────────┴───────────┘\n" + ] + } + ], + "execution_count": 13 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.5 特征重要性" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:55:05.840200Z", + "start_time": "2026-03-05T15:55:05.836355Z" + } + }, + "source": [ + "importance = model.feature_importance()\n", + "if importance is not None:\n", + " print(\"\\n特征重要性:\")\n", + " print(importance.sort_values(ascending=False))\n", + "\n", + "print(\"\\n\" + \"=\" * 80)\n", + "print(\"训练完成!\")\n", + "print(\"=\" * 80)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "特征重要性:\n", + "return_10 3244.585386\n", + "ma_ratio 2871.645070\n", + "return_20 2686.807540\n", + "vol_ratio 2667.200664\n", + "high_low_ratio 2461.679219\n", + "return_diff 1491.578852\n", + "volatility_5 1360.579366\n", + "market_cap_rank 697.769018\n", + "vol_ma5 665.639110\n", + "vol_ma20 640.332628\n", + "n_income 536.010082\n", + "ma5 489.527820\n", + "ma20 481.715007\n", + "ma10 303.121463\n", + "volatility_20 224.481188\n", + "dtype: float64\n", + "\n", + "================================================================================\n", + "训练完成!\n", + "================================================================================\n" + ] + } + ], + "execution_count": 14 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. 可视化分析\n", + "\n", + "使用训练好的模型直接绘图。\n", + "- **特征重要性图**:辅助特征选择\n", + "- **决策树图**:理解决策逻辑" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:55:06.004470Z", + "start_time": "2026-03-05T15:55:05.857163Z" + } + }, + "source": [ + "# 导入可视化库\n", + "import matplotlib.pyplot as plt\n", + "import lightgbm as lgb\n", + "import pandas as pd\n", + "\n", + "# 从封装的model中取出底层Booster\n", + "booster = model.model\n", + "print(f\"模型类型: {type(booster)}\")\n", + "print(f\"特征数量: {len(feature_cols)}\")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "模型类型: \n", + "特征数量: 15\n" + ] + } + ], + "execution_count": 15 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.1 绘制特征重要性(辅助特征选择)\n", + "\n", + "**解读**:\n", + "- 重要性高的特征对模型贡献大\n", + "- 重要性为0的特征可以考虑删除\n", + "- 可以帮助理解哪些因子最有效" + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-03-05T15:55:06.162872Z", + "start_time": "2026-03-05T15:55:06.013403Z" + } + }, + "cell_type": "code", + "source": [ + "print(\"绘制特征重要性...\")\n", + "\n", + "fig, ax = plt.subplots(figsize=(10, 8))\n", + "lgb.plot_importance(\n", + " booster, \n", + " max_num_features=20,\n", + " importance_type='gain',\n", + " title='Feature Importance (Gain)',\n", + " ax=ax\n", + ")\n", + "ax.set_xlabel('Importance (Gain)')\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "# 打印重要性排名\n", + "importance_gain = pd.Series(\n", + " booster.feature_importance(importance_type='gain'),\n", + " index=feature_cols\n", + ").sort_values(ascending=False)\n", + "\n", + "print(\"\\n[特征重要性排名 - Gain]\")\n", + "print(importance_gain)\n", + "\n", + "# 识别低重要性特征\n", + "zero_importance = importance_gain[importance_gain == 0].index.tolist()\n", + "if zero_importance:\n", + " print(f\"\\n[低重要性特征] 以下{len(zero_importance)}个特征重要性为0,可考虑删除:\")\n", + " for feat in zero_importance:\n", + " print(f\" - {feat}\")\n", + "else:\n", + " print(\"\\n所有特征都有一定重要性\")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "绘制特征重要性...\n" + ] + }, + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9wAAAMWCAYAAAADI47PAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAwwhJREFUeJzs3QmcTfX/x/EPYydrWZLsIktEVEQlEUkbKpKoVFJZSkqSiFCURLtSWlW0SipptYQolFCSrWxFGGb+j/f39zj3f+fOvWO2Y2bOvJ6PxzXm3HPPPXO/c++cz/fz+X6/eRITExMNAAAAAABkqryZezgAAAAAAEDADQAAAACAT8hwAwAAAADgAwJuAAAAAAB8QMANAAAAAIAPCLgBAAAAAPABATcAAAAAAD4g4AYAAAAAwAcE3AAAAAAA+ICAGwAAIAts3LjRChUqZF999dVReb6ePXtalSpV0vXYu+66y5o1a5bp5wQAQUfADQAInGnTplmePHmi3hQ4+OHrr7+24cOH265duyy7vh6LFy+2nOqJJ55wP0eQjBgxwgWxzZs3T3bfggULrEuXLlaxYkUrUKCAlShRwu2rx2zduvWon+vtt99uy5cvt9mzZx/15waAnCxfVp8AAAB+UXBStWrVJNvq1avnW8B9//33uyxiyZIlfXmO3EwB97HHHute3yDYvn27vfDCC+4WadiwYfbAAw9YtWrV3M+rr/v377clS5bYww8/7B7z66+/pvk5n376aUtISEjX+ZYvX946depk48ePt4suuihdxwCA3IiAGwAQWBdccIE1adLEcrK9e/da0aJFLbfat2+fFSlSxILmpZdesnz58lnHjh2TbH/ttddcsK3s9vTp0112O9yECRPcLT3y58+foXPWOXXu3NnWrVvnOgEAAEdGSTkAINf68MMP7ayzznIB7THHHGMdOnSwH3/8Mck+P/zwQyjLqPG2yvT16tXL/v7779A+KiW/44473P+VUffK1zds2OBu+n+0cmht12PDj6NtP/30k1111VVWqlQpa9GiRZIgrXHjxla4cGErXbq0XXHFFW4ccHroZypWrJj9/vvvduGFF7r/q3x58uTJ7v4VK1bYueee616bypUr24wZM6KWqX/xxRfWp08fK1OmjBUvXtx69OhhO3fujJqhrlu3rhUsWNCOP/5469u3b7Ly+7PPPttVICiT27JlSxdo33333W7csdpl/vz5oddW+8qOHTts0KBBVr9+ffcz6BzU0aLy53Cff/65e9zrr79uo0aNshNOOMG1Z+vWrW3t2rXJzve7776z9u3buzbQa9CgQQN79NFHk+yzevVqu/zyy11b6Fjq3EltyfU777zjSsR1zpHZbWXyn3322WTBtqi0PPx3RmbNmuV+d/W66vWtXr26C9oPHz6c4hhu73dTWeunnnrKPU6PP+2002zRokXJnvu8884LPR8AIHXIcAMAAmv37t32119/JdmmYEaUPbzmmmusbdu29tBDD7lM6pQpU1yAu3Tp0lBgMnfuXJfRu/baa12wrcBPwYm+fvvtty5gufTSS+3nn3+2V155xWUfvec47rjjXOlwWimLWLNmTXvwwQctMTHRbVOQeO+997os43XXXeeOO2nSJBeY6nzTU8augEzBqY4xduxYe/nll+2WW25xAeY999xj3bp1cz/b1KlTXSB9xhlnJCvR1/56bgWBa9asca/hb7/9FgpwRfep3F4B20033RTaT0GdJgwLz7yqI0PnpM6E7t27W7ly5Vxw3a9fPxec6rxE20Vto+BVr5nOTeObn3zySWvVqpXruFAQGm7MmDGWN29eF6Tr90M/t35OBdgetbk6ISpUqGC33Xaba/dVq1bZe++9574Xtb/GXquTQvMC6DVTMH/xxRfbzJkz7ZJLLon5usfHx7ufXa9FOP0O6ab2jQzEU6LOD+0/YMAA9/XTTz91gfuePXts3LhxR3y8OlP++ecf13GiNtNronbXaxveNgr2FZSrzfr375/q8wOAXC0RAICAef755xWlRr3JP//8k1iyZMnE66+/PsnjtmzZkliiRIkk2/ft25fs+K+88oo71hdffBHaNm7cOLdt/fr1SfbV99quc4qk7ffdd1/oe/1f26688sok+23YsCExLi4ucdSoUUm2r1ixIjFfvnzJtsd6PRYtWhTads0117htDz74YGjbzp07EwsXLpyYJ0+exFdffTW0ffXq1cnO1Ttm48aNEw8ePBjaPnbsWLd91qxZ7vtt27YlFihQIPH8889PPHz4cGi/xx9/3O333HPPhba1atXKbZs6dWqyn6Fu3bru/kj79+9PclzvNS9YsGDiiBEjQts+++wzd+w6deokHjhwILT90Ucfddv1WsqhQ4cSq1atmli5cmX3eoRLSEgI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pZ8h/BzVwYCcL5/lAOrdGTVqlOs92rRpk/vlUwB9++23W+vWrS0o3nrrLXvwwQdt7dq17sOkZs2aNnDgQPcmTqtmo+fZoXxFfTlPZK2CcYk2tqlZveFz7MDhPDRHwNC+wUcbBxvtG3y08dGxYUwH9/Wjjz5Ksn3atGkuFliyZIm1bNnSbfv6669typQp1rRpU/f90KFDbcKECW4fZawLFCjgst8eXWfPmjXL+vXr5zLJosy4jqH7Xn/99VSd46FDh+y2226zcePGuWDac/LJJyfbV8dWVnvYsGH24YcfRj2efq6SJUum6rmRc2T7DPeGDRuscePG9umnn7pfZvVa6Y13zjnnuN6uICldurTdc8899s0339gPP/zgesp0mzNnTlafGgAAAJDldu/eHbpu9iiD/dprr9mOHTssISHBXn31VVcifvbZZ0c9hjLhKu/WdXZGfP/99y4ZmDdvXhfYV6hQwS644AJbuXJlkv1++uknGzFihL344otu31iUUNQx2rRp4zLlCIZsH3DffPPNrudp4cKFbixFrVq1rG7dujZgwABXWiK///67derUyYoVK2bFixd3JSRbt26NeUy9+ZQdD6exFhq34alSpYqNHDnSlajouJUrV3Zvzu3bt4eeSyUhixcvTtLjpl4pBch16tRx+7Rr186VhKSGzuuSSy5xj61evbrrMdNzfPnll+l45QAAAIDgUDCta/jmzZtbvXr1QtuVkVZmukyZMlawYEHr06ePvf3221ajRo2ox3n22Wetbdu2bjx1Rqxbty40fFVZ9ffee8+N4dY1vYJ/OXDggF155ZUucXjiiSdGPY6C7KlTp7rydN0qVarkjqGAHjlfti4p1y+qstkqJ1eZRyQFt3rjeQGwxniotEOZ765du7oJCDJCpSgq8b733nvd/1XarR60Xr16uTfN4MGDXUD+448/hspR9u3bZ+PHj7fp06e7Hqzu3bvboEGD7OWXX07TcycmJrqsvsZyPPTQQzH305tYN8+ePXvc14J5Ey0uLjHdPzuyL7Vt+FcEC+0bfLRxsNG+wUcbHx0KoCNpfLWyx5999lmS+1UhunPnThc3KOhWkkwJOF1L169fP8kx/vjjD5ccmzFjRtTn8LbpWjza/eEOHjzovt5111120UUXuf8/9dRTbmy4suzXX3+9ixdOOukkF5voeIpVvOfxjl+tWjV3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P2HCBPdBce+997r/q7xFPW+9evVy2fbBgwe7gFzjSPThI/v27bPx48e7njT1rnXv3t0GDRpkL7/88hGfT8d+6aWXXIDdtGlT92GlcofwsppIKo3RLbzEQQrmTbS4uGw/WgDpoLYN/4pgoX2DjzYONto3+HJqGyuQDadx2StXrnSTnXn3ecGwyrd1DStjx451AfbTTz/trsk1GvWmm25yZeV6bOHChe25556zjh07uuRRhQoV3PF0UyCusdSijHilSpVc9ltJpWg05lvl6Lr+V9CtZJcSaap0rV+/vstY6/kjfxbRfdquwNs7f8UDmlDt/vvvd4m7Dz/8MHTNfqTXKdpzIBjiM9jGaX1ctg64165d695UtWvXjrnPvHnzXJm5JkjQm9h7QysLrvEdmokxvVTXr541GTZsmBtTouN17tzZbVPAfcYZZ7hsumZT9Bpg6tSpVr169dCH2YgRI1L1fMpsa1yMZnrUz63OgxtvvDHFknKN79aHSKShjRKsSJHD6fq5kTM80CQhq08BPqJ9g482DjbaN/hyWhsrieN56qmnXAm2Eks//PCDu4lXIarAO3x/jVfV/tq2fPly91VJol27drnbBRdc4ILjoUOHusBWFaGiKs/w4ygjru91jRtJ+z7xxBP22GOPuTJylaOrPFxVproWVpCvkvc///wzyTEVaP/9999uf233klwak+5VmSpBpiBc2XaVw6eGOgYQbHPT2cZKsAYm4E7NfG4a66xA2wu2RZMpKPut+zIScKtk3KMxLKLetchtevN7AXeRIkVCwbaol0/3p4Yy8vrg04dNs2bNXIfDbbfd5iatUJY9miFDhrjy+vAMt16LkUvz2qH8cWn+mZH9qUddf+TvXZzXDiTknMlakDq0b/DRxsFG+wZfTm3jlcPbumtrlZFrImFNelazZs0k++h+JXKUtVbiyaP5hTTDuLapulQ0bFIVph79X8fTPioBnzRpkhu77WW4VbmqydU6dOjgSssjKYEmGjOuoZmeyZMnu+PouCoXf/zxx911t0rdvaBJ560klSZN0/W05oAKP38v8NaEcEqWpUTJMx1T58iY72CKz2AbexXFgQi49aZV2cfq1asz9bgq9Y4M5qOVBoQ3gFd+Em2b98ETeb+3T2ongldQrfJx9cB5wb0mo9BSByqxCV+OwaOxKbpF0h+AQzlo5kykndo4J82O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quWyugMGDLBvv/3W7fP777+7oLNYsWJWvHhx90G1devWmMc8++yzk2WONaZFZTSeKlWq2MiRI61Hjx7uuJUrV7bZs2e73j/vudT7qKA3vGezZMmSNmfOHPehqX1UqrN58+ZU/awq1VGnwhVXXGEFCxaMuo/Kd9q3b281a9Z0r4Uy/3oe77UAAADA0aWgWdeWzZs3t3r16oW2Dxo0yM4880x37RjNunXr3GNV9q2y8zfffNN27Nhhbdq0sYMHD6b7fHRcb1ilMujvvfeeKwPXNbCOH40y2+ocCM96t23b1p555hmX6NE4dF336nsF23/99Ve6zw9ANikp1weCstkKKlVOE0nBrT6kvABYY2lUQqPMt0pfPv/88ww9v0q69QF47733uv9fffXV7kOzV69eLjAePHiwC8iVXfbG5agnc/z48a4ER72K3bt3dx+2L7/8smU2jel544033Fif8NKlSOqd1M2zZ88e97Vg3kSLi0vM9PNC1lPbhn9FsNC+wUcbBxvtm/NFZndvueUWlz3+7LPP3H26KVmk71WCHb6/rlW97719NY5bVYteprlSpUou+60x4eF03avbkbLLXrB+11132UUXXeT+/9RTT1nVqlXt1VdfdeOwwylxs2rVKnv++eeTHFuP//PPP+300093AXe5cuXcta1K5HUdmluz3OHth2CKz2Abp/VxWRZwr1271r25a9euHXOfefPmuTLz9evXuw8n74NKWXB9wClrnF7KJGvcimictMbP6HidO3d22xRwK9BVNt0rE9KLO3XqVKtevXroA3jEiBGWmfTz6nk1qYU6Gt5+++0kY3KizaJ5//33J9s+tFGCFSlyOFPPDdnLA00SsvoU4CPaN/ho42CjfXOuDz74IPR/BbLfffedS9L88MMP7ib6qkzzsccem+SxSgqpElIJJVVOiqohw4+pmc/1vYLzcH/88YdLtITvG42qP0XjvcP3VZZbnQAVK1ZMsv+kSZNcMK55kyKPfckll7gKSx1Lj//4449dFlzX2Uou5WbqFEGwzU1nGysJmyMCbgXbR6LeOAXaXrAtCj6V/dZ9GQm4wyesUI+eaEmGyG1aOsELuDX2xQu2RWNmwpdWyAxakkETcGiskEqPrrnmGpfdjxV0a3ZJleCHZ7j1eo1cmtcO5Y/L1HND9sme6ELu3sV57UACk6YFDe0bfLRxsNG+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wAcE3AAAAAAA+ICAGwAAAAAAHxBwAwAAAADgAwJuAAAAAAB8QMANAAAAAIAPCLgBAAAAACDgBgAAAAAgZyDDDQAAAACADwi4AQAAAADwAQE3AAAAAAA+IOAGAAAAAMAHBNwAAAAAAPiAgBsAAAAAAB8QcAMAAAAA4AMCbgAAAAAAfEDADQAAAACADwi4AQAAAADwAQE3AAAAAAA+IOAGAAAAAMAHBNwAAAAAAPiAgBsAAAAAAB8QcAMAAAAA4AMCbgAAAAAAfEDADQAAAACADwi4AQAAAADwAQE3AAAAAAA+yBUB9/Dhw61hw4ZZfRoAgGziiy++sI4dO9rxxx9vefLksXfeeSfZ343atWtb0aJFrVSpUnbeeefZd999l+w477//vjVr1swKFy7s9rv44ouT3P/7779bhw4drEiRIla2bFm744477NChQymeW5UqVdw5hd/GjBmT5Nwi79dN5+qJj4+3ESNGWPXq1a1QoUJ2yimn2EcffZSBVwwAAKRHPssBtmzZYqNGjXIXNps2bXIXLQqgb7/9dmvdurUF0auvvmpXXnmlderUKdmFYGo0Gz3PDuX7/4svBEfBuEQb29Ss3vA5duBwnqw+HWQy2tdfG8Z0cF/37t3rgtBevXrZpZdemmy/WrVq2eOPP27VqlWz//77zyZMmGDnn3++rV271o477ji3z8yZM+3666+3Bx980M4991wXSK9cuTJ0jMOHD7tgu3z58vb111/b5s2brUePHpY3b14788wzUzxPBcs6tueYY44J/X/QoEF24403JtlffwtPO+200PdDhw61l156yZ5++mnXcTBnzhy75JJL3Hk0atQoXa8dAAAIYMC9YcMGa968uZUsWdLGjRtn9evXdz33unjo27evrV692oJGP7MuqM4666ysPhUACKQLLrjA3WK56qqrknz/yCOP2LPPPms//PCDC24VXN92223u71Lv3r1D+5188smh/3/88cf2008/2SeffGLlypVzHcUPPPCADR48OElwHI0CbAXq0RQrVszdPMuXL3fPM3Xq1NC26dOn2z333GPt27d33990003uPB5++GEXiAMAgKMj25eU33zzza5UbuHChXbZZZe5rEPdunVtwIAB9u2334ZK9pQJ1gVI8eLFrUuXLrZ169aYxzz77LNddjycygB79uyZpKRv5MiRLhuh41auXNlm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TZamGwAAAAAAyEBJudbZfuCBB6xixYpWrFgxW7dundt+77332rPPPpueQwIAAAAAECjpCrhHjRpl06ZNs7Fjx1qBAgVC2+vVq+fW5AYAAAAAILdLV8CtNbifeuopt952XFxcaPspp5zixnMDAAAAAJDbpSvg3rRpk5sgLVJCQoLFx8dnxnkBAAAAAJD7Au6TTz7ZFixYkGz7m2++aY0aNcqM8wIAAAAAIPfNUj5s2DC75pprXKZbWe233nrL1qxZ40rN33vvvcw/SwAAAAAAgpzh1mzkiYmJ1qlTJ3v33Xftk08+saJFi7oAfNWqVW5bmzZt/DtbAAAAAACCmOGuWbOmbd682cqWLWtnnXWWlS5d2lasWGHlypXz7wwBAAAAAAh6hlvZ7XAffvih7d27N7PPCQAAAACA3DlpWqwAHAAAAAAApCPgzpMnj7tFbgMAAAAAABkYw62Mds+ePa1gwYLu+/3799uNN97oJk4Lp1nLAQAAAADIzdIUcGspsHDdu3fP7PMBAAAAACD3BdzPP/+8f2cCAAAAAECAZGjSNAAAAAAAEB0BNwAAAAAAPiDgBgAAAADABwTcAAAAAAD4gIAbAAAAAAAfEHADAAAAAOADAm4AAAAAAHyQ4wPu4cOHW8OGDbP6NABEsWnTJuvevbuVKVPGChcubPXr17fFixcn2WfVqlV20UUXWYkSJaxo0aJ22mmn2e+//x66/+yzz7Y8efIkud14441HfL2PdNw+ffpY9erV3Xkdd9xx1qlTJ1u9enWSY8ybN8/OPPNMO+aYY6x8+fI2ePBgO3ToEG0NAACAVMlnWWzLli02atQoe//9993FedmyZV0Affvtt1vr1q0tKH788UcbNmyYLVmyxH777TebMGGC+xkjTZ482caNG+del1NOOcUmTZpkTZs2TfPzNRs9zw7lK5pJZ4/spGBcoo1talZv+Bw7cDiPZUcbxnSwnTt3WvPmze2cc86xDz/80AW1v/zyi5UqVSq036+//motWrSw3r172/3332/Fixd375VChQolOd71119vI0aMCH1fpEiRFJ8/Ncdt3LixdevWzU488UTbsWOH67w7//zzbf369RYXF2fLly+39u3b2z333GMvvvii+3xSoH/48GEbP358pr5eAAAACKYsDbg3bNjgLshLlizpgkxlv+Lj423OnDnWt2/fZNmmnGzfvn1WrVo169y5s/Xv3z/qPq+99poNGDDApk6das2aNbOJEyda27Ztbc2aNa4jAshJHnroIatUqZI9//zzoW1Vq1ZNso+CWQW1Y8eODW1T1jmSAmxlmFMrNce94YYbQv+vUqWKjRw50nVy6XNJ++r92KBBA9dRJjVq1HDH69Kli913330u6w0AAABk25Lym2++2ZWHLly40C677DKrVauW1a1b1wWd3377rdtHJaAq9SxWrJjLUulid+vWrTGPqfLTyMzxxRdfbD179kx2cd2jRw933MqVK9vs2bNt+/btoefShXZ46eu0adNcx4A6A+rUqeP2adeunW3evDlVP6vKWdWpcMUVV1jBggWj7vPII4+4TN61115rJ598sgu8FWg899xzqXoOIDvRe6pJkyauk0kdRo0aNbKnn346dH9CQoKrbNH7Xh1L2kcdTe+8806yY7388st27LHHWr169WzIkCGuAyuWtBzXs3fvXtcxoA4BdRLIgQMHkmXaVX6+f/9+V6kCAAAAZNuAWyWcH330kctka3xlJAW3unBWAKx958+fb3PnzrV169ZZ165dM/z8KulWdn3p0qXWoUMHu/rqq10ArvGm33//vctw6fvExMTQY3SRr1LS6dOn2xdffOE6AwYNGmSZ4eDBg+4i/rzzzgtty5s3r/v+m2++yZTnAI4mvVenTJliNWvWdB1VN910k9166632wgsvuPu3bdtm//77r40ZM8Z1Xn388cd2ySWX2KWXXure756rrrrKXnrpJfvss89csK33n96nsaT2uPLEE0+4zjPdVPauz5gCBQq4+xSsf/311/bKK6+4MnKVlHtl7antaAMAAEDulmUl5WvXrnXBbO3atWPuowmLVqxY4cZUelknjaVUFnzRokUua5xeKjfVpEmiklEFBjqesnGiyZHOOOMMl033SllV7q6ss1eaessttyQZV5oRf/31l7uoL1euXJLt+j6l0npl4XTz7Nmzx30tmDfR4uL+v7MAwaG2Df+aHem9og4zjZPWGGpRdvqHH35w7zUF0d7vbceOHd17SfTe/vLLL10grMnKRBUfHn1eaCy4gmG9L6KVn6f2uKKKGVXFaM4EVZjo/a+gXJltjT1X0K5x2+qQU2XK3XffbQsWLHA/m35Gv1678K8IHto42Gjf4KONg432Db74DF5rpfVxWRZwh2eOU5plWIG2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5wikx0MPPeQyx88//3xoW9WqVZPtpw61fv36ufd3hw4dkty3atUq++ijj2zRokXWpEkTt23SpEnWvn17Gz9+fNQAXcID4ipVqrjAWu8hfbYo862g/6abbgrtU7lyZbv55pvd542nUaNG7hZ+nLfeessWLFhAwA0AAICcW1KuC1+Vli5cuNAuu+wyq1WrltWtW9cGDBjgsmDy+++/uwxVsWLFXKlply5dbOvWrTGPefbZZyfLHCtL3LNnz2QX5j169HDH1UX47Nmzbfv27aHnUrYrvCR22rRprmNAwUKdOnXcPipVVUYuNU477TR3kX/FFVe40tZoLrjgAndel1xySaqOCWQHeu8oSFZnkipUFLw+/fTTSfZJSEiwq6++2u644w73Ho/0zTffuPeXF2zLeeed5zLU3333XarOQx1WCvoV7KsDIJo///zTBdOtWrWKeZylS5fa119/neI+AAAAQLYOuFXSqYyWMtkq3Yyki29dpCsA1r7z5893pabr1q2zrl27Zvj5VdKt7LourpVtUzCgAFzjUL///nuXHdP3iYmJSbLUyrZNnz7dlX+rM2DQoEEZPhcgJ9N7csqUKVazZk3XIaWM8q233movvPBCkix4vnz53PZYQ0sUrIfT/qVLl3b3peSJJ55wHWC6qaRdnxMFChRIss+VV15pRYoUsYoVK7qOu2eeeSbZcU444QTXGaagX59L1113XRpfCQAAACCblJRrLKWCWU1QFMu8efNsxYoVbjyml7F68cUXXYZMpafKGqeXSlU1TlM0tloBg46nLJ0MHjzYzjjjDJdNL1++vNumcvepU6e6YFw07nPEiBGWlQ4cOOBuHm8yqIJ5Ey0u7v87CxAcatvwr1lJ7wl1jGks9f333++21atXz3744Qf3nrrqqqtcB9ajjz7qMtWHDh0KPfbw4cPu8d7/9XngfR8ufL9oVPWiyhYF5o888oh7D6uDrlChQqF9xo4da3fffbcbWz506FBXBaOS9XCffvqpm6RNFTf33HOPq4RRRcrR5v2sKf3MyNlo42CjfYOPNg422jf44jN4rZXWx2VZwB2eOY5F4zoVaIeXh5588sku+637MhJwq2TcU65cOfdVY8gjt23bti0UcCtD5gXbUqFCBXd/Vho9enQo0Ak3tFGCFSlyOEvOCUfHA00Ssvyl/uCDD9z7Udll/d+jwFrBrbap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1apldevWdRmyb7/91u3z+++/uwv2YsWKWfHixV02b+vWrTGPefbZZycpwRUFtsrweapUqeKCAgU1Om7lypVdxnD79u2h51KAoqyhZ9q0aa5jQJ0BderUcfsoANm8eXOqftZHH33U7X/HHXe4xz/wwAOuHFhZSCDcU0895SoflKmOdOaZZ9prr71mO3bscBnnV1991fbv3+9+7+XAgQNWoECBUMArKgGXL7/8MsUX+vPPP3cVJieddJLddNNN9vfff6e4vzLYpUuXDn3fuHFj97zKkivw1v3Tp093PwfBNgAAAIImWwfcChg++ugjl8nWWNRICm4VUCgA1r7z58+3uXPn2rp161y5bEYpK6js+tKlS61Dhw5uXKwC8O7du7uss8ao6vvExMTQY/bt2+eyeQoivvjiC9cZoAxeanzzzTfJAqi2bdu67YBHwfSvv/6aLLPtef311122WGOzlZHu06ePvf3226HM9bnnnuuGaahiROOrd+7caXfddZe7L6XOIXUGvfjiizZv3jw31EHvtwsuuMAFztEoWz5p0iT3/B6N7/7444/t7rvvduem9/Aff/zhzhkAAAAImmxdUq4LdgWztWvXjrmPLv5XrFjhxoZWqlTJbVNQoCz4okWL7LTTTkv38yuD6AULw4YNc6WxOl7nzp3dtsGDB9sZZ5zhsulema0CHZXnKhiXW265xUaMGJGq51MQVK5cuSTb9L22x6JspW4ejceVgnkTLS7u/zsCkPPpd2vjxo2uuuOee+6xuLg4t03vEXU86f+i+xREq7NKQbcqM1T18emnn7ohGaoSefbZZ+3OO++0IUOGuOPo91S/azqWd5xIqjDx6D2pKgx9/eSTT1wQH05zLShA12NUOeIdU7/L1113neu0UqeYJmq7//773X4ffvihq2bJ7bzXKlY7IOejjYON9g0+2jjYaN/gi8/gtVZaH5etA+7wzHEsq1atcoG2F2zLySef7DJnui8jAXf4ZFReIKyAJXLbtm3bQgF3kSJFQsG2VKhQwd3vF433VsASaWijBCtSJHrmETnTBx984IZRaFiDgm7dRMH2ggUL3Jhs3Z544gl77LHHXBm5Al+VcWtIhLLKKgOXEiVKuMnNNLmaMs0KdCdOnOi+1/OkloZwzJo1yz2XR9UmGjeuwL5jx45JjqeJ0qRly5ahbLqqRBSE6/lVqo7/UbUO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" + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "[特征重要性排名 - Gain]\n", + "return_10 3244.585386\n", + "ma_ratio 2871.645070\n", + "return_20 2686.807540\n", + "vol_ratio 2667.200664\n", + "high_low_ratio 2461.679219\n", + "return_diff 1491.578852\n", + "volatility_5 1360.579366\n", + "market_cap_rank 697.769018\n", + "vol_ma5 665.639110\n", + "vol_ma20 640.332628\n", + "n_income 536.010082\n", + "ma5 489.527820\n", + "ma20 481.715007\n", + "ma10 303.121463\n", + "volatility_20 224.481188\n", + "dtype: float64\n", + "\n", + "所有特征都有一定重要性\n" + ] + } + ], + "execution_count": 16 + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.0" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}