# Automatic News Comment Classification **Repository Path**: Qjw775/automatic-news-comment-classification ## Basic Information - **Project Name**: Automatic News Comment Classification - **Description**: 基于人工智能与大数据的企业级项目 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-09-17 - **Last Updated**: 2026-09-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 新闻评论自动分类系统(News Comment Classification) 基于 scikit-learn(MultinomialNB + TF-IDF)与 Hadoop/HBase 的新闻标题与评论五分类系统: **体育 / 科技 / 财经 / 娱乐 / 军事**。完整规格见 `需求分析与可行方案.html`(v3)。 ``` ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 数据采集 │ → │ 三级清洗 │ → │ 分词 │ → │ HBase/ │ → │ 模型训练 │ │ 30路爬虫 │ │ 评论存活率│ │ jieba │ │ SQLite │ │ TF-IDF+NB│ │ │ │ 48–82% │ │ 停用词v1 │ │ 主存储 │ │ 双模型 │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └─────┬────┘ │ ┌────────────────────────────────────────────────────┘ ▼ ┌────────────────────────────────────────────────────────────────────────┐ │ Web 应用「分拣台」:首页 / 分类 / 复核 / 看板 / 训练 / 模型 六个视图 │ │ 低置信度(<闸门0.50) → review_queue → 人工复核 → human_corrections.jsonl │ │ → merge_corrections.py 按 rowkey 覆盖标签 → snapshot_{ver}_corr.parquet │ │ → 一行 model.train 即增量重训(预测→复核→回流→重训,见「回流闭环」一节) │ └────────────────────────────────────────────────────────────────────────┘ ``` ## 目录结构 ``` ├── config.py 全局配置(唯一配置入口,规格参数全部在此) ├── common.py 公共工具(UTF-8 输出/中文字体/文本清洗/日志) ├── assets/ 停用词v1、用户词典、评论黑名单、echarts.min.js ├── crawler/ 30 路爬虫(6 站 × 5 频道,独立适配器) │ ├── run_crawl.py 入口:python -m crawler.run_crawl [test|small|full] │ └── checkpoint.db 断点续爬(自动生成) ├── cleaning/ 三级清洗(长度→黑名单→去重[MD5+SimHash]) │ └── run_clean.py 入口:python -m cleaning.run_clean ├── segmentation/ jieba 分词(停用词v1 + 用户词典) │ └── run_segment.py 入口:python -m segmentation.run_segment ├── storage/ 存储层(HBase 主 / SQLite 备,同一接口 BaseStore) │ ├── import_data.py 清洗+分词结果导入主存储 │ ├── export_snapshot.py 主存储 → snapshot_{ver}.parquet(训练快照) │ └── update_stats.py 物化统计(看板数据) ├── model/ 模型(TF-IDF + MultinomialNB,标题/评论双模型) │ ├── train.py 训练入口:python -m model.train │ ├── predict.py 预测器(web 服务与验收调用) │ ├── selfcheck.py 模型包往返自检(7.3 必过) │ └── iterative_clean.py 第 3 级:最低置信度样本导出人工复核 ├── web/ 自定义前端(「分拣台」设计 + FastAPI 推理服务) │ ├── server.py 后端:python -m web.server(或 uvicorn web.server:app --port 8502) │ └── static/ index.html + style.css + app.js(ECharts 已本地化 assets/echarts.min.js) ├── scripts/ HBase 建表 / 连通性验证 / 虚拟机一键部署 / Docker 备用 ├── tests/ pytest 测试套件 ├── demo/ 演示数据生成器(无网络联调用) └── docs/ 数据字典(交付物 7) ``` ## 快速开始 ```bash # 0) 环境:Python 3.9+(本项目开发环境 3.14),无需 Docker python -m venv .venv .venv\Scripts\activate # Windows;Linux/macOS: source .venv/bin/activate pip install -r requirements.txt # ⚠️ 必须激活 venv。PATH 上的系统 python 没有本项目依赖,不激活直接跑 # python -m ... 会报 ModuleNotFoundError(如 No module named 'uvicorn')。 # 不想激活也行,把下面的 python 一律换成 .venv\Scripts\python.exe。 # 1) 跑通全链路(推荐先用小批量试爬,再决定是否全量) python -m crawler.run_crawl small # 小批量试爬(30 路,每路限量) python -m cleaning.run_clean # 三级清洗 → data/cleaned/ python -m segmentation.run_segment # 分词 → data/segmented/ python -m storage.import_data # 导入主存储(默认 HBase;本地 SQLite 兜底) python -m storage.update_stats # 更新物化统计 python -m storage.export_snapshot # 导出训练快照 parquet python -m model.train # 训练标题/评论双模型 python -m model.selfcheck # 模型包往返自检(必须通过) # 2) 启动 Web 应用(「分拣台」自定义前端 + FastAPI 推理服务) .venv\Scripts\python.exe -X utf8 -m web.server # Windows:全路径写死,不依赖 venv 激活 # Linux/macOS: .venv/bin/python -X utf8 -m web.server # 打开 http://127.0.0.1:8502 → 首页 / 分类 / 复核 / 看板 / 训练 / 模型 六个视图 # Windows 也可直接双击项目根目录的「启动网站.bat」(自动开浏览器) # 3) 测试 pytest tests/ -v ``` > **无网络 / 联调**:`python -m demo.make_demo_data 1000 3000` 生成合成样本后 > 从第 1 步的 run_clean 开始即可跑通全链路(含低质量评论过滤演示)。 ## 核心配置(config.py) | 项 | 默认 | 说明 | |---|---|---| | `NCC_BACKEND` | `hbase` | 存储后端:`hbase`(主) / `local`(SQLite 离线兜底) | | `NCC_HBASE_HOST` | `192.168.182.128` | HBase Thrift 地址(虚拟机 IP,2026-09-18 已上线) | | `NCC_DATASET_VER` | `v1_20260917` | 数据集版本(回流重训时递增) | | 模型参数 | TF-IDF: max_features=5000, min_df=2, sublinear_tf, norm=l2;NB: alpha=1.0 | 锁定规格,不缩水 | | 置信度阈值(闸门) | 0.50 | 低于此值进人工复核队列;运行时可调 0.40–0.60 | | 评论清洗 | 长度≥6;SimHash 汉明距离≤3 判近重复;emoji 默认删除 | 锁定规格 | 改配置只需改 `config.py`(或设环境变量),全工程统一读取。 ## HBase 部署(主存储,2026-09-18 已上线) 1. **虚拟机部署**:VM `192.168.182.128`(SSH hadoop)上 Hadoop 2.10.2 + HBase 2.4.18, 当前为 **HDFS 伪分布式**:`hbase.cluster.distributed=true`、 `hbase.rootdir=hdfs://localhost:9000/hbase`,内置 ZK,Thrift 9090。 (早期为 `file:///home/hadoop/hbase-data` 单机模式,2026-09-20 迁至 HDFS, 迁移步骤与证据见 `docs/交付报告.md`。) 安装/启动脚本:`scripts/setup_hbase_resume.sh`(断点续传+幂等安装)、 `scripts/start_hbase_vm.sh`(VM 侧 `~/start_hbase.sh`;必须用 `setsid nohup bash ~/start_hbase.sh &` 脱离 SSH 会话启动)。 `hbase` 服务已 `systemctl enable`(开机自启),但 **HDFS 未设自启**—— 重启虚拟机后需先 `start-dfs.sh` 再 `sudo systemctl restart hbase`, 否则 HBase master 会因 rootdir 不可达而卡在初始化。 ★ 历史坑(保留配置,勿删):`hbase.wal.provider=filesystem` + `hbase.unsafe.stream.capability.enforce=false`。这是 file:// 时期为了让 WAL 在无 hflush 的本地文件系统上可写而加的——当时默认 AsyncFSWAL 会让 master 在 becomeActiveMaster 阶段自杀。迁到 HDFS 后已非必需,但留着不影响正确性。 2. **Docker 备用**(需求方案风险应对):`docker compose -f scripts/docker-compose.hbase.yml up -d`。 3. **建表**(预分区 16 Region):`hbase shell scripts/create_tables.hbase`。 4. **验证连通**:`python -m scripts.verify_hbase`(10 行写读回;`--bench N` 批量压测, 实测 4261 行/秒)。 5. 本地 SQLite 后端(`NCC_BACKEND=local`)与 HBase 接口完全一致,无 HBase 时全链路照常可跑。 ## 常用命令速查 | 命令 | 作用 | |---|---| | `python -m crawler.run_crawl full --sites sina,netease --resume` | 指定站点全量续爬 | | `python -m model.iterative_clean --top 200` | 导出 200 条最低置信度评论人工复核 | | `python -m storage.update_stats` | 手动刷新看板统计(app 内 ttl=300s 自动缓存) | | `python -m model.selfcheck` | 检查所有模型包完整性 | ## 关键设计说明 - **双模型**:标题(20 万)与评论(10 万)独立训练,Web 端按类型路由(需求方案 07)。 - **三级清洗**:长度 → 黑名单正则 → 迭代去重(MD5 + SimHash 4 带×16 位索引); 最低置信度 200 条/轮导出人工复核,复核结果回流重训(需求方案 04,见「回流闭环」一节)。 - **主指标 Macro-F1**:军事等小类样本少,Accuracy 失真,所有评估以 Macro-F1 为准。 - **TfidfVectorizer 陷阱**:`token_pattern=None + tokenizer=str.split`(默认正则会把单字 中文词静默丢弃),分词结果按空格拼接后直接喂给向量器。 - **HBase 写入**:必须 `batch(batch_size=2000)` 批量提交,单条 put 慢 10 倍以上。 - **行键**:`salt(2)+'_'+md5(text)`,salt 取 md5 前 2 位,建表 16 Region 预分区打散热点。 - **模型包自检**:joblib 包含 vec/clf/dataset_ver/trained_at/n_samples,加载往返比对 失败即报错(需求方案 7.3)。 - **漂移监控**:pred_log 记录每次预测,看板对比预测分布 vs 训练集分布(需求方案 09 补强)。 - **停用词 v1**:刻意保留否定词(不/没/无/未/非…)与程度词(很/非常/太…), 已收录新闻噪声词(记者/报道/责任编辑/原标题…)。 ## 回流闭环(人工复核 → 增量快照) 规格 8.2/09 的「预测 → 复核 → 回流 → 重训」链路,由 `scripts/merge_corrections.py` 落地: ```bash python -X utf8 -m scripts.merge_corrections # dry-run,只报告不写文件(默认) python -X utf8 -m scripts.merge_corrections --apply # 写出增量快照 python -X utf8 -m model.train --snapshot "data/snapshots/snapshot_v1_20260917_corr.parquet" ``` **为什么是覆盖而不是追加**:语料 `rowkey = salt(2) + md5(清洗后文本)` 天然按文本去重, 人工纠正改的是**标签**——同一 rowkey 已在快照里带着原标签。若当新样本追加,同一篇文本 会带两个互相矛盾的标签,训练时等于灌噪声。故:命中已有 rowkey → 覆盖 `category`; 未命中 → 才作为新样本追加(文本走分词器补 `segmented_text`)。 **清洗口径必须对齐**:复核队列存的是**用户原样输入**的文本,语料 id 用的是**清洗后** 文本,两者 md5 对不上。匹配前先走一遍与 `run_clean` 相同的清洗,否则会把「其实已在 语料里的文本」误判成新样本。 **产物不覆盖冻结快照**:写出 `snapshot_{ver}_corr.parquet`(列为冻结快照的同一组, 元数据含 `derived_from` / 覆盖与追加条数)。冻结快照是已交付模型的数据基础, 不能被增量覆盖(05.1 可复现性)。 > 说明:本轮锁定规格下数据已冻结、不再重训,故「回流」段(脚本)已实现并实测, > 「重训」段是上面那条 `model.train` 命令,接入点就绪但未执行。 ## 测试与验收 - `pytest tests/`:去重(SimHash)、清洗(三级)、schema(行键/序列化)、 本地存储(导入导出)、分词、模型包往返自检。 - 验收顺序(需求方案 10.2):P0 环境(verify_hbase)→ P1 小批量试爬 → P2 清洗率 → P3 分词 → P4 训练 + 自检 → P5 Web → P6 规模决策(是否全量 85 万)。