You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SVM文本分类概率结果极差的技术求助

解决SVC文本年代分类概率区分度低的问题

问题描述

我是机器学习新手,正在使用sklearn的SVC进行文本年代分类项目,但得到的概率分数极低。我有13篇创作于598-1358年不同年代的文本(将年代作为类别),存储在训练和测试目录中,使用CountVectorizer和TfidfTransformer处理数据并通过pickle保存:

src = "../data/datasets/pickledWordLists/" 
corpus = [] 
for filename in os.listdir(src): 
    with (open(os.path.join(src, filename), "rb")) as openfile: 
        while True: 
            try: 
                text = pickle.load(openfile) 
                text = ' '.join(word for word in text) 
                corpus.append(text) 
            except EOFError: 
                break 
src = "../data/datasets/TestsPickled/" 
for filename in os.listdir(src): 
    with (open(os.path.join(src, filename), "rb")) as openfile: 
        while True: 
            try: 
                text = pickle.load(openfile) 
                text = ' '.join(word for word in text) 
                corpus.append(text) 
            except EOFError: 
                break 
vectorizer = CountVectorizer() 
vectorizer.fit(corpus) 
vector = vectorizer.transform(corpus) 
tfidf_transformer = TfidfTransformer() 
vector = tfidf_transformer.fit_transform(vector) 
with open('../data/datasets/labeledData/training/train_matrices/corpus.pickle', 'wb') as handle: 
    pickle.dump(vector, handle) 

之后加载数据:

train_sparse = [] 
with open('../data/datasets/labeledData/training/train_matrices/corpus.pickle', 'rb') as handle: 
    train_sparse = pickle.load(handle) 
train_set = np.array(train_sparse.toarray()[0:9]) 
test_set = np.array(train_sparse.toarray()[10:14]) 
labels = [1028, 1107, 1358, 598, 707, 875, 884, 890, 988] 

接着用训练数据和类别标签拟合SVC:

clf = SVC(kernel='linear', C=100, cache_size=300, class_weight='balanced', coef0=10.0, decision_function_shape='ovo', degree=10, gamma='auto', max_iter=-1, probability=True, random_state=None, shrinking=False, tol=1, verbose=False) 
clf.fit(train_set, labels) 

我用训练过的样本测试(实际类别884),预期该类别概率接近1.0,但得到错误分类且所有类别概率在10%-12%左右:

Actual Class: 884 
Predicted Class: [988] 
Class: 1028 probability: 0.13680521863292022 % 
Class: 1107 probability: 0.1372151835630488 % 
Class: 1358 probability: 0.09314753496099398 % 
Class: 598 probability: 0.11216304253012621 % 
Class: 707 probability: 0.07705449472997644 % 
Class: 875 probability: 0.07702437742491991 % 
Class: 884 probability: 0.11694844959109225 % 
Class: 890 probability: 0.12739816653603753 % 
Class: 988 probability: 0.1222435320308847 % 

其他测试结果类似:

Actual Class: 890 
Predicted Class: [890] 
Class: 1028 probability: 0.13682366473176108 % 
Class: 1107 probability: 0.1372180833047104 % 
Class: 1358 probability: 0.09312179238345174 % 
Class: 598 probability: 0.11286567433780788 % 
Class: 707 probability: 0.07636519076484871 % 
Class: 875 probability: 0.07712682059152805 % 
Class: 884 probability: 0.1169118710112273 % 
Class: 890 probability: 0.12735823672708854 % 
Class: 988 probability: 0.12220866614757639 % 

我需要提升概率分数的区分度,另一组英文语料测试也有相同问题,项目需要通过类别相似度分数粗略判定文本年代,请问该如何解决?


解决方案与思路

首先得明确:你遇到的核心问题是数据集规模极小(9个训练样本对应9个类别),再加上SVC的概率估计本身是通过近似方法(如Platt缩放)得到的,并非模型原生输出,这直接导致了概率分布趋于平均,区分度极低。下面是具体的调整方向:

1. 解决数据量不足的根本问题

这是最关键的一步,小样本下任何模型都很难学到有效的特征:

  • 数据增强:针对古文本可以尝试:
    • 同义词替换(利用古汉语/英语的专属同义词库,比如古汉语《同义词词林》或英文古旧词汇资源)
    • 合理的文本重排(注意古文本语法结构固定,不要破坏语义)
    • 补充公开的同年代古文本数据集,扩充样本量
  • 合并相近年代类别:把跨度较小的年代合并为大类别(比如500-700、700-900、900-1100等),减少类别数量,让每个类别有足够的样本支撑模型学习。

2. 优化文本特征工程

文本特征的质量直接决定模型性能:

  • 简化特征流程:用TfidfVectorizer直接替代CountVectorizer+TfidfTransformer,效果一致且代码更简洁
  • 添加n-gram特征:设置ngram_range=(1,2),捕捉词语搭配关系,古文本的固定词组往往带有明显的年代特征
  • 过滤噪音特征:在向量器中设置min_df=2,去掉只在单个文本中出现的低频词,减少无关噪音
  • 引入语言学特征:
    • 统计虚词(古汉语“之乎者也”、英语古旧助词)的使用频率,不同年代虚词差异极大
    • 字符级特征:比如平均词长、特定古文字符的出现频率,这些细节也能携带年代信息

3. 调整SVC模型与概率校准

SVC的概率估计需要针对性优化:

  • 简化模型参数:你当前的参数过于冗余(比如线性核下degree和coef0是无效的,tol=1容忍度过高),先简化为基础版本,再用网格搜索调优:
    clf = SVC(kernel='linear', C=1.0, class_weight='balanced', 
              probability=True, random_state=42, tol=1e-3)
    
  • 概率校准:用CalibratedClassifierCV校准SVC的概率输出,让其更接近真实置信度:
    from sklearn.calibration import CalibratedClassifierCV
    
    base_clf = SVC(kernel='linear', C=1.0, class_weight='balanced', random_state=42)
    calibrated_clf = CalibratedClassifierCV(base_clf, method='sigmoid', cv=3)
    calibrated_clf.fit(train_set, labels)
    

4. 换用更适合小样本的模型

如果SVC表现不佳,可以尝试其他更适配小样本文本任务的模型:

  • 朴素贝叶斯(MultinomialNB):对文本数据友好,小样本下稳定,概率估计基于统计原理,天然更可靠
  • K近邻(KNN):基于文本相似度直接判断类别,适合小样本场景,推荐用余弦相似度作为距离度量:
    from sklearn.neighbors import KNeighborsClassifier
    
    knn_clf = KNeighborsClassifier(n_neighbors=3, metric='cosine')
    knn_clf.fit(train_set, labels)
    
  • 回归思路:把年代看作连续数值,转换为回归任务预测具体年份,用预测值与真实年份的偏差来衡量相似度,输出的连续值更容易区分差异

5. 调整评估方式

小样本下常规评估方式误差大,建议:

  • 采用留一交叉验证(LeaveOneOut),更准确反映模型真实性能
  • 除了准确率,计算平均绝对误差(MAE),衡量预测年代与真实年代的偏差,更符合你“粗略判定年代”的需求

内容的提问来源于stack exchange,提问作者Charlie Tizzard • Kevlahan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:31:47