1 NLP自然语言处理
1.1 NLP领域:
自然语言处理NLP
自然语言理解NLU —— 人工智能方式Bert
自然语言生成NLG —— 人工智能方式GPT orT5
Bert,GPT,T5:预训练的自然语言模型;
内部是有点分裂的:
学习途径:
使用的工具:python+pytorch+huggingface
huggingface网址:https://huggingface.co/
人类的语言有什么特别之处?
语言文字是上层抽象表征,NLP与计算机视觉或任何其他机器学习任务都有很大的不同。
大多数单词只是一个语言学以外的符号:单词是一个映射到所指(signified 想法或事物)的能指(signifier)。例如,“rocket”一词指的是火箭的概念,因此可以引申为火箭的实例。当我们使用单词和字母来表达符号时,也会有一些例外,例如“whoompaa”的使用。
最重要的是,这些语言的符号可以被编码成几种形式:声音、手势、文字等等,然后通过连续的信号传输给大脑;大脑本身似乎也能以一种连续的方式对这些信号进行解码。人们在语言哲学和语言学方面做了大量的工作来概念化人类语言,并将词语与其参照、意义等区分开来。
Natural language is a discrete[离散的] / symbolic[符号的] / categorical[分类的] system.
1.2 自然语言处理任务
自然语言处理有不同层次的任务,从语言处理到语义解释再到语篇处理。自然语言处理的目标是通过设计算法使得计算机能够“理解”语言,从而能够执行某些特定的任务。不同的任务的难度是不一样的:
1) 简单任务
- 拼写检查 Spell Checking
- 关键词检索 Keyword Search
- 同义词查找 Finding Synonyms
2) 中级任务
- 解析来自网站、文档等的信息
3) 复杂任务
- 机器翻译 Machine Translation
- 语义分析 Semantic Analysis
- 指代消解 Coreference
- 问答系统 Question Answering
1.3 如何表征词汇
在所有的NLP任务中,第一个也是可以说是最重要的共同点是我们如何将单词表示为任何模型的输入。在这里我们不会讨论早期的自然语言处理工作是将单词视为原子符号 atomic symbols。
为了让大多数的自然语言处理任务能有更好的表现,我们首先需要了解单词之间的相似和不同。有了词向量,我们可以很容易地将其编码到向量本身中。
2.词向量
2.1one-hot(最简单的):
onehot的维度由词库大小决定
缺点:
1.维度灾难
2.无法度量词语之间的相似性
2.2词向量
word2vec:
Word2Vec是一个迭代模型,该模型能够根据文本进行迭代学习,并最终能够对给定上下文的单词的概率对词向量进行编码呈现,而不是计算和存储一些大型数据集(可能是数十亿个句子)的全局信息。
这个想法是设计一个模型,该模型的参数就是词向量。然后根据一个目标函数训练模型,在每次模型的迭代计算误差,基于优化算法调整模型参数(词向量),减小损失函数,从而最终学习到词向量。大家知道在神经网络中对应的思路叫“反向传播”,模型和任务越简单,训练它的速度就越快。
基于迭代的方法一次捕获一个单词的共现情况,而不是像SVD方法那样直接捕获所有的共现计数。
Word2Vec是google开源的软件包,包含以下核心内容:
-
两个算法:continuous bag-of-words(CBOW)和skip-gram
- CBOW是根据中心词周围的上下文单词来预测该词的词向量
- skip-gram则相反,是根据中心词预测周围上下文的词的概率分布
-
两个训练方法:negative sampling和hierarchical softmax
- Negative sampling通过抽取负样本来定义目标
- hierarchical softmax通过使用一个有效的树结构来计算所有词的概率来定义目标
Word2Vec依赖于语言学中一个非常重要的假设「分布相似性」,即相似的词有相似的上下文
重要假设:文本中离得越近的词语相似性越高
CBOW:上下文词来预测中心词
skip-gram:中心词来预测上下文词
评估词向量
word2vec缺点:
代码练习:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import re
import nltk
from nltk.corpus import stopwords
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import VotingClassifier
from sklearn.metrics import accuracy_score, confusion_matrix, roc_auc_score, classification_report
nltk.download('stopwords')
# 获取英文停用词,存入集合stop_words里面
stop_words = set(stopwords.words('english'))
file_path = "E:/workspace_python/python/data/emotion/val.txt"
val_df = pd.read_csv(file_path, sep=';', header=None, names=['Text', 'Emotion'])
file_path = "E:/workspace_python/python/data/emotion/test.txt"
test_df = pd.read_csv(file_path, sep=';', header=None, names=['Text', 'Emotion'])
file_path = "E:/workspace_python/python/data/emotion/train.txt"
train_df = pd.read_csv(file_path, sep=';', header=None, names=['Text', 'Emotion'])
print("-------------------------------------------")
print(train_df.info())
print("-------------------------------------------")
print(test_df.info())
print("-------------------------------------------")
print(val_df.info())
from collections import Counter
# Counter是一个字典子类,用于计数可哈希对象。它在进行频率统计时非常有用。
# 计数情感类别出现次数:创建了一个Counter对象,用于统计val_df数据集中'Emotion'列中每个情感类别的出现次数
val_counts = Counter(val_df['Emotion'])
train_counts = Counter(train_df['Emotion'])
test_counts = Counter(test_df['Emotion'])
percentage_appearance_val = {k: v / len(val_df) * 100 for k, v in val_counts.items()}
# val_counts:这是一个 Counter 对象,通常是通过 collections.Counter 创建的,用于统计 val_df['Emotion'] 中每个情感类别出现的次数。
# for k, v in val_counts.items():这是一个循环,遍历 val_counts 字典中的所有项。k 代表字典中的键(即情感类别),v 代表与每个键对应的值(即该情感类别在 val_df['Emotion'] 中出现的次数)。
# len(val_df):这计算了 val_df DataFrame 的行数,即 val_df 中的总样本数。
# v / len(val_df) * 100:这是一个计算表达式,它将每个情感类别的出现次数 v 除以总样本数 len(val_df),然后乘以 100,得到该情感类别在验证集 val_df 中的出现频率百分比。
# {k: v / len(val_df) * 100 for k, v in val_counts.items()}:这是字典推导式的主体。对于 val_counts 中的每个项,它创建一个新的键值对,其中键是情感类别 k,值是计算得到的发生频率百分比。
percentage_appearance_train = {k: v / len(train_df) * 100 for k, v in train_counts.items()}
percentage_appearance_test = {k: v / len(test_df) * 100 for k, v in test_counts.items()}
print(percentage_appearance_val)
print(percentage_appearance_train)
print(percentage_appearance_test)
# 绘制饼图
def plot_pie_chart(percentage_dict, title):
# 定义一个名为plot_pie_chart的函数,它接受两个参数:percentage_dict(情感类别及其出现频率百分比的字典)和title(图表的标题)。
labels = list(percentage_dict.keys())
sizes = list(percentage_dict.values())
# 从传入的字典中提取标签(情感类别)和大小(出现频率百分比),并将它们转换为列表。
plt.figure(figsize=(8, 8))
plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=140)
# 绘制饼图,其中sizes是每个扇区的大小,labels是对应的标签,autopct='%1.1f%%'表示每个扇区的百分比标签格式,startangle=140设置饼图的起始绘制角度。
plt.axis('equal')
# 确保饼图是圆形的。
plt.title(title)
# 设置图表的标题。
plt.show()
# 绘制每个数据集的饼图
plot_pie_chart(percentage_appearance_val, 'Validation Set Emotion Distribution')
plot_pie_chart(percentage_appearance_train, 'Training Set Emotion Distribution')
plot_pie_chart(percentage_appearance_test, 'Test Set Emotion Distribution')
# query()函数用于根据一个字符串表达式筛选DataFrame中的行。这个字符串表达式通常是一个条件表达式,用于指定筛选规则。
# query()调用将用于从DataFrame中排除(即不选择)包含特定情感类别'surprise'和'love'的行。
val_df = val_df.query('Emotion != "surprise" and Emotion != "love"')
test_df = test_df.query('Emotion != "surprise" and Emotion != "love"')
train_df = train_df.query('Emotion != "surprise" and Emotion != "love"')
# 查看余下的数据情况
emotion_counts = train_df['Emotion'].value_counts()
print("Remaining Emotion Counts in train_df:")
print(emotion_counts)
# 向量机
vectorizer = CountVectorizer(max_features=3000)#文本数据转换为数值型特征向量,max_features=3000参数表示只保留出现频率最高的3000个单词作为特征,其他的单词将被忽略。这有助于减少特征空间的维度,提高模型的训练效率。
svm = SVC(kernel="linear", C=0.5, random_state=42)#是支持向量机分类器,用于执行线性分类。kernel="linear"表示使用线性核函数,C=0.5是正则化参数,它控制了模型对错误分类的惩罚程度。较小的C值意味着更强的正则化,有助于防止过拟合。random_state=42用于确保每次运行代码时结果的一致性。
logistic = LogisticRegression(random_state=42, max_iter=1000)#逻辑回归分类器,它适用于二分类问题。random_state=42同样用于确保结果的一致性,max_iter=1000表示最大迭代次数,这有助于确保算法有足够的时间收敛。
svm_pipeline = Pipeline([("vectorizer", vectorizer), ("svm", svm)])
#第一个机器学习管道,它将CountVectorizer和SVC组合起来。管道会依次执行向量化和分类步骤,使得整个过程自动化和流水线化。
logistic_pipeline = Pipeline([("vectorizer", vectorizer),("logistic", logistic)])
#第二个机器学习管道,它将CountVectorizer和LogisticRegression组合起来,同样实现了向量化和分类的自动化流程。
voting_classifier = VotingClassifier(
estimators=[
("svm", svm_pipeline),
("logistic", logistic_pipeline)
],
voting='hard'
#这是VotingClassifier的voting参数,它指定了投票机制。'hard'表示使用硬投票(hard voting),即每个分类器对每个样本进行分类,然后选择得票最多的类别作为最终预测结果。硬投票通常适用于分类器的预测结果是确定性的(即不输出概率)的情况。
)
voting_classifier.fit(train_df['Text'], train_df['Emotion'])
# 调用VotingClassifier实例的fit方法,它将训练数据(文本和情感标签)输入到模型中,以便模型学习如何根据文本特征预测情感标签。在内部,fit方法会依次对每个子模型(即svm_pipeline和logistic_pipeline)进行训练,使用train_df['Text']作为特征输入,train_df['Emotion']作为目标标签。
def evaluate_model(model, X_train, y_train, X_val, y_val, X_test, y_test):
# 进行预测
train_pred = model.predict(X_train)
val_pred = model.predict(X_val)
test_pred = model.predict(X_test)
#计算每个数据集上的准确率
train_acc = accuracy_score(y_train, train_pred)
val_acc = accuracy_score(y_val, val_pred)
test_acc = accuracy_score(y_test, test_pred)
#打印出每个数据集上的准确率,格式化为两位小数。
print(f"Train Accuracy: {train_acc:.2f}")
print(f"Validation Accuracy: {val_acc:.2f}")
print(f"Test Accuracy: {test_acc:.2f}")
return train_pred, val_pred, test_pred
train_pred, val_pred, test_pred = evaluate_model(
voting_classifier,
train_df['Text'], train_df['Emotion'],
val_df['Text'], val_df['Emotion'],
test_df['Text'], test_df['Emotion']
# 使用voting_classifier模型和分割好的数据集(train_df, val_df, test_df)作为参数调用evaluate_model函数。
# 这将评估VotingClassifier在训练集、验证集和测试集上的性能。
)
train_true=train_df['Emotion']
val_true=val_df['Text']
test_true=test_df['Text']
labels= voting_classifier.classes_
subset_test_df = test_df.sample(n=1000, random_state=42)
#从测试数据集中随机抽取1000个样本,创建一个新的DataFrame ,random_state=42确保了抽样的可重复性,即每次运行代码时,抽取的样本都是相同的
subset_test_preds = voting_classifier.predict(subset_test_df['Text'])
#使用voting_classifier模型对抽取的测试子集的文本数据进行预测
fig, ax = plt.subplots(figsize=(8, 6))
#使用seaborn库的heatmap函数绘制混淆矩阵。
sns.heatmap(confusion_matrix(subset_test_df['Emotion'], subset_test_preds),
annot=True,
fmt='d',
xticklabels=labels,
yticklabels=labels,
ax=ax)
# confusion_matrix函数计算真实标签subset_test_df['Emotion']和预测标签subset_test_preds之间的混淆矩阵。
# annot=True表示在热图的每个单元格中显示数值,
# fmt='d'表示数值以整数形式显示。
# xticklabels和yticklabels用于设置热图的x轴和y轴标签,
# 这里使用了之前获取的模型类别标签labels。
ax.set_title('Subset Test Confusion Matrix')
ax.set_xlabel('Predicted')
ax.set_ylabel('True')
plt.show()
test_acc = accuracy_score(test_df['Emotion'], test_pred)
print('The Model has an accuracy of {:.2f}%'.format(test_acc * 100))
#accuracy_score函数(通常来自sklearn.metrics模块)用于计算分类任务中预测标签与真实标签之间的准确率。它将计算正确预测的样本数量占总样本数量的比例。
#test_acc:这是之前计算得到的模型在测试集上的准确率,是一个介于0和1之间的数值。
# format(test_acc * 100):将准确率乘以100,将其转换为百分比形式。
# 'The Model has an accuracy of {:.2f}%':这是一个格式化字符串,其中{:.2f}是一个占位符,用于插入一个保留两位小数的浮点数。format(test_acc * 100)将计算得到的准确率百分比插入到这个位置。
class_report = classification_report(test_df['Emotion'], test_pred, target_names=labels)
print(class_report)
#精确率(Precision):在模型预测为某个类别的样本中,实际属于该类别的样本比例。它衡量的是模型预测的准确性。
# 召回率(Recall):在所有实际属于某个类别的样本中,模型正确预测为该类别的样本比例。它衡量的是模型对实际类别样本的识别能力。
# F1分数(F1-Score):精确率和召回率的调和平均数,是精确率和召回率的综合指标。
# 支持度(Support):每个类别的样本数量。
texts = [
"I'm feeling happy and excited today",
"I really don't even know why this is done for me!",
"I feel overwhelmed with sorrow",
"I was completely taken aback when everyone shouted 'Happy Birthday!'",
]
for custom_text in texts:
processed_text = preprocess_text(custom_text)
predicted_emotion = voting_classifier.predict([processed_text])
print(f"Text: {custom_text}")
print(f"Predicted Emotion: {predicted_emotion[0]}")
# print(f"Predicted Emotion: {predicted_emotion[0]}"):这行代码打印自定义文本的预测情感。由于predict返回一个数组,predicted_emotion[0]访问这个数组的第一个(也是唯一的)元素。
学习自用