本文将探讨自然语言处理的实践应用,涵盖从原始文本数据的预处理到词向量表示的转化的整个流程。我们将通过Python和相关库(如NLTK, scikit-learn, Gensim)逐步演示如何对文本数据进行清洗、分词,以及应用N-Grams、TF-IDF、余弦相似度、K-Means聚类、LDA主题建模和Word2Vec模型等核心NLP技术。
import nltk
import numpy as np
import pandas as pd
import re
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.cluster import KMeans
from sklearn.decomposition import LatentDirichletAllocation
from gensim.models import word2vec
# 加载英文的停用词列表
stop_words = nltk.corpus.stopwords.words('english')
# 创建一个词和标点符号的分词器
wpt = nltk.WordPunctTokenizer()
# 定义文档语料库
corpus = [
'The sun is blazing and the air is dry',
'The snow is thick, covering the mountains',
'Clouds gather, promising a heavy rain soon',
'Winds howl through the empty streets at night',
'Morning frost blankets the green fields',
'A lion roars under the blazing sun',
'A thick-furred bear roams snowy mountains',
'Birds sing before the rain, atop the city trees',
'Wolves howl, echoing through the forest',
'Deer graze as morning frost melts around them'
]
# 定义每个文档对应的类别标签
labels = ['weather', 'weather', 'weather', 'weather', 'weather', 'animals', 'animals', 'animals', 'animals', 'animals']
# 将文档列表转换为NumPy数组
corpus = np.array(corpus)
# 创建一个包含文档及其类别标签的DataFrame
corpus_df = pd.DataFrame({'Document': corpus, 'Category': labels})
# 定义文档预处理函数
def normalizedoc(doc):
# 使用正则表达式删除非字母数字字符
doc = re.sub(r'[^a-zA-Z0-9\s]', '', doc, flags=re.I)
# 转换为小写
doc = doc.lower()
# 去除首尾空白
doc = doc.strip()
# 分词
tokens = wpt.tokenize(doc)
# 过滤掉停用词
filtered_tokens = [token for token in tokens if token not in stop_words]
# 重新组合为文档字符串
doc = ' '.join(filtered_tokens)
return doc
# 使用np.vectorize函数向量化预处理函数,以便一次性处理整个数组
normalize_corpus = np.vectorize(normalizedoc)
# 对语料库中的每个文档应用预处理
normcorpus = normalize_corpus(corpus)
# N-Grams模型
bv = CountVectorizer(ngram_range=(2,2)) # ngram_range=(2,2)表示只考虑二元词组,用于捕获相邻单词的关系
bv_matrix = bv.fit_transform(normcorpus)
bv_matrix = bv_matrix.toarray()
vocab = bv.get_feature_names_out()
pd.set_option('display.max_columns', None) # 设置显示最大列数为无限
pd.DataFrame(bv_matrix, columns = vocab)
# TF-IDF模型
tv = TfidfVectorizer(min_df=0, max_df=5, use_idf=True) # 将文档集合转换为TF-IDF特征矩阵
tv_matrix = tv.fit_transform(normcorpus)
tv_matrix = tv_matrix.toarray()
vocab = tv.get_feature_names_out()
pd.DataFrame(np.round(tv_matrix, 2), columns = vocab)
# Similarity特征
similarity_matrix = cosine_similarity(tv_matrix) # 计算两个或多个文档之间的余弦相似度
similarity_df = pd.DataFrame(similarity_matrix)
similarity_df
# 聚类特征
km = KMeans(n_clusters = 2)
km.fit_transform(similarity_df)
cluster_labels = km.labels_
cluster_labels = pd.DataFrame(cluster_labels, columns = ['ClusterLabel'])
pd.concat([corpus_df, cluster_labels], axis = 1)
# LDA主题模型
lda = LatentDirichletAllocation(n_components=2, n_jobs=2, max_iter=100, random_state=42) # # n_components=2表示提取的主题数量,max_iter=100表示迭代次数,n_jobs=2表示并行运行的作业数量,random_state用于随机数生成器
dt_matrix = lda.fit_transform(tv_matrix)
features = pd.DataFrame(dt_matrix, columns=['T1', 'T2'])
features
# 词向量模型
wpt = nltk.WordPunctTokenizer()
tokenized_corpus = [wpt.tokenize(document) for document in normcorpus]
feature_size = 10 # 词向量的维度
window_context = 10 # 上下文窗口大小
min_word_count = 1 # 忽略总频率低于此值的所有单词
sample = 1e-3 # 对高频词进行下采样的配置阈值
w2v_model = word2vec.Word2Vec(tokenized_corpus, vector_size=10,
window=window_context, min_count=min_word_count,
sample=sample)
w2v_model.wv['sun']
# array([-0.01577653, 0.00321372, -0.0414063 , -0.07682689, -0.01508008,
# 0.02469795, -0.00888027, 0.05533662, -0.02742977, 0.02260065],
# dtype=float32)
# 这个数组是单词'sun'在模型中的词向量表示,每个数字对应词向量空间中的一个维度。
# 由于设置的feature_size为10,因此这个向量有10个维度。这个向量可以用来在
# 词向量空间中表示'sun',用于计算词语之间的相似度、寻找同义词等NLP任务。
def average_word_vectors(words, model, vocabulary, num_features):
"""
功能:计算给定单词列表的平均词向量。
参数:
- words: 单词列表。
- model: 训练好的Word2Vec模型。
- vocabulary: 模型词汇表。
- num_features: 词向量的维度。
返回值:给定单词列表的平均词向量。
"""
feature_vector = np.zeros((num_features,), dtype='float64')
nwords = 0
for word in words:
if word in vocabulary:
nwords += 1
feature_vector = np.add(feature_vector, model.wv[word])
if nwords:
feature_vector = np.divide(feature_vector, nwords)
return feature_vector
def average_word_vectorizer(corpus, model, num_features):
"""
功能:为整个语料库计算平均词向量。
参数:
- corpus: 分词后的语料库,每个元素是单词列表。
- model: 训练好的Word2Vec模型。
- num_features: 词向量的维度。
返回值:整个语料库的平均词向量数组。
"""
vocabulary = set(model.wv.index_to_key)
features = [average_word_vectors(tokenized_sentence, model, vocabulary, num_features)
for tokenized_sentence in corpus]
return np.array(features)
# 使用average_word_vectorizer函数计算语料库的平均词向量,并将结果转换为DataFrame
w2v_feature_array = average_word_vectorizer(corpus=tokenized_corpus, model=w2v_model, num_features=feature_size)
pd.DataFrame(w2v_feature_array)
# 输出结果(Out[18])示例:
# 0 1 2 3 4 5 6 7 8 9
# 0 0.002978 0.013262 0.012789 -0.018555 0.050005 0.000842 -0.000868 0.059669 -0.067598 -0.001516
# ...
# 9 -0.010244 -0.020123 -0.020692 0.016608 -0.004070 -0.016828 0.049279 0.033294 -0.028813 -0.020145
"""
输出结果说明:每行代表语料库中一个文档(或句子)的平均词向量。每列代表词向量的一个维度。
例如,第一行的词向量是第一个文档的平均词向量,由10个维度组成。
这些平均词向量可以用于文档的向量表示,适用于后续的机器学习或文本分析任务。
"""