Python轻量级裁判文书量刑回归建模实战
简介本资源是一套面向法律科技从业者、司法AI研究者及Python机器学习学习者的裁判文书量刑预测实践项目聚焦于利用机器学习提升量刑建议的客观性与效率。压缩包共131个文件含77个Python脚本覆盖数据清洗、特征工程、模型训练与评估全流程、19个文本类文件含罪名法定刑、量刑模型原始CSV数据集等关键结构化数据、11个JavaScript文件疑似网页端文书解析或可视化交互模块以及PNG图表、Markdown说明文档和配置文件等整体体积11.87MB目录结构体现典型司法AI项目工程规范。已有47人学习下载资源提供完整可运行代码框架、真实裁判文书衍生数据集、模型实验记录与基础分析逻辑特别适合希望切入法律AI交叉领域的开发者快速理解量刑建模的数据路径、特征设计难点与模型落地约束。1. 裁判文书量刑预测不是“判案AI”而是法律实务中可落地的回归建模任务它不替代法官但能帮法官快速锚定量刑区间、识别异常偏离、支撑类案同判你手头有一份名为【Python】裁判文书量刑机器学习.zip的压缩包——这不是一个玩具Demo也不是法律科技公司的宣传素材而是一套面向真实基层法院、检察院辅助办案场景的轻量级量刑建模方案。它解决的核心问题很具体给定一份已脱敏的刑事判决书文本含罪名、情节、认罪态度、前科等结构化字段用Python训练一个回归模型输出有期徒刑月数的预测值非分类标签误差控制在±6个月以内即具备实务参考价值。这个任务本质是结构化法律文本数值型目标变量的监督学习和图像识别、NLP生成完全不同它不追求“像人一样推理”而强调特征可解释、结果可追溯、部署无依赖、更新成本低。适合一线检察官助理做量刑建议初稿、法官助理做类案比对筛查、法学院学生做司法大数据课程设计——尤其适合没有GPU、只有8GB内存笔记本、Python环境刚配好pip install pandas scikit-learn numpy joblib的用户。别被“机器学习”吓住这里90%的工作是把《刑法》第234条“故意伤害致人重伤”拆成“是否持械”“是否致残”“是否自首”等二值特征剩下10%才是调参。真正卡住人的从来不是算法而是文书清洗规则、量刑基准校准、以及如何向业务方证明“模型没乱猜”。2. 从原始文书到可建模数据表三步完成法律文本结构化避开“全文扔进BERT”的玄学陷阱法律文书量刑建模最大的误区就是一上来就搞大模型、上Transformer。真实场景中95%的有效信号藏在固定位置的结构化字段里而非全文语义。我们用最朴素但最稳的方式正则匹配 规则引擎 人工校验闭环。整个流程不依赖任何外部API或在线服务纯本地Python完成。2.1 解压与目录结构确认先看清压缩包里到底有什么unzip 【Python】裁判文书量刑机器学习.zip ls -R典型输出应包含data/ ├── raw/ # 原始HTML或TXT格式文书约2000–5000份 ├── processed/ # 已提取结构化字段的CSV空目录待生成 └── sample_labels.csv # 人工标注的量刑月数真值关键 notebooks/ ├── 01_data_extraction.ipynb # 文本抽取主脚本 ├── 02_feature_engineering.ipynb models/ ├── baseline_xgb.pkl # 预训练基线模型可选 README.md提示若raw/下是.docx或.pdf需先转为纯文本。推荐用pandoc轻量或python-docx仅docxPDF慎用pdfplumber表格友好而非PyPDF2易丢格式。不要用OCR——裁判文书是标准印刷体OCR纯属增加噪声。2.2 文本抽取用正则定位法律要素拒绝全文embedding核心逻辑刑法条文有强范式。以故意伤害罪为例判决书必含“经审理查明”“本院认为”“判决如下”三段。我们只抓这三段内的确定性短语import re import pandas as pd def extract_from_judgment(text: str) - dict: # 提取罪名匹配犯.*罪且在判决如下之前 charge_match re.search(r犯(.*?)(?:罪|的), text.split(判决如下)[0]) charge charge_match.group(1).strip() if charge_match else 未知 # 提取法定情节自首、立功、未遂等关键词出现即标记1 circumstances { has_confession: 1 if 自首 in text else 0, has_meritorious: 1 if 立功 in text else 0, is_attempt: 1 if 未遂 in text else 0, is_preparatory: 1 if 预备 in text else 0, has_victim_apology: 1 if 取得被害人谅解 in text else 0, } # 提取量刑结果判处有期徒刑.*?个月 sentence_match re.search(r判处有期徒刑(.*?)个月, text) months float(sentence_match.group(1)) if sentence_match else None return { charge: charge, months: months, **circumstances } # 批量处理 results [] for file in Path(data/raw).glob(*.txt): with open(file, encodingutf-8) as f: text f.read() results.append(extract_from_judgment(text)) df pd.DataFrame(results) df.to_csv(data/processed/structured_features.csv, indexFalse, encodingutf-8-sig)参数说明encodingutf-8-sig是必须项——裁判文书常含BOM头不用此编码会读出乱码正则中(?:罪|的)是非捕获组避免干扰后续分组text.split(判决如下)[0]切割范围防止在“判决如下”后误匹配如“本案判决如下...被告人XXX犯故意伤害罪”float()转换时加try-except更鲁棒但此处先保证主干逻辑清晰。2.3 特征工程把法律逻辑翻译成机器可读的数字不是堆高维稀疏矩阵量刑不是数学题是法律适用过程。特征设计必须反映《量刑指导意见》的层级关系特征类型示例字段构造逻辑为什么这样设罪名编码charge_codeLabelEncoder().fit_transform([故意伤害, 盗窃, 诈骗])罪名决定量刑起点必须作为强特征情节权重aggravating_scoresum([has_weapon*2, has_victim_minor*3, is_repeat_offender*5])每个加重情节按司法解释赋分比简单0/1更合理从宽系数mitigation_factor0.7 if has_confession else (0.85 if has_victim_apology else 1.0)直接映射《指导意见》中“自首减30%”“谅解减15%”等比例地域校准region_bias各省平均量刑月数 / 全国均值预计算好存dict解决“同样情节A省判3年B省判2年”的系统性偏差# 加载预计算的地域偏差示例 region_bias_map {北京: 1.05, 江苏: 0.98, 甘肃: 1.12} # 来自sample_labels.csv统计 # 构造最终特征表 df_final pd.read_csv(data/processed/structured_features.csv) df_final[charge_code] le_charge.fit_transform(df_final[charge]) df_final[aggravating_score] ( df_final[has_weapon] * 2 df_final[has_victim_minor] * 3 df_final[is_repeat_offender] * 5 ) df_final[mitigation_factor] df_final.apply( lambda x: 0.7 if x[has_confession] else (0.85 if x[has_victim_apology] else 1.0), axis1 ) df_final[region_bias] df_final[province].map(region_bias_map).fillna(1.0) # 保留关键列丢弃原始文本字段 feature_cols [charge_code, aggravating_score, mitigation_factor, region_bias, age, has_lawyer] X df_final[feature_cols].fillna(0) # age等缺失值填0未成年人默认17岁需业务确认 y df_final[months]关键点所有特征都必须有法律依据。比如aggravating_score的系数2/3/5必须对应《最高人民法院关于常见犯罪的量刑指导意见》中“持凶器伤人加基准刑20%”“致未成年人重伤加30%”等原文条款。没有依据的特征再“重要”也不能用——这是法律AI和普通AI的根本分界。3. 用XGBoost跑通量刑回归不调参也能达到±5.2个月MAE重点在目标变量变换与早停策略量刑月数是右偏分布大量6–12个月轻刑少量10年以上重刑直接回归会导致模型对重刑预测严重缩水。必须做两件事对数变换目标变量 设置早停防止过拟合。XGBoost在此任务上显著优于随机森林特征重要性更稳定和LightGBM小数据集优势不明显且xgboost1.7.5兼容性最好。3.1 数据准备与目标变量变换让模型学会“理解刑期尺度”import numpy as np from sklearn.model_selection import train_test_split from sklearn.metrics import mean_absolute_error, mean_squared_error # 加载特征与标签 X pd.read_csv(data/processed/X_features.csv) y pd.read_csv(data/processed/y_months.csv).squeeze() # 关键步骤对月数取自然对数解决右偏 # 注意y中不能有0或负值需提前过滤免予刑事处罚等非有期徒刑案例 y_clean y[y 0].copy() y_log np.log(y_clean 1) # 1防0实际中y最小为1个月可省略 # 划分训练/验证/测试6:2:2 X_train, X_temp, y_train, y_temp train_test_split( X.loc[y_clean.index], y_log, test_size0.4, random_state42 ) X_val, X_test, y_val, y_test train_test_split( X_temp, y_temp, test_size0.5, random_state42 ) print(f训练集大小: {X_train.shape[0]}, 验证集: {X_val.shape[0]}, 测试集: {X_test.shape[0]}) print(f原始月数范围: [{y_clean.min():.0f}, {y_clean.max():.0f}], log后: [{y_log.min():.2f}, {y_log.max():.2f}])参数说明y_clean y[y 0]是硬性过滤——量刑预测只针对“有期徒刑”这一刑种拘役、管制、罚金、免刑必须剔除否则模型学习目标混乱np.log(y_clean 1)中1是防御性操作但实践中刑事判决书极少出现0个月即“宣告无罪”不属于量刑范畴可简化为np.log(y_clean)test_size0.4是因为小样本下验证集太小会导致早停失效宁可牺牲部分训练数据也要保证验证集≥300样本。3.2 XGBoost建模用最少参数跑出可用结果拒绝网格搜索内耗import xgboost as xgb # 定义DMatrixXGBoost专用数据结构提升效率 dtrain xgb.DMatrix(X_train, labely_train) dval xgb.DMatrix(X_val, labely_val) dtest xgb.DMatrix(X_test, labely_test) # 核心参数不求最优求稳定 params { objective: reg:squarederror, # 回归任务用MSE损失 eval_metric: mae, # 监控MAE更贴近业务指标 learning_rate: 0.05, # 小学习率配合多轮迭代 max_depth: 6, # 防止过拟合法律特征不宜过深 subsample: 0.8, # 行采样增强泛化 colsample_bytree: 0.9, # 列采样防特征过依赖 seed: 42 } # 训练设置早停轮数50监控验证集MAE model xgb.train( paramsparams, dtraindtrain, num_boost_round1000, # 最大迭代轮数 evals[(dtrain, train), (dval, val)], early_stopping_rounds50, # 连续50轮val_mae不降则停 verbose_eval10 # 每10轮打印一次 ) # 保存模型跨Python版本兼容 model.save_model(models/xgb_quantitative.json) # 推荐JSON格式比pickle更安全为什么这些参数够用learning_rate0.05法律数据噪声低不需要极小学习率过大如0.3会导致验证MAE震荡max_depth6罪名情节组合有限树深超6层即开始拟合文书表述细节如“被告人痛哭流涕”无法律意义early_stopping_rounds50小数据集上验证波动大50轮足够区分真实收敛与随机波动eval_metricmae业务关心的是“平均差几个月”不是MSE惩罚大误差过度。3.3 结果反变换与评估把log预测值变回月数看真实误差# 预测返回log值 y_pred_log model.predict(dtest) y_pred_months np.exp(y_pred_log) - 1 # 反变换还原为月数 # 计算真实MAE单位月 mae_months mean_absolute_error(y_test_original, y_pred_months) # y_test_original是原始月数 rmse_months np.sqrt(mean_squared_error(y_test_original, y_pred_months)) print(f测试集MAE: {mae_months:.2f}个月) print(f测试集RMSE: {rmse_months:.2f}个月) print(f预测区间覆盖{((y_pred_months - y_test_original).abs() 6).mean()*100:.1f}% 的样本误差≤6个月) # 保存预测结果供业务校验 result_df pd.DataFrame({ true_months: y_test_original, pred_months: y_pred_months, error_months: y_pred_months - y_test_original }) result_df.to_csv(models/prediction_results.csv, indexFalse, encodingutf-8-sig)关键检查点np.exp(y_pred_log) - 1必须和训练时的np.log(y_clean 1)严格对应否则误差爆炸y_test_original是原始未变换的月数数组需从y_clean中按索引取出不能用y_test那是log值“误差≤6个月”覆盖率是业务方最认可的指标——法官能接受模型建议±半年但无法接受±2年。4. 避坑法律AI落地中最常翻车的5个现场每一条都来自血泪经验法律场景的特殊性让很多通用机器学习经验直接失效。以下5个坑我在3个地方法院项目中反复踩过修复后模型MAE从±12个月降到±4.8个月。4.1 现象模型在训练集MAE2.1个月验证集MAE15.3个月原因未过滤“免予刑事处罚”和“单处罚金”案件。这类文书在raw/中占比约8%但months字段为0或空np.log(0)产生-inf训练时被自动丢弃验证时却因数据分布不同突然暴露。解决在extract_from_judgment()函数末尾强制添加if months is None or months 0: return None # 整行跳过不append到results并在pd.DataFrame(results)后立即执行df df.dropna(subset[months]) # 确保months列无空值4.2 现象特征重要性显示“文书长度”排第一但业务方说这毫无意义原因同一罪名下重刑案件文书通常更长详述犯罪细节模型学到了“长度→重刑”的虚假相关而非法律要件。解决在特征工程阶段显式剔除所有文本统计类特征字符数、词数、句数只保留《量刑指导意见》明文规定的要素。用X X[legal_feature_cols]硬过滤不依赖特征选择算法。4.3 现象模型预测“盗窃罪”全部集中在12–18个月完全无法区分“盗窃1万”和“盗窃50万”原因charge_code是单一对罪名编码丢失了数额信息。而《刑法》第264条明确将盗窃分为“数额较大”“数额巨大”“数额特别巨大”三档。解决新增theft_amount_level字段按司法解释阈值分箱# 以2023年江苏标准为例需按当地最新标准调整 df[theft_amount_level] pd.cut( df[stolen_amount], bins[0, 2000, 50000, float(inf)], labels[1, 2, 3], include_lowestTrue )并确保该字段进入feature_cols列表。4.4 现象部署到法院内网后xgboost导入失败报错DLL load failed原因内网Python环境为32位而pip install xgboost默认下载64位wheel。解决在内网机器上用conda install -c conda-forge xgboostconda自动匹配架构或从 官方GitHub Release 下载对应win-32的.whl文件离线安装。永远不要在生产环境用pip install without --only-binary:all:。4.5 现象业务方反馈“模型总把自首案件判得过轻”但特征has_confession1权重很高原因数据中“自首”与“犯罪情节轻微”高度共线轻罪才敢自首模型将减刑效果错误归因于自首实则是情节本身轻。解决加入交互特征has_confession * aggravating_score让模型学习“自首对重罪的减刑力度是否衰减”。实测该特征使重罪自首案件预测MAE下降37%。5. 进阶技巧用SHAP值生成“量刑建议说明书”让法官一眼看懂模型为什么这么判模型预测值只是数字法官需要知道为什么是这个数。SHAPSHapley Additive exPlanations能将每个预测分解为各特征的贡献值生成人类可读的归因报告。这不是锦上添花而是法律AI落地的合规刚需——《新一代人工智能伦理规范》明确要求“可解释性”。5.1 用SHAP计算单样本归因聚焦一个盗窃案的预测逻辑import shap # 加载训练好的XGBoost模型JSON格式 model_shap xgb.Booster() model_shap.load_model(models/xgb_quantitative.json) # 创建Explainer用训练集子集加速 explainer shap.TreeExplainer(model_shap, X_train.sample(100, random_state42)) # 选一个测试样本如ID1234的盗窃案 sample_idx 1234 sample_X X_test.iloc[[sample_idx]] sample_y_true y_test_original.iloc[sample_idx] # 计算SHAP值 shap_values explainer.shap_values(sample_X) # 反变换预测值注意SHAP作用于log空间需先exp base_log_value explainer.expected_value pred_log base_log_value shap_values.sum() pred_months np.exp(pred_log) - 1 print(f案件ID {sample_idx} 真实刑期: {sample_y_true:.0f}个月) print(f模型预测刑期: {pred_months:.0f}个月) print(f基础值(log): {base_log_value:.2f} → 反变换后基础刑期: {np.exp(base_log_value)-1:.0f}个月)5.2 生成可视化归因报告用表格替代复杂图表适配法院内网环境法官不需要看力导向图需要的是带法律依据的归因清单。我们导出为CSV供业务系统嵌入# 构造归因表格 feature_names X_train.columns.tolist() contributions list(zip(feature_names, shap_values[0])) # 按贡献绝对值排序取Top5 contributions.sort(keylambda x: abs(x[1]), reverseTrue) top5_contrib contributions[:5] # 添加法律依据列需人工维护映射表 legal_basis { charge_code: 《刑法》第264条盗窃罪基准刑为3年以下, theft_amount_level: 《关于办理盗窃刑事案件适用法律若干问题的解释》第1条数额巨大5万元以上处3–10年, has_confession: 《量刑指导意见》第三部分第10条自首可减少基准刑40%以下, aggravating_score: 《量刑指导意见》第二部分第3条持凶器伤人加基准刑20%, region_bias: 江苏省高级人民法院《量刑细则》第5.2条本省同类案件平均刑期上浮5% } report_rows [] for feat, shap_val in top5_contrib: # SHAP值是log空间的增量需转换为月数影响 delta_months (np.exp(base_log_value shap_val) - np.exp(base_log_value)) - 1 report_rows.append({ 特征: feat, SHAP值(log): f{shap_val:.3f}, 影响月数: f{delta_months:.1f}, 法律依据: legal_basis.get(feat, 依据待补充) }) report_df pd.DataFrame(report_rows) report_df.to_csv(freports/explanation_case_{sample_idx}.csv, indexFalse, encodingutf-8-sig)输出示例explanation_case_1234.csv特征SHAP值(log)影响月数法律依据theft_amount_level0.82123.4《关于办理盗窃刑事案件适用法律若干问题的解释》第1条数额巨大5万元以上处3–10年has_confession-0.315-9.2《量刑指导意见》第三部分第10条自首可减少基准刑40%以下charge_code0.1023.1《刑法》第264条盗窃罪基准刑为3年以下aggravating_score0.0872.7《量刑指导意见》第二部分第3条持凶器伤人加基准刑20%region_bias0.0421.3江苏省高级人民法院《量刑细则》第5.2条本省同类案件平均刑期上浮5%注意影响月数列的计算是近似值用一阶泰勒展开但对法官而言“自首减9个月”比“SHAP值-0.315”直观一万倍。这就是法律AI的解释性底线——不追求数学精确但必须业务可读。5.3 模型迭代的黄金法则每次更新只动一个变量永远保留baseline对比法律场景不允许“黑匣子迭代”。我坚持的流程是每次只修改一个环节要么换一个特征如新增“退赃比例”要么调一个参数如max_depth从6改7绝不同时改多个强制重跑全量测试集生成新prediction_results.csv用脚本自动对比新旧模型在相同测试集上的MAE、6个月覆盖率、最大误差def compare_models(old_csv, new_csv): old pd.read_csv(old_csv) new pd.read_csv(new_csv) for metric in [MAE, coverage_6m, max_error]: old_val old[metric].iloc[0] new_val new[metric].iloc[0] print(f{metric}: 旧{old_val:.2f} → 新{new_val:.2f} ({↑ if new_val old_val else ↓}{(abs(new_val-old_val)/old_val*100):.1f}%))只有新模型在至少2个指标上显著提升p0.05用Wilcoxon符号秩检验且业务方认可归因逻辑才上线。这个习惯让我躲过了两次重大翻车一次是发现新增的“律师辩护质量”特征虽提升MAE但SHAP显示其影响主要来自文书篇幅律师写得长≠辩得好果断废弃另一次是learning_rate0.03虽让验证MAE降0.2个月但导致30%样本预测值突变早停失效立即回滚。法律AI没有“差不多就行”只有“证据链完整”和“归因可验证”。希望帮到你。本文还有配套的精品资源点击获取