用 Python 构建高考志愿填报系统:位次换算与录取概率预测

为什么不用深度学习

这个场景是表格数据回归预测,不是图像识别。数据量有限(全国高校 × 省份 × 年份),LightGBM 等梯度提升模型在表格数据上通常比神经网络效果更好,且训练速度快。

技术栈

Python
├── Pandas       数据清洗和处理
├── LightGBM     预测最低录取位次
├── FastAPI      后端 API
├── SQLAlchemy   数据库 ORM
└── Vue3         前端展示

第一层:位次换算

真正决定录取的是位次,而非分数。同一个位次在不同年份对应的分数不同:

import pandas as pd

# 读取当年一分一段表
score_table = pd.read_csv("score_rank_2025.csv")
# 结构:score, rank(分数→位次)

def score_to_rank(score: int, year: int) -> int:
    df = score_table[score_table["year"] == year]
    row = df[df["score"] == score]
    if row.empty:
        # 取最接近的分数
        row = df.iloc[(df["score"] - score).abs().argsort()[:1]]
    return int(row["rank"].values[0])

位次越小录取概率越高(1 代表全省第一名)。

第二层:训练预测模型

历史录取数据结构:

yearschoolmajorprovincemin_rankplan_count
2023清华计算机江苏23515
2024清华计算机江苏19812
import lightgbm as lgb
from sklearn.model_selection import train_test_split

df = pd.read_csv("admission_history.csv")

features = ["year", "school_id", "major_id", "province_id", "plan_count"]
target = "min_rank"

X_train, X_test, y_train, y_test = train_test_split(
    df[features], df[target], test_size=0.2, random_state=42
)

model = lgb.LGBMRegressor(n_estimators=500, learning_rate=0.05)
model.fit(X_train, y_train)

也可以替换为 XGBRegressorCatBoostRegressor,效果相近。

第三层:计算录取概率

基于历史波动区间:

def admission_probability(school_id, major_id, province_id, student_rank: int, year: int) -> float:
    # 预测今年最低录取位次
    predicted_min_rank = model.predict([[year, school_id, major_id, province_id, plan_count]])[0]
    
    # 历史波动标准差
    history = df[(df.school_id == school_id) & (df.major_id == major_id)]
    std = history["min_rank"].std()
    
    # 学生位次越小(越靠前)于预测线,概率越高
    z = (predicted_min_rank - student_rank) / (std + 1)
    
    from scipy.stats import norm
    return float(norm.cdf(z))

输出 0.0~1.0 的概率值。

冲/稳/保 分类

def classify(prob: float) -> str:
    if prob >= 0.8:
        return "保"    # 稳上
    elif prob >= 0.5:
        return "稳"    # 有竞争力
    else:
        return "冲"    # 有风险但值得一试

FastAPI 接口

from fastapi import FastAPI

app = FastAPI()

@app.get("/predict")
def predict(school: str, major: str, province: str, score: int, year: int):
    rank = score_to_rank(score, year)
    prob = admission_probability(school, major, province, rank, year)
    label = classify(prob)
    return {
        "rank": rank,
        "probability": round(prob, 3),
        "label": label
    }

模型效果优化

  • 特征工程:加入招生人数变化趋势、学校综合排名、专业热度
  • 位次分段:分段训练(Top 1000 / 1000~10000 / 10000+),各段波动规律不同
  • 时序权重:近年数据给更高权重(sample_weight 参数)
  • 多省合并训练:数据量小时跨省训练,加省份编码作为特征

数据来源

历年录取数据可从各省教育考试院官网下载,或使用第三方爬虫整理的开源数据集(GitHub 搜索”高考录取数据”)。确保数据包含:学校、专业、省份、年份、最低分、最低位次、计划人数。