feat: fix py code for tratitional import path error

This commit is contained in:
shenjianZ 2026-01-15 17:53:00 +08:00
parent 08c9950db5
commit 4684216c85
3 changed files with 129 additions and 12 deletions

View File

@ -3,10 +3,14 @@
""" """
import os import os
import sys
import joblib import joblib
import jieba import jieba
from typing import Dict, Any from typing import Dict, Any
# 获取根模块路径ml-module目录
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# 分类映射(根据数据库中的分类) # 分类映射(根据数据库中的分类)
CATEGORY_MAP = { CATEGORY_MAP = {
'ENTERTAINMENT': '娱乐', 'ENTERTAINMENT': '娱乐',
@ -17,15 +21,20 @@ CATEGORY_MAP = {
'AUTOMOTIVE': '汽车', 'AUTOMOTIVE': '汽车',
'GOVERNMENT': '政务', 'GOVERNMENT': '政务',
'HEALTH': '健康', 'HEALTH': '健康',
'AI': 'AI' 'AI': 'AI',
'HOUSE': '房产'
} }
class TraditionalPredictor: class TraditionalPredictor:
"""传统机器学习预测器""" """传统机器学习预测器"""
def __init__(self, model_type='nb', model_dir='../../models/traditional'): def __init__(self, model_type='nb', model_dir='./models/traditional'):
self.model_type = model_type self.model_type = model_type
# 如果是相对路径,则基于根模块路径
if not os.path.isabs(model_dir):
self.model_dir = os.path.join(ROOT_DIR, model_dir)
else:
self.model_dir = model_dir self.model_dir = model_dir
self.vectorizer = None self.vectorizer = None
self.classifier = None self.classifier = None
@ -85,10 +94,96 @@ def predict_single(title: str, content: str, model_type='nb') -> Dict[str, Any]:
return predictor.predict(title, content) return predictor.predict(title, content)
def print_probabilities_table(probabilities: Dict[str, float]):
"""
表格方式打印各分类概率
"""
# 按概率降序排序
sorted_probs = sorted(probabilities.items(), key=lambda x: x[1], reverse=True)
# 表头
print("\n📊 各分类预测概率")
print("=" * 50)
print(f"{'分类代码':<15}{'分类名称':<10}{'概率':>10}")
print("-" * 50)
# 表体
for code, prob in sorted_probs:
name = CATEGORY_MAP.get(code, '未知')
print(f"{code:<15}{name:<10}{prob * 100:>8.2f}%")
print("=" * 50)
if __name__ == '__main__': if __name__ == '__main__':
# 测试 # 测试
result = predict_single( result = predict_single(
title="华为发布新款折叠屏手机", title="BBA在华销量跌回七八年前",
content="华为今天正式发布了新一代折叠屏手机,搭载最新麒麟芯片..." content="""
中新经纬1月15日电 (龚宸芫)近日BBA(宝马奔驰奥迪)公布了2025年全球销量数据显示宝马集团全球销量为246.37万辆同比微增0.5%梅赛德斯-奔驰全球销量为216万辆同比下降10%奥迪全球销量为162.36万辆同比下降2.9%
  聚焦中国市场宝马中国2025年销量为62.55万辆同比下滑12.5%奔驰中国销量为57.5万辆同比下滑19.5%奥迪中国销量为61.75万辆同比下滑5%同2024年相比三家车企销量减幅合计接近26万辆
  上述数据显示2025BBA中国市场销量水平回到了七八年前
  根据各家官网披露的数据宝马奔驰奥迪2018年在华销量分别为64万辆67.41万辆以及66.09万辆2017年则分别为59.44万辆58.79万辆以及59.79万辆
BBA近十年在华销量 中新经纬制图
  部分主销车型每月少卖近3000辆
  虽然奔驰和宝马在华销量下降幅度都超过了10%但从官方数据来看其最大的单一市场还是中国其中宝马中国在其全球销量体系中占比为25.4%奔驰中国在其全球销量体系中占比为26.5%
  谈及中国市场销量下滑原因奔驰给出的解释是其在中国市场面临豪华车市场结构性波动及自身产品周期调整等挑战
  中国汽车流通协会专家委员会委员章弘告诉中新经纬中国品牌产销量迅速增长尤其是新能源品牌在30万元以上市场中抢占份额直接挑战了BBA原有地位此外特斯拉等品牌在新能源领域的布局也对BBA形成压力尤其在中高端市场特斯拉的产品力和品牌影响力都在逐渐增强
  比如根据懂车帝统计的终端数据问界M9自2025年3月底上市以来持续在50万元以上的SUV市场取得头部表现全年销量接近12万辆而与之价格相接近的宝马X5全年销量为7.01万辆比2024年低1.7万辆
  BBA电动化转型滞后也是其销量下滑的原因之一BBA的新能源车型占比相对较低奔驰纯电动车占比仅8.1%奥迪也刚过12.9%而中国市场新能源渗透率已达47%消费者对新能源车型的需求增长使得BBA的传统燃油车优势逐渐减弱章弘说
  与2024年相比从主销产品销量来看根据第三方平台懂车帝数据宝马奔驰奥迪在华各有不同表现
  其中宝马中国主销轿车在2025年实现不同程度涨幅而SUV普遍呈下降趋势比如宝马3系2025年比2024年多卖了1.19万辆车宝马5系多卖2.74万辆而宝马X3 2025年比2024年少卖3.34万辆宝马X1也少卖3万辆
  奔驰中国的主销车型不管是SUV还是轿车都有不同程度下滑其中下滑最多的是奔驰C级比2024年下降了3.54万辆平均每个月少卖了0.295万辆GLC则是2025年比2024年少卖了2.74万辆奔驰E级和奔驰GLB分别少卖了1.47万辆和1.74万辆
  奥迪中国是三家中下滑程度最轻的车企变动最大的主销车型是奥迪A4L从2024年的10.74万辆降至2025年的8万辆少卖出2.74万辆而其他大部分主销车型下降幅度在0.5万辆到1.5万辆之间不过奥迪A3销量实现了上涨从2024年的5.48万辆增至2025年的6.68万辆多卖了1.2万辆
  值得一提的是公开资料显示2025年年中奥迪A3在终端市场曾进行了一次幅度较大的降价该车指导价为16.59万到20.99万元当时在4S店端裸车价跌破13万元根据各大购车平台显示的车主成交价最低成交价为11万元出头比官方指导价低5万元
  汽车市场的价格体系与性价比正在发生变化BBA入门级车型在20万40万元区间面临中国品牌的激烈竞争价格优势不再明显消费者在购车时更注重性价比中国品牌在配置智能化等方面的表现更具吸引力并且BBA部分车型存在配置选装费用较高的问题导致实际购车成本上升进一步削弱竞争力此外消费者需求变化市场环境与政策调整都会影响到BBA销量章弘分析道
  1月初中新经纬探访位于北京的多家宝马4S店看到大部分主销车型现车都有选装费用如宝马5系3即使是基础选装也会比裸车价格贵上万元
  三家均将推出多款新能源车
  从公开披露的信息来看BBA三家车企决定2026年继续加大投入中国市场尤其在新能源车领域
  宝马集团在2026年总体规划中提到将为中国消费者带来约20款BMWMINI和BMW摩托车新产品其中国产长轴距版新世代BMW iX3将于2026年上半年全球首发并在下半年上市该车将搭载宝马集团首创的全景iDriveBMW新世代电驱系统BMW驾控超级大脑等技术
  按照梅赛德斯-奔驰的计划其2026年将向中国市场引入超15款全新和改款产品覆盖新生代豪华核心豪华和高端豪华细分市场以及多种驱动方式如旗下三大全新纯电架构平台MB.EAAMG.EAVAN.EA均有新车陆续亮相
  对于奥迪中国而言2026年亦是产品大年其中一汽奥迪在2025年底表示2026年将推出全新奥迪Q5L奥迪A6L e-tron全新奥迪A6L等车型
  上汽奥迪计划在2026年推出奥迪E5 Sportback钦定性能quattro型奥迪E7X等车型后者计划于2026年北京车展亮相并在同年上半年上市此外新品牌AUDI E SUV概念车的量产版也将在2026年上市
  BBA已做好进击准备中国豪华市场2026年将迎来怎样的竞争格局
  章弘认为自主品牌在30万元以上高端市场占比将会持续提升比亚迪吉利长安奇瑞等传统车企通过高端子品牌与新势力车企共同发力凭借电动化智能化技术优势和本土化创新抢占传统豪华品牌市场份额
  预计2026年自主高端车型销量占比将进一步扩大形成与BBA等传统豪华品牌分庭抗礼的格局传统豪华品牌将加速本土化研发推出更多电动车型只是产品竞争力仍需时间提升部分品牌可能通过降价优化渠道等方式维持甚至提高销量章弘表示
  公开资料显示2026年开年之初宝马中国宣布对旗下超30款主力车型进行建议零售价调整其中24款车型的降幅超10%6款超20%部分车型最高官降30万元
  我们对2026年中国豪华车市场保持审慎乐观态度预计市场将延续2025年态势整体竞争强度持续高位市场整合与分化将进一步加剧同时2026年将是豪华车消费税起征点下调后的第一个完整实施年份其对市场结构的深远影响将全面显现在经历了前几年高速增长后市场进入调整期是正常的近日保时捷中国总裁潘励驰对中新经纬表示
  罗兰贝格1月8日发布的预见2026中国行业趋势报告显示从阵营格局看新势力与民营企业的份额已分别从2023年的3.6%和24.6%上升至2025年的8.8%和33.1%外资品牌份额则出现快速下滑然而这一趋势未必会持续放大随着合资车企加强与本土供应链的合作其在智能化方面的短板有望补足市场份额或将逐步止跌回稳
  聚焦BBA章弘认为BBA也许会加速本土化转型如加大电动化产品投放提升智能化配置等其市场份额下跌趋势可能得到一定遏制跌幅较往年收窄同时BBA有可能会继续推进渠道优化收缩低效能网点同时加强数字化展厅建设和服务体验提升
  公开资料显示2025年以来BBA旗下多家中国4S店闭店比如2025年3月到8月宝马中国撤销了数十家4S店的授权其中包括北京最大的宝马4S店2025年4月奔驰宝利德旗下三家门店闭店
"""
) )
print(result) print("\n🎯 最终预测结果")
print("=" * 50)
print(f"预测分类 : {result['categoryName']} ({result['categoryCode']})")
print(f"置信度 : {result['confidence'] * 100:.2f}%")
print("=" * 50)
# 表格打印概率
print_probabilities_table(result['probabilities'])

View File

@ -4,6 +4,7 @@
""" """
import os import os
import sys
import jieba import jieba
import joblib import joblib
import pandas as pd import pandas as pd
@ -14,6 +15,9 @@ from sklearn.svm import SVC
from sklearn.model_selection import train_test_split from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, accuracy_score, f1_score from sklearn.metrics import classification_report, accuracy_score, f1_score
# 获取根模块路径ml-module目录
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# 分类映射(与数据库表一致) # 分类映射(与数据库表一致)
CATEGORY_MAP = { CATEGORY_MAP = {
'ENTERTAINMENT': '娱乐', 'ENTERTAINMENT': '娱乐',
@ -24,7 +28,8 @@ CATEGORY_MAP = {
'AUTOMOTIVE': '汽车', 'AUTOMOTIVE': '汽车',
'GOVERNMENT': '政务', 'GOVERNMENT': '政务',
'HEALTH': '健康', 'HEALTH': '健康',
'AI': 'AI' 'AI': 'AI',
'HOUSE': '房产'
} }
REVERSE_CATEGORY_MAP = {v: k for k, v in CATEGORY_MAP.items()} REVERSE_CATEGORY_MAP = {v: k for k, v in CATEGORY_MAP.items()}
@ -40,7 +45,8 @@ CATEGORY_STOPWORDS = {
'AUTOMOTIVE': {'汽车', '车型', '上市', '发布', '销量', '市场', '品牌', '厂商'}, 'AUTOMOTIVE': {'汽车', '车型', '上市', '发布', '销量', '市场', '品牌', '厂商'},
'GOVERNMENT': {'会议', '讲话', '指出', '强调', '部署', '落实', '推进', '要求', '精神', '决定', '意见', '方案', '安排'}, 'GOVERNMENT': {'会议', '讲话', '指出', '强调', '部署', '落实', '推进', '要求', '精神', '决定', '意见', '方案', '安排'},
'HEALTH': {'医生', '专家', '建议', '提示', '提醒', '研究', '发现', '可能', '有助于'}, 'HEALTH': {'医生', '专家', '建议', '提示', '提醒', '研究', '发现', '可能', '有助于'},
'AI': {'技术', '系统', '模型', '算法', '应用', '功能', '版本', '升级', '研发', '推出', '人工智能'} 'AI': {'技术', '系统', '模型', '算法', '应用', '功能', '版本', '升级', '研发', '推出', '人工智能'},
'HOUSE': {'楼盘', '房价', '房产', '二手房', '新房', '学区房', '租房', '购房', '按揭', '首付', '房贷', '小区', '物业', '开发商', '售楼处', '开盘', '交房', '产权', '房产证', '不动产'}
} }
@ -65,10 +71,12 @@ class NewsClassifier:
if self.use_stopwords: if self.use_stopwords:
self._load_stopwords() self._load_stopwords()
def _load_stopwords(self, stopwords_path='../../data/news_stopwords.txt'): def _load_stopwords(self, stopwords_path=None):
""" """
加载停用词表 加载停用词表
""" """
if stopwords_path is None:
stopwords_path = os.path.join(ROOT_DIR, 'data/news_stopwords.txt')
try: try:
with open(stopwords_path, 'r', encoding='utf-8') as f: with open(stopwords_path, 'r', encoding='utf-8') as f:
self.stopwords = set(line.strip() for line in f if line.strip()) self.stopwords = set(line.strip() for line in f if line.strip())
@ -82,6 +90,11 @@ class NewsClassifier:
:param text: 待处理文本 :param text: 待处理文本
:param category: 可选指定分类时使用分类专属停用词 :param category: 可选指定分类时使用分类专属停用词
""" """
# 处理 NaN 值或空值
if pd.isna(text) or text is None:
return ''
if not isinstance(text, str):
text = str(text)
# 移除多余空格和换行 # 移除多余空格和换行
text = ' '.join(text.split()) text = ' '.join(text.split())
# jieba分词 # jieba分词
@ -108,6 +121,9 @@ class NewsClassifier:
""" """
从CSV文件加载训练数据 从CSV文件加载训练数据
""" """
# 如果是相对路径,则基于根模块路径
if not os.path.isabs(csv_path):
csv_path = os.path.join(ROOT_DIR, csv_path)
df = pd.read_csv(csv_path) df = pd.read_csv(csv_path)
# 合并标题和内容作为特征 # 合并标题和内容作为特征
df['text'] = df['title'] + ' ' + df['content'] df['text'] = df['title'] + ' ' + df['content']
@ -205,6 +221,9 @@ class NewsClassifier:
""" """
保存模型 保存模型
""" """
# 如果是相对路径,则基于根模块路径
if not os.path.isabs(model_dir):
model_dir = os.path.join(ROOT_DIR, model_dir)
os.makedirs(model_dir, exist_ok=True) os.makedirs(model_dir, exist_ok=True)
joblib.dump(self.vectorizer, os.path.join(model_dir, f'{self.model_type}_vectorizer.pkl')) joblib.dump(self.vectorizer, os.path.join(model_dir, f'{self.model_type}_vectorizer.pkl'))
joblib.dump(self.classifier, os.path.join(model_dir, f'{self.model_type}_classifier.pkl')) joblib.dump(self.classifier, os.path.join(model_dir, f'{self.model_type}_classifier.pkl'))
@ -214,6 +233,9 @@ class NewsClassifier:
""" """
加载模型 加载模型
""" """
# 如果是相对路径,则基于根模块路径
if not os.path.isabs(model_dir):
model_dir = os.path.join(ROOT_DIR, model_dir)
self.vectorizer = joblib.load(os.path.join(model_dir, f'{self.model_type}_vectorizer.pkl')) self.vectorizer = joblib.load(os.path.join(model_dir, f'{self.model_type}_vectorizer.pkl'))
self.classifier = joblib.load(os.path.join(model_dir, f'{self.model_type}_classifier.pkl')) self.classifier = joblib.load(os.path.join(model_dir, f'{self.model_type}_classifier.pkl'))
print(f"模型已从 {model_dir} 加载") print(f"模型已从 {model_dir} 加载")
@ -224,12 +246,12 @@ if __name__ == '__main__':
classifier = NewsClassifier(model_type='nb') classifier = NewsClassifier(model_type='nb')
# 假设有训练数据文件 # 假设有训练数据文件
train_data_path = '../../data/processed/training_data.csv' train_data_path = './data/processed/training_data.csv'
if os.path.exists(train_data_path): if os.path.exists(train_data_path):
df = classifier.load_data(train_data_path) df = classifier.load_data(train_data_path)
classifier.train(df) classifier.train(df)
classifier.save_model('../../models/traditional') classifier.save_model('./models/traditional')
# 测试预测 # 测试预测
test_title = "高效办成一件事”" test_title = "高效办成一件事”"

View File

@ -154,7 +154,7 @@ if __name__ == '__main__':
loader = DataLoader(db_url) loader = DataLoader(db_url)
# 从数据库加载数据并保存到本地 # 从数据库加载数据并保存到本地
data = loader.update_local_data(limit=2000) data = loader.update_local_data(limit=5000)
if data is not None: if data is not None:
print(f"成功加载数据,共 {len(data)} 条记录") print(f"成功加载数据,共 {len(data)} 条记录")