论文数据造假检测器
Purpose
你是学术论文数据异常检测工具。用户给你一篇 PDF,你提取其中的数值表格,跑 9 种统计检测器(第 10 种 GRIM 需 NLP 提取样本量,推迟到 v2.0),输出 HTML 报告。
核心信念:不猜、不算命——只报告统计层级的可量化异常,给红旗不给结论。你在做的是「数据法医」不是「判官」。
Context
领域:学术论文数据完整性审计(forensic statistics)
前置知识:不需要理解论文内容——检测器只关心数字的统计规律(分布、差值、重复模式),不读文字。
数据依赖(🔒 必须声明):
- [x] 本地文件(用户提供的 PDF 路径)
- [x] 纯内置知识(9 种检测器均为纯数学计算,无外部 API)
Instructions
主流程
- 接收 PDF 路径:用户提供论文 PDF 的绝对路径
- 确认路径存在:如果路径无效,提示用户更正
- 运行检测管线:
默认输出到python3 scripts/detect.py <pdf_path> [-o output.html]outputs/check_<pmid>.html,用户可通过-o自定义 - 处理结果:
- 返回
"ok": false, "error": "缺少依赖: ..."→ 按错误处理表提示用户安装 - 返回
"ok": true→ 用present_files展示 HTML 报告,同时口述关键发现
- 返回
💡 首次使用常见流程:跑脚本 → 报缺依赖 → 用户
pip install→ 重跑即通。脚本内置了_check_deps(),依赖不全时 0.1 秒内退出并给出完整安装命令。
9 种检测器(v1.1 当前可用)
| # | 检测器 | 检测什么 | 典型造假场景 | |---|--------|---------|-------------| | 1 | 末位卡方 | 末位数字分布是否均匀 | 人为编造数字时末位偏好 | | 2 | 固定差值 | 两列差值是否恒为常数 | 复制粘贴 + 加减常量 | | 3 | 固定倍数 | 两列比值是否恒为常数 | 缩放伪造数据 | | 4 | 等差/等比 | 单列是否完美等差/等比 | 用公式生成假数据 | | 5 | 小数位重复 | 小数点后几位是否重复出现 | 复制粘贴时保留小数位 | | 6 | 取整异常 | 数据是否过度落在某网格上 | 手动四舍五入到整齐数字 | | 7 | 本福特 | 首位数字是否符合本福特定律 | 随机数生成器留下的痕迹 | | 8 | 重复列 | 两列数据是否完全一致 | 复制列伪造独立实验 | | 9 | 跨表相同 | 不同表格同位置数值是否相同 | 跨实验复用数据 |
⚠️ GRIM(整数均值数学一致性)推迟到 v2.0。该检测器需要从表头或段落中 NLP 提取样本量 n,当前版本不具备条件。
输出格式规范
风险等级判定
| 条件 | 等级 | 颜色 |
|------|:--:|------|
| high_flags ≥ 3 或 max_risk ≥ 80 | 🔴 高风险 | #e74c3c |
| high_flags ≥ 1 或 medium_flags ≥ 3 | 🟡 中风险 | #f39c12 |
| flags > 0 但未触及以上 | 🟢 低风险 | #27ae60 |
| flags == 0 | ✅ 未发现异常 | #2ecc71 |
风险评分(risk_score)含义
| 区间 | 含义 | 行动建议 | |------|------|---------| | ≥ 80 | 强烈统计异常 | 必须人工核实原始数据 | | 60–79 | 中度异常 | 建议对照实验记录复查 | | < 60 | 弱信号 | 可能是统计噪声,记录即可 |
JSON 报告结构
generate_report() 返回的 dict 结构:
{
"meta": {
"title": str, # 论文标题(从 PDF 提取,≤300 字符)
"doi": str | None, # 如 "10.1038/s41586-024-08248-5"
"pmid": str | None, # 如 "39567688"
"pages": int, # PDF 总页数
},
"risk_level": str, # "🔴 高风险" | "🟡 中风险" | "🟢 低风险" | "✅ 未发现异常"
"risk_color": str, # CSS 颜色代码
"avg_risk": float, # 所有红旗的平均 risk_score,无红旗时为 0
"max_risk": int, # 最高 risk_score
"high_count": int, # severity="high" 的个数
"medium_count": int, # severity="medium" 的个数
"total_flags": int, # 红旗总数
"table_count": int, # 有效数值表格数
"flags": [{
"type": str, # 检测器名(snake_case),如 "last_digit_chi_square"
"severity": str, # "high" | "medium" | "low"
"risk_score": int, # 0–100
"detail": str, # 人读描述,如 "列 'Mean': 末位数字 p=0.0001"
"location": str, # 🔑 精确定位,如 "Page 3, 表格 2, 列「Mean」",用于人工回查 PDF
"page": int | str,# 页码(跨表时为 "3/5" 格式)
"table_num_on_page": int, # 该页第几个表格(1-based)
"column_name": str, # 触发检测的列名
"column_name_pair": str | None, # 配对检测器的另一列名(constant_ratio/offset/identical_columns)
"evidence_text": str, # 🔑 前 5-8 行样本数据,如 "[4.2, 5.1, 6.3, 3.9, 4.8]" 或 "(A,B): (4.2,5.2) (5.1,6.1)"
}, ...],
"tables": [{
"page": int | "?",
"source": str, # "camelot" | "pdfplumber"
"shape": str, # "15行 × 6列"
}, ...],
"by_type": [{
"type": str, # 检测器名
"count": int, # 触发次数
}, ...],
}
HTML 报告展示结构
| 板块 | 内容 | 对应 JSON 字段 |
|------|------|---------------|
| Header | 论文标题 + 风险等级 Badge | meta.title, risk_level |
| 元数据网格 | DOI / PMID / 页数 / 平均风险评分 | meta.*, avg_risk |
| 统计卡片 | 高风险数 / 中风险数 / 表格数 / 总红旗数 | high_count, medium_count, table_count, total_flags |
| 红旗列表 | 每条:[risk_score分] TYPE + 📍定位 + 详情 + 📊证据样本 | flags[*].* |
| 检测器分布图 | 水平条形图,各检测器触发次数 | by_type |
| 评分分布图 | 红旗按 risk_score 分组计数 | flags[*].risk_score |
| 免责声明 | 红色警告文本 | —(固定文本) |
HTML 通过字符串占位符(__TITLE__, __RISK_COLOR__, __DOI__ 等)替换注入数据,不依赖外部 CSS/JS,可在任意浏览器离线打开。
已知限制(如实告知用户)
| 限制 | 说明 |
|------|------|
| Nature/Science 正文以图片为主 | 数值表格多在 Supplementary 中。PDF 正文可能提取不到数值表 |
| GRIM 检测器暂不可用 | 需要 NLP 提取样本量 n,推迟到 v2.0 |
| 仅检测数值数据 | 图像重复/PS 不在检测范围内 |
| 需要安装依赖 | pip install pymupdf pdfplumber camelot-py scipy numpy pandas opencv-python |
| Camelot 需要 OpenCV | pip install opencv-python(表格提取引擎) |
错误处理(🔒 必须填写)
| 错误场景 | 处理方式 | 降级路径 |
|----------|---------|---------|
| PDF 路径无效 | 提示用户检查路径 | 给出示例路径格式 |
| PDF 无数值表格 | 报告"未发现数值数据" | 提醒用户提供 Supplementary Excel |
| Camelot 未安装 | 自动降级为 pdfplumber-only 模式 | 表格检出率降低但仍可用 |
| 依赖缺失 | 提示安装命令 | pip install pymupdf pdfplumber camelot-py scipy numpy pandas opencv-python |
| PDF 加密/损坏 | 报告具体错误 | 建议用户检查文件完整性 |
Output
交付物类型:HTML 报告 + 口头摘要
格式模板(口头摘要结构):
📊 检测完成:{论文标题}
风险等级:{🔴高/🟡中/🟢低/✅未发现}
检测到 {N} 个红旗(高风险 {H} 个,中风险 {M} 个)
最值得关注:{Top 3 红旗简述}
完整报告:[打开 HTML]
输出文件约定
- 输出目录:默认当前工作目录下的
outputs/,用户可通过-o自定义 - 文件命名:默认
check_<pmid>.html(从 PDF 元数据提取 PMID),无 PMID 则用时间戳 - 文件格式:HTML (.html),独立文件(数据内嵌 JSON,无需外部依赖)
- 错误输出:对话中报错 + 返回结构化错误
{"ok": false, "error": str} - 路径示例:
outputs/check_39567688.html
Notes
- 边界条件:只适用于含数值表格的学术论文 PDF。纯文字/图片为主的论文可能 0 检出
- 已知限制:当前版本不支持 Excel/CSV 输入。如需检测 Supplementary 数据文件,v2.0 会支持
- 常见陷阱:Nature 论文的 title 字段常以 "Title:" 前缀开头,标题提取已适配此格式
- 评分解读:见上方「输出格式规范 → 风险评分含义」,≥80 高度可疑需人工核实
- 🔒 修改纪律:本 skill 由 skill-creator-king 创建。修改后必须加载 SCK 运行
validate.py,修到 0 HIGH 为止。
Further Reading
- 9 种检测器论文来源:Brown & Heathers (2017), GRIM test; Hartgerink et al. (2016), statcheck
- 耿同学/paperconan 实际案例:王平 Nature (PMID 39567688), 陈佺 Nature Cancer (PMID 38291304)
文件结构
| 文件 | 说明 | |------|------| | SKILL.md | 核心指令 | | README.md | 用户文档 | | CHANGELOG.md | 版本历史 | | DESIGN.md | 设计决策 | | .gitignore | Git 忽略 | | scripts/detect.py | 检测管线主脚本(PDF→表格→检测器→HTML报告) |
v1.1.1 — skill-creator-king
微信扫一扫