笔试、代码审查与项目答辩
本章目录
学完后,你应能独立完成
- 按推导、实现、诊断与研究表达四类练习
- 定位非法筛选、未成熟标签与错误净值
- 记录A/B/C并在延迟后复测
前置建议:因子研究综合实验
改变一个条件,观察发生什么
浏览器内即时教学计算;Python 实验结果另列于代码区。图形与数值一起核对。
如何判断自己真的会
A=不看资料独立完成并解释;B=提示后完成;C=看答案后才理解。当天照着答案重写不算A;隔两三天重新推导或完成变式,才检查是否能迁移。网页记录学习者自评,不会把“页面已读”自动标为掌握。
每个主题按四层练:用30–60秒说机制;从目标推关键式;写小规模NumPy实现;在股票面板中识别应用条件。计时用来发现卡点,不把速度替代解释和正确性。
笔试推导的解题顺序
先定义变量、维度、目标归一化、截距和条件,再求导或写最优条件。最后做一个数值小例子和极限检查。Ridge常漏n,Lasso常漏正交条件,XGBoost常漏1/2和父叶评分。
推导完问:是否存在解,是否唯一,库参数怎样对应,样本依赖影响哪层结论。能给出反例往往比把公式写得更长有用。
审查题 A:先全数据筛选再CV
如果先用全部X和y做SelectKBest,然后按日期切分,留出标签已经影响输入选择。把模型包在Pipeline里也来不及。应在每个训练折fit筛选器,只在未来段transform,且筛选使用的训练标签必须已成熟。
额外检查索引是否仍与日期、股票对应;验证选子集、窗长、指标也有累计选择压力。不能只说“用了CV,所以没问题”。
审查题 B:训练只限制 signal date
panel.date<validation_start并不保证future_5d_return已可得。先写entry、exit、cutoff和到达延迟,然后按label_available_time筛选。还要核对特征可得时点、尾部NA和日期键。
本例五日开盘标签、前一日收盘训练会删六个信号日期;若政策变化,重新推导。把gap写成常数不能替代解释。
审查题 C:测试早停与重叠净值
eval_set传入最终测试,若用于选轮数或checkpoint,测试就参与了选择;若仅事后日志,不机械声称模型一定更新,但须检查真实行为。把daily_future_5d_spread连乘则混淆了多日标签与每日持仓收益。
加手续费不能修复错误的时间口径。要构建实际权重、交易、逐日收益和成本;未做时明确承认只得到预测诊断。
项目答辩的五个连续问题
①你预测什么、为何可能有信息?②当时究竟能知道什么?③基线与新方法如何公平比较?④哪些结果能排除替代解释、哪些不能?⑤你个人做了哪个判断,失败后怎么修正?
准备3分钟主线和可展开的证据。可以坦诚未知和负结果,但不能把合成实验说成真实业绩,也不能把团队完成的内容全部记作个人实现。
从算法到一次真实运行
代码在本地 Python 中执行,HTML 内展示参考实现和本轮运行结果。请先独立完成练习,再展开完整参考文件。
def ols_fit(X, y):
"""X excludes intercept. Return intercept, slopes, rank of centered X."""
X, y = np.asarray(X, float), np.asarray(y, float)
if X.ndim != 2 or y.shape != (len(X),) or len(X) == 0:
raise ValueError("Expected nonempty X(n,p) and y(n)")
if not np.isfinite(X).all() or not np.isfinite(y).all():
raise ValueError("Resolve nonfinite data first")
mean = X.mean(axis=0)
coef, _, rank, _ = np.linalg.lstsq(X-mean, y-y.mean(), rcond=None)
return float(y.mean()-mean@coef), coef, int(rank)
def ridge_fit(X, y, lam):
"""SSE/(2n) + lam*||beta||^2/2; do not penalize intercept."""
if not np.isfinite(lam) or lam < 0:
raise ValueError("lam must be nonnegative and finite")
if lam == 0:
b, coef, _ = ols_fit(X, y)
return b, coef
X, y = np.asarray(X, float), np.asarray(y, float)
ols_fit(X, y) # Validate the input; not used as the regularized solution.
mean = X.mean(0)
xc, yc = X-mean, y-y.mean()
coef = np.linalg.solve(xc.T@xc + len(X)*lam*np.eye(X.shape[1]), xc.T@yc)
return float(y.mean()-mean@coef), coef
def best_split(x, y, min_leaf=1):
"""One-feature squared-error stump. None means no positive valid gain."""
x, y = np.asarray(x,float), np.asarray(y,float)
if x.ndim != 1 or y.shape != x.shape or min_leaf < 1:
raise ValueError("Expected matching 1D arrays and min_leaf>=1")
if len(x)==0 or not np.isfinite(x).all() or not np.isfinite(y).all():
raise ValueError("Expected nonempty finite data")
order = np.argsort(x,kind="stable"); xs, ys = x[order], y[order]
parent = np.sum((ys-ys.mean())**2)
best = None; best_sse = parent
for i in range(min_leaf, len(x)-min_leaf+1):
if xs[i-1] == xs[i]:
continue
left, right = ys[:i].mean(), ys[i:].mean()
sse = np.sum((ys[:i]-left)**2)+np.sum((ys[i:]-right)**2)
if sse < best_sse-1e-12:
best_sse = sse
best = (float((xs[i-1]+xs[i])/2), float(left), float(right), float(sse))
return best"""Standalone synthetic teaching example. Run locally with Python, not in the HTML."""
import json
import numpy as np
import pandas as pd
from scipy.special import expit
def clean(value):
if isinstance(value, dict): return {str(k):clean(v) for k,v in value.items()}
if isinstance(value,(list,tuple,np.ndarray)): return [clean(v) for v in value]
if isinstance(value,(np.integer,)): return int(value)
if isinstance(value,(float,np.floating)): return float(value) if np.isfinite(value) else None
if isinstance(value,(np.bool_,)): return bool(value)
return value
def print_result(result):
print(json.dumps(clean(result),ensure_ascii=False,allow_nan=False))
def ols_fit(X, y):
"""X excludes intercept. Return intercept, slopes, rank of centered X."""
X, y = np.asarray(X, float), np.asarray(y, float)
if X.ndim != 2 or y.shape != (len(X),) or len(X) == 0:
raise ValueError("Expected nonempty X(n,p) and y(n)")
if not np.isfinite(X).all() or not np.isfinite(y).all():
raise ValueError("Resolve nonfinite data first")
mean = X.mean(axis=0)
coef, _, rank, _ = np.linalg.lstsq(X-mean, y-y.mean(), rcond=None)
return float(y.mean()-mean@coef), coef, int(rank)
def ridge_fit(X, y, lam):
"""SSE/(2n) + lam*||beta||^2/2; do not penalize intercept."""
if not np.isfinite(lam) or lam < 0:
raise ValueError("lam must be nonnegative and finite")
if lam == 0:
b, coef, _ = ols_fit(X, y)
return b, coef
X, y = np.asarray(X, float), np.asarray(y, float)
ols_fit(X, y) # Validate the input; not used as the regularized solution.
mean = X.mean(0)
xc, yc = X-mean, y-y.mean()
coef = np.linalg.solve(xc.T@xc + len(X)*lam*np.eye(X.shape[1]), xc.T@yc)
return float(y.mean()-mean@coef), coef
def best_split(x, y, min_leaf=1):
"""One-feature squared-error stump. None means no positive valid gain."""
x, y = np.asarray(x,float), np.asarray(y,float)
if x.ndim != 1 or y.shape != x.shape or min_leaf < 1:
raise ValueError("Expected matching 1D arrays and min_leaf>=1")
if len(x)==0 or not np.isfinite(x).all() or not np.isfinite(y).all():
raise ValueError("Expected nonempty finite data")
order = np.argsort(x,kind="stable"); xs, ys = x[order], y[order]
parent = np.sum((ys-ys.mean())**2)
best = None; best_sse = parent
for i in range(min_leaf, len(x)-min_leaf+1):
if xs[i-1] == xs[i]:
continue
left, right = ys[:i].mean(), ys[i:].mean()
sse = np.sum((ys[:i]-left)**2)+np.sum((ys[i:]-right)**2)
if sse < best_sse-1e-12:
best_sse = sse
best = (float((xs[i-1]+xs[i])/2), float(left), float(right), float(sse))
return best
if __name__ == "__main__":
X=np.array([[-1.],[0.],[1.]])
y=2*X[:,0]
b,w=ridge_fit(X,y,1.)
np.testing.assert_allclose(w,[.8])
split=best_split(np.arange(1,7),np.array([0.,0.,1.,4.,5.,5.]))
GL,HL,GR,HR,lam,gamma=-2.,2.,2.,2.,1.,.1
gain=.5*(GL**2/(HL+lam)+GR**2/(HR+lam)-(GL+GR)**2/(HL+HR+lam))-gamma
print_result({"ridge_hand_fixture":w[0],"split_hand_fixture":split,
"xgboost_gain_hand_fixture":gain,"scope":"numerical fixtures, not a mastery score"})
查看本轮本地运行记录 · 2026-10-12
{
"ridge_hand_fixture": 0.8,
"split_hand_fixture": [
3.5,
0.3333333333333333,
4.666666666666667,
1.3333333333333335
],
"xgboost_gain_hand_fixture": 1.2333333333333332,
"scope": "numerical fixtures, not a mastery score"
}先回答,再看提示和答案
某研究员拿随机CV的GBDT IC=.12与日期CV的Ridge IC=.04相比,怎样回应?
一级提示
先审分数在回答什么问题。
参考答案与条件
先重建统一信息集、标签、日期集合与合法开发政策,再比较配对增量与风险/成本。原分数不可直接排序。
怎样解释Ridge不胜单因子这个失败?
一级提示
先写出目标、信息集和所需条件。
参考答案与条件
额外特征与学权重在该政策、该样本里没显示增量。查共线、信号、正则、状态与选择压力,不能直接宣布线性模型无效。
页面看完、答案都认识,应标A吗?
一级提示
先写出目标、信息集和所需条件。
参考答案与条件
不应。关资料完成推导、实现和变式,隔几天复测;否则按提示程度标B/C。
把知识迁移到一个新任务
设定15分钟闭卷练习:推Ridge、算一轮boosting、解释一个时间边界。随后用3分钟讲完整案例,按研究时点、增量、失败原因各接受一次追问。
这里保存学习笔记,不在浏览器执行 Python。A/B/C 由你按独立完成程度填写。
参考与进一步阅读
在线文档可能比本地固定版本更新;API 行为以已验证代码和版本记录为准。
掌握状态与复习
关掉资料独立完成后记 A;提示后完成记 B;需要重学记 C。
记录尽量保存在当前浏览器,建议定期导出备份。