在这篇文章中,我将通过机器学习中的线性回归来计算zipf定律中一个经验常数alpha,还会画TF-IDF的图像,此外还将简单介绍下与zipf、TF-IDF有关的知识。
在之前的一篇文章中我曾介绍过TF-IDF,但之后我又阅读了Ricardo Baeza-Yates和Berthier Ribeiro-Neto所写的《Modern Information Retrieval》,发现其中所讲述的有关IF-IDF部分的内容与我之前了解的有许多不同,所以便又写了这篇文章。
一、 Zipf定律
1.1 介绍
Zipf's Law 是一种经验观察到的语言现象,它最初是由语言学家 George Kingsley Zipf 在 20 世纪初提出的。虽然 Zipf's Law 主要在语言学领域被讨论,但它也在自然语言处理(Natural Language Processing, NLP)和信息检索(Information Retrieval, IR)等领域得到了广泛应用。在这些领域中,Zipf's Law 被用来研究词汇频率分布,并且在建模文本数据的统计特性方面发挥着重要作用。
1.2 概念
Zipf's Law 描述了词汇的使用频率与其在频率表中的排名之间的关系。按照 Zipf's Law,最常用的词汇出现频率最高,而随着词汇排名的降低,其出现频率也会迅速下降。
1.3 表达式
设是索引项的文档频率。对所有的索引项的文档频率按降序排列,并设n(r)是第r个项的文档频率,那么根据Zipf定律就会有:
其中,α是经验常数。
那么,我们就可以将之改写为:
其中的C同样是经验常数。在英语中可以用α=1来提供一种简单的近似,而在中文里,本篇文章正是要去计算它。
在我们先取α等于1等情况下,我们可以对等式左右同时取log,变形为:
其中的log都是以2为底。
在之后还可以变形,这样就得到了IDF的公式:
其中的IDFi称为索引项ki的反比文档频率。(关于TF的表达式一会再说)
1.4 python计算
接下来,我就将用python的线性回归模型来计算α在中文中的大小,注意,因为我引用的是一个kaggle中的一个数据集,其规模很大,所以我只在代码中对其进行切片,并只取用一小部分来计算。代码如下:
import jieba
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer'''文本预处理&停用词库'''
data_normal = pd.read_csv(r"C:\Users\20349\Desktop\ArtificialIntelligence\data_set\dataset\chinese_news.csv")
data = data_normal.iloc[:500]
data.dropna(inplace=True)# 删除有缺失值的行
N = len(data)
# 停用词库
with open(r"C:\Users\20349\Desktop\ArtificialIntelligence\wordCloud\stopWords.txt", 'r', encoding='utf-8') as swfile:stopwords = set(line.strip() for line in swfile)
# 文本预处理函数
def preprocess_text(text,stopwords):words = jieba.lcut(text)after_word = [w for w in words if w not in stopwords]# 处理后return ''.join(after_word)
data = data.copy()
for i in range(1,N):data.iloc[i,-1] = preprocess_text(data.iloc[i,-1],stopwords)'''计算alpha'''
word_str = ''.join(data.iloc[:,-1])
word_ls = list(jieba.cut(word_str))
# 统计词频
word_freq_dict = {word: word_ls.count(word) for word in set(word_ls)}
word_freq_df = pd.DataFrame(list(word_freq_dict.items()), columns=['word', 'frequency'])
# 排序
word_freq_df.sort_values(by='frequency', ascending=False, inplace=True)
# 排名与频率
rank = np.arange(1, len(word_freq_df) + 1)
freq = word_freq_df['frequency'].values
# log
log_rank = np.log(rank)
log_freq = np.log(freq)
# 线性回归
model = LinearRegression()
log_rank = log_rank.reshape(-1, 1) # 转换为二维数组
model.fit(log_rank, log_freq)
# 计算
alpha = -model.coef_[0]
print("Alpha(α) is:{}".format(alpha))
那么,最后输出的α值是这样的:Alpha(α) is:0.9978112574757174
(关于我引用的文本数据集所在的url如下:新闻联播(Chinese official daily news) (kaggle.com))
1.5 代码解释
然后是关于代码的一个解释。
我先给出流程图:
可以看见代码分为两部分,一部分是停用词库的文本预处理,一部分是α的计算,关于预处理方面,我们要做的就是单独拿出每一项中的文本内容然后用jieba函数库的函数进行分词处理并将存在于停用词库中的词语直接忽略,将其余部分再重新组合成字符串写入即可;而在α的计算方面,我们需要获得排序于频率,但此时式子是相除的形式,无法引用线性回归的模型,所以我们需要log化,这样就变为相加的形式了,如此带入模型即可求得结果。
二、 TF-IDF
2.1 概念
TF-IDF(Term Frequency-Inverse Document Frequency)是一种在信息检索与数据挖掘领域中广泛使用的统计方法,用于评估一个词在一个文档或语料库中的重要程度。TF-IDF是两个独立度量的乘积:词频(TF)和逆文档频率(IDF)。
2.2 TF
TF是指词频,意思是某个词在文档中出现的次数。一个词出现得越多,通常意味着它对文档内容越重要。然而,一些非常常见的词汇(如“的”、“是”等)可能频繁出现,但并不具有多少实际意义。因此,词频只是一个局部指标,并不能单独决定一个词的重要性。
其表达式如下:
2.3 IDF
IDF是指逆文档频率,逆文档频率是一个全局性的度量,它考虑了整个文档集或者语料库的情况。一个词如果在整个文档集合中出现的频次越多,那么该词的IDF就越低;反之则越高。通过这种方式,可以降低常见词汇的影响,增加独特或罕见词汇的重要性。
其表达式在刚才Zipf中已经推出。
2.4 TF-IDF
最流行的权重公式就是将IDF因素于词频结合起来的权重计算方法,公式如下:
2.5 python计算
代码如下:
# 计算IDF
IDF = {}
for key in total_words_freq.keys():IDF[key] = 0times = 0for i in range(N):if key in contentList[i]:times += 1idf_value = log(N / times, 2)IDF[key] = idf_value# 计算TF-IDF
tf_list = []
idf_list = []
tfidf = []
word_indices = []
number = 1
for key, value in sorted_TF.items():tf_list.append(value)idf_list.append(IDF[key])tfidf.append(value * IDF[key])word_indices.append(number)number += 1# 绘制TF和IDF散点图
X = [log(i+1, 10) for i in range(len(sorted_TF))]
x_index = [0, 1, 2, 3, 4, 5]
labels = [1, 10, 100, 1000, 10000, 100000]plt.figure()
plt.scatter(X, tf_list, color='red', marker='+', label='TF')
plt.scatter(X, idf_list, color='blue', marker='x', label='IDF')
plt.xticks(x_index, labels)
plt.xlabel("Log Word Number")
plt.ylabel("TF or IDF")
plt.legend()
plt.show()# 绘制TF-IDF图
plt.figure()
plt.scatter(X, tfidf, color='black', marker='+', label='TF-IDF')
plt.xticks(x_index, labels)
plt.xlabel("Log Word Number")
plt.ylabel("TF-IDF")
plt.legend()
plt.show()
代码所绘制出的图像为:
这两幅图像与书中所给出的用《Wall Street Journal》的文档集绘制的图像极为相似,不过应该是我的数据量远远小于书中这个华尔街日报的数据量的缘故,我的图像略显杂乱,有许多异常的数据点。
此上