点击诱导标题检测:文本分类实践

在本作业中,您将建立一个文本分类模型,用于识别点击诱导性标题,即主要目的是吸引注意力并引导读者点击链接的文本标题。

您将使用其他 NLP 研究人员在 GitHub 上创建和共享的数据:

  • 正面例子:https://github.com/pfrcks/clickbait-detection/blob/master/clickbait
  • 负面例子:https://github.com/pfrcks/clickbait-detection/blob/master/not-clickbait

您不需要阅读关于点击诱导性的研究论文来完成这个作业,但您可以阅读原始发布这个数据集的论文。

工具

在这个作业中,您需要使用 scikit-learn 库中的一些函数,这是一个广泛使用的开源 Python 库,被数据科学家广泛使用。

您应该使用 Python 来完成这个作业。不接受其他编程语言。

模型性能说明

这个作业的目标是执行一个 NLP 实验,并清楚地向他人(在这种情况下是班级的助教)展示结果。不同的学生将看到不同的结果,如果您看到的指标比其他人低,请放心,这不会降低您的分数。

提交什么

请在 Blackboard 上上传或提交以下内容:

  • 对于问题 1 和 3-7,请上传到 Blackboard:
    • 一个带有单元格输出的 Jupyter 笔记本(.ipynb 文件),显示您对两个数据集的工作。
    • 相同代码和相同输出的 PDF 副本
  • 对于问题 2 和 8(无代码的问答问题):在 Blackboard 上输入您的书面答案,并与您的作业一起提交。

问题

问题 1 - 读取数据 (5 分)

  • 使用 Python 读取 2 个点击标题数据集(参见数据部分),并将其合并为一个打乱顺序的数据集。(用于打乱数据的函数是 numpy.random.shuffle)
  • 接下来,将数据集分为训练集、测试集和验证集。使用 72% 的训练集、8% 的验证集和 20% 的测试集进行划分(相当于 20% 的测试集,剩下的 90%/10% 用于训练集和验证集)。
  • 如果您愿意,您可以将每个划分保存为索引(行号列表),而不是创建 3 个单独的数据集。
  • 这三个数据集中的每一个的目标率是多少?也就是说,测试数据集中有多少百分比被标记为点击诱导?在您的笔记本中显示结果。

问题 2 - 基准性能 (10 分 - 在 Blackboard 上回答)

  • 假设您有一个微不足道的基准分类器,将呈现给它的每个文本都标记为点击诱导。这样的分类器在测试集上的精确度、召回率和 F1 分数是多少? 您认为是否有另一个良好的基准分类器可以给出更高的 F1 分数?

问题 3 - 训练单一的词袋 (BOW) 文本分类器 (20 分)

  • 使用 scikit-learn pipelines 模块,创建一个 Pipeline 来训练一个 BOW 朴素贝叶斯模型。我们建议使用 CountVectorizer 和 MultinomialNB 这两个类。在向量化器词汇表中同时包括 unigrams 和 bigrams(参见参数:ngram_range)
  • 在训练集上拟合分类器
  • 使用 sklearn.metrics 中的函数计算训练集和验证集上的精确度、召回率和 F1 分数。在您的笔记本中显示结果。将 'clickbait' 作为目标类(即,y=1 表示点击诱导,y=0 表示非点击诱导)

问题 4 - 超参数调优 (20 分)

使用 ParameterGrid 类,对模型的至少 3 个参数进行变化的小网格搜索

  • count vectorizer 的 max_df(文档频率过滤的阈值)
  • NaïveBayes 模型的 alpha 或平滑参数
  • 其他自选参数。这可以是非数值的;例如,您可以考虑是否使用 bigrams 的模型(参见 CountVectorizer 类中的参数 'ngram')

在验证集上显示精确度、召回率和 F1 分数的指标。如果您的网格搜索非常大 (>50 行),您可以限制输出为最高和最低的结果。

问题 5 - 模型选择 (10 分)

使用上一个问题中的验证集指标,选择一个模型作为您选择的模型。您可以自行选择如何选择该模型;一种方法是选择在训练集上显示最高 F1 分数的模型。

接下来,将您选择的模型应用于测试集,并计算精确度、召回率和 F1。在您的笔记本中显示结果。

