文本分类的伪标签 Python

Pseudo Labelling on Text Classification Python

我不擅长机器学习。有人能告诉我如何在 python 中使用伪标签进行文本分类吗?我从来不知道正确的实现,我在互联网上到处搜索,但我发现任何东西都放弃了 :'( 我只是找到了数字数据集的实现,但我没有找到文本分类(矢量化文本)的实现。所以我写了这种语法,但我不知道我的代码是否正确。我做错了吗?请帮助我,我真的需要你的帮助.. :'(

如果你想试试,这是我的datasets。我想从 'Content'

分类 'Label'

我的步骤是:

  1. 拆分数据 0.75 未标记,0.25 标记
  2. 从 0.25 标记的 I 拆分:0.75 训练标记,和 0.25 测试标记
  3. 为训练、测试和未标记的数据集制作矢量器
  4. 从标记的训练构建第一个模型,然后标记未标记的数据集
  5. 将标记数据与 >0.99(伪标记)的未标记预测相结合,并制作第二个模型
  6. 从未标记的数据集中删除伪标记
  7. 从第二个模型中预测剩余的未标记,然后迭代步骤 3,直到预测的伪标记概率 <0.99。

这是我的代码:

对文本分类进行伪标注

from sklearn.naive_bayes import MultinomialNB

# Initiate iteration counter
iterations = 0

# Containers to hold f1_scores and # of pseudo-labels
train_f1s = []
test_f1s = []
pseudo_labels = []

# Assign value to initiate while loop
high_prob = [1] 

# Loop will run until there are no more high-probability pseudo-labels
while len(high_prob) > 0:
    
    # Set the vector transformer (from data train)
    columnTransformer = ColumnTransformer([
    ('tfidf',TfidfVectorizer(stop_words=None, max_features=100000),
     'Content')
    ],remainder='drop')

    def transforms(series):
        before_vect = pd.DataFrame({'Content':series})
        vector_transformer = columnTransformer.fit(pd.DataFrame({'Content':X_train}))
        return vector_transformer.transform(before_vect)

    X_train_df = transforms(X_train);
    X_test_df = transforms(X_test);
    X_unlabeled_df = transforms(X_unlabeled)
    
    # Fit classifier and make train/test predictions
    nb = MultinomialNB()
    nb.fit(X_train_df, y_train)
    y_hat_train = nb.predict(X_train_df)
    y_hat_test = nb.predict(X_test_df)

    # Calculate and print iteration # and f1 scores, and store f1 scores
    train_f1 = f1_score(y_train, y_hat_train)
    test_f1 = f1_score(y_test, y_hat_test)
    print(f"Iteration {iterations}")
    print(f"Train f1: {train_f1}")
    print(f"Test f1: {test_f1}")
    train_f1s.append(train_f1)
    test_f1s.append(test_f1)
   
    # Generate predictions and probabilities for unlabeled data
    print(f"Now predicting labels for unlabeled data...")

    pred_probs = nb.predict_proba(X_unlabeled_df)
    preds = nb.predict(X_unlabeled_df)
    prob_0 = pred_probs[:,0]
    prob_1 = pred_probs[:,1]

    # Store predictions and probabilities in dataframe
    df_pred_prob = pd.DataFrame([])
    df_pred_prob['preds'] = preds
    df_pred_prob['prob_0'] = prob_0
    df_pred_prob['prob_1'] = prob_1
    df_pred_prob.index = X_unlabeled.index
    
    # Separate predictions with > 99% probability
    high_prob = pd.concat([df_pred_prob.loc[df_pred_prob['prob_0'] > 0.99],
                           df_pred_prob.loc[df_pred_prob['prob_1'] > 0.99]],
                          axis=0)
    
    print(f"{len(high_prob)} high-probability predictions added to training data.")
    
    pseudo_labels.append(len(high_prob))

    # Add pseudo-labeled data to training data
    X_train = pd.concat([X_train, X_unlabeled.loc[high_prob.index]], axis=0)
    y_train = pd.concat([y_train, high_prob.preds])      
    
    # Drop pseudo-labeled instances from unlabeled data
    X_unlabeled = X_unlabeled.drop(index=high_prob.index)
    
    print(f"{len(X_unlabeled)} unlabeled instances remaining.\n")
    
    # Update iteration counter
    iterations += 1

我想我做错了什么.. 因为当我看到 f1 分数时它正在下降。请大家帮帮我 :'( 我压力很大。 f1 scores image

=================编辑=================

所以我搜索了期刊,然后我认为我对伪标签中数据拆分的概念有误解。

我最初认为,这些步骤从将数据拆分为标记数据和未标记数据开始,然后从标记数据拆分为训练和测试。

但是经过网上搜索,我发现this journal我的步骤是错误的。这个期刊说伪标签的步骤首先应该从将数据拆分为训练集和测试集开始,然后从该训练集中将数据拆分为标记和未标记的数据集。

根据该期刊,将数据拆分为 90% 的训练集和 10% 的测试集时,效果最好。然后,从这 90% 的训练集中,它被分成 20% 的标记数据和 80% 的未标记数据集。这个期刊尝试以0.7~0.9的证据范围为界来去掉伪标签,在这个比例的拆分上,最好的证据阈值是0.74。所以我用新的比例和 0.74 的阈值修正了我的步骤,我终于得到了 F1 分数在增加。这是我的步骤:

  1. 拆分数据0.9训练,0.1测试集(我标记了测试集,所以我可以测量f1分数)
  2. 我从 0.9 训练中拆分:0.2 个标记数据和 0.8 个未标记数据
  3. 为标记的训练、测试和未标记的训练数据集的 X 值制作矢量器
  4. 从标记的训练构建第一个模型,然后标记未标记的训练数据集。然后根据测试集(已经标注)测量F-1分数。
  5. 将标记数据与概率 > 0.74(基于期刊的阈值)的未标记预测相结合。我们称这个新数据为伪标签,比作实际标签),并从新的训练数据集中制作第二个模型。
  6. 从未标记的数据集中删除选定的伪标记
  7. 使用第二个模型预测剩余未标记数据,然后迭代步骤3,直到没有预测伪标记的概率>0.74
  8. 所以最后一个模型就是最终模型。

我的语法还是一样的,我只是改变了分割比例,最后我的 f1 分数通过 4 次迭代增加了:my new f1 scores.

我做的对吗?谢谢大家的关注..非常感谢..

I'm not good at machine learning.

总的来说,我会说你很擅长机器学习:半监督学习是一种高级问题,我认为你的解决方案很好。至少一般原则似乎是正确的,但很难肯定(我没有时间详细分析代码抱歉)。几点评论:

  • 可能可以改进的一件事是 0.74 阈值:这个值当然取决于数据,因此您可以通过尝试不同的阈值并选择最适合您的数据的阈值来进行自己的实验。
  • 最好将最终测试放在一边,并在迭代期间使用单独的验证集。这样可以避免数据泄露的风险。
  • 我不确定循环的停止条件。可能没问题,但可能值得尝试其他选择:
    • 只需迭代固定次数(例如10次)。
    • 停止条件可以基于“F1 分数不再提高”(即性能稳定),但它更高级一些。

总之还是很不错的,如果你想进一步改进,我的评论只是想法。请注意,我已经有很长时间没有使用半监督了,我不确定我是否记得很清楚;)