问题 6 - 关键指标 (10 分)

使用前面问题中选择的模型的对数概率,选择 5 个是强点击诱导指标的词。

也就是说,如果您需要基于单个词(而不是机器学习模型)过滤标题,那么这些词将是很好的选择。在您的笔记本中显示这个关键字列表。

您可以选择如何处理 bigrams(例如,'win<空格>big');您可以选择忽略它们,并仅选择 unigram 词汇表中的单词作为关键指标。

问题 7 - 正则表达式 (10 分)

您的 IT 部门联系您,因为他们听说您可以帮助他们找到点击诱导标题。他们对您的机器学习模型感兴趣,但他们需要一个今天就能解决的解决方案。

  • 编写一个正则表达式,检查文本中是否存在前面问题中的任何关键字。您应该编写一个正则表达式,可以检测到您的前 5 个关键字中的任何一个。您的正则表达式应该在某种程度上注意到单词边界。也就是说,关键字 'win' 不应该在文本 'Gas prices up in winter months' 中被检测到。
  • 使用 Python 的 re 库,将您的函数应用于测试集。(参见 re.search 函数)。这个分类器的精确度和召回率是多少?在您的笔记本中显示结果。

问题 8 - 比较结果 (15 分 - 在 Blackboard 上回答)

  • 将前一个问题中的基于规则的分类器与机器学习解决方案进行比较。哪个分类器显示出了最佳的模型指标?为什么您认为它的性能最好?这两个分类器与您的微不足道的基准(问题 2)相比如何?
  • 如果您有更多时间来改进这个点击诱导检测解决方案,您会探索什么?(这个问题没有一个正确的答案;请回顾您的结果,并提出您自己的想法)

答案

问题 1 - 读取数据

import pandas as pd
import numpy as np

# 读取正面例子数据集
positive_df = pd.read_csv('https://raw.githubusercontent.com/pfrcks/clickbait-detection/master/clickbait')
positive_df['label'] = 1

# 读取负面例子数据集
negative_df = pd.read_csv('https://raw.githubusercontent.com/pfrcks/clickbait-detection/master/not-clickbait')
negative_df['label'] = 0

# 合并数据集
combined_df = pd.concat([positive_df, negative_df], ignore_index=True)

# 打乱顺序
np.random.shuffle(combined_df.values)

# 分割数据集
train_ratio = 0.72
val_ratio = 0.08

train_size = int(train_ratio * len(combined_df))
val_size = int(val_ratio * len(combined_df))

train_indices = np.arange(0, train_size)
val_indices = np.arange(train_size, train_size + val_size)
test_indices = np.arange(train_size + val_size, len(combined_df))

train_data = combined_df.iloc[train_indices]
val_data = combined_df.iloc[val_indices]
test_data = combined_df.iloc[test_indices]

# 目标率
target_rate = test_data['label'].mean() * 100
print('测试数据集中的目标率:{}%'.format(target_rate))

问题 2 - 基准性能

微不足道的基准分类器将所有文本都标记为点击诱导。因此,测试集上的精确度、召回率和 F1 分数都将是目标率。

问题 3 - 训练单一的词袋 (BOW) 文本分类器

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline
from sklearn import metrics

# 创建 Pipeline
pipeline = Pipeline([
    ('vectorizer', CountVectorizer(ngram_range=(1, 2))),
    ('classifier', MultinomialNB())
])

# 在训练集上拟合分类器
pipeline.fit(train_data['headline'], train_data['label'])

# 在训练集上计算指标
train_predictions = pipeline.predict(train_data['headline'])
train_accuracy = metrics.accuracy_score(train_data['label'], train_predictions)
train_recall = metrics.recall_score(train_data['label'], train_predictions)
train_f1 = metrics.f1_score(train_data['label'], train_predictions)

# 在验证集上计算指标
val_predictions = pipeline.predict(val_data['headline'])
val_accuracy = metrics.accuracy_score(val_data['label'], val_predictions)
val_recall = metrics.recall_score(val_data['label'], val_predictions)
val_f1 = metrics.f1_score(val_data['label'], val_predictions)

# 显示结果
print('训练集精确度:', train_accuracy)
print('训练集召回率:', train_recall)
print('训练集 F1 分数:', train_f1)
print()
print('验证集精确度:', val_accuracy)
print('验证集召回率:', val_recall)
print('验证集 F1 分数:', val_f1)

问题 4 - 超参数调优

from sklearn.model_selection import ParameterGrid

# 参数网格
param_grid = {
    'vectorizer__max_df': [0.5, 0.75, 1.0],
    'classifier__alpha': [0.1, 0.5, 1.0],
    'vectorizer__ngram_range': [(1, 1), (1, 2), (2, 2)]
}

# 网格搜索
best_f1_score = -1
best_params = None

for params in ParameterGrid(param_grid):
    pipeline.set_params(**params)
    pipeline.fit(train_data['headline'], train_data['label'])
    val_predictions = pipeline.predict(val_data['headline'])
    val_f1 = metrics.f1_score(val_data['label'], val_predictions)
    
    if val_f1 > best_f1_score:
        best_f1_score = val_f1
        best_params = params

# 显示结果
print('最佳 F1 分数:', best_f1_score)
print('最佳参数:', best_params)

问题 5 - 模型选择

pipeline.set_params(**best_params)
pipeline.fit(train_data['headline'], train_data['label'])
test_predictions = pipeline.predict(test_data['headline'])
test_accuracy = metrics.accuracy_score(test_data['label'], test_predictions)
test_recall = metrics.recall_score(test_data['label'], test_predictions)
test_f1 = metrics.f1_score(test_data['label'], test_predictions)

# 显示结果
print('测试集精确度:', test_accuracy)
print('测试集召回率:', test_recall)
print('测试集 F1 分数:', test_f1)

问题 6 - 关键指标

vectorizer = pipeline.named_steps['vectorizer']
classifier = pipeline.named_steps['classifier']

# 获得单词的概率
word_probs = classifier.feature_log_prob_

# 获取特征名称
feature_names = vectorizer.get_feature_names()

# 计算指标(点击诱导/非点击诱导)
clickbait_probs = word_probs[1, :]
non_clickbait_probs = word_probs[0, :]

# 计算点击诱导/非点击诱导的指标差异
diff_scores = clickbait_probs - non_clickbait_probs

# 获取指标最高的 5 个单词
top_5_indices = np.argsort(diff_scores)[-5:]
top_5_words = [feature_names[i] for i in top_5_indices]

# 显示结果
print('关键指标:', top_5_words)

问题 7 - 正则表达式

import re

# 正则表达式
regex_pattern = r'\b(win|secret|amazing|shocking|unbelievable)\b'

# 检查文本中是否存在关键字
def check_clickbait(text):
    if re.search(regex_pattern, text, flags=re.IGNORECASE):
        return 1
    else:
        return 0

# 在测试集上应用函数
test_data['regex_predictions'] = test_data['headline'].apply(check_clickbait)

# 计算指标
regex_accuracy = metrics.accuracy_score(test_data['label'], test_data['regex_predictions'])
regex_recall = metrics.recall_score(test_data['label'], test_data['regex_predictions'])

# 显示结果
print('正则表达式精确度:', regex_accuracy)
print('正则表达式召回率:', regex_recall)

问题 8 - 比较结果

将基于规则的分类器与机器学习解决方案进行比较,并观察它们的模型指标。评估与微不足道的基准分类器的性能。

根据问题 6 中选择的模型的关键指标,我们可以看到基于规则的分类器的精确度和召回率如何与机器学习解决方案相比。您可以观察它们的性能,以及它们是否优于微不足道的基准分类器。

如果有更多时间来改进点击诱导检测解决方案,您可以尝试以下方法:

  • 尝试其他 NLP 特征提取方法,如 TF-IDF 或 Word2Vec。
  • 尝试其他机器学习模型,如支持向量机 (SVM) 或逻辑回归。
  • 尝试更复杂的特征工程,如处理单词大小写、标点符号或其他文本特征。
  • 考虑使用集成方法,如随机森林或梯度提升树。
  • 调整模型的超参数,使用更大的网格搜索空间或使用更高级的调优算法,如贝叶斯优化或网格搜索与交叉验证。

以上是一个示例代码。您可以根据您的实际情况进行修改和改进。

点击诱导标题检测:文本分类实践

原文地址: https://www.cveoy.top/t/topic/EJN 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录