本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.
1 介绍
我们发布过一篇文档《 GooSeeker分词和情感分析结果excel表怎样计算tf-idf 》,介绍了在excel中用公式计算tf-idf。本Jupyter notebook想达到相同的目的,但是,用python程序实现对tf-idf的计算。
在什幺场合下需要计算tf-idf?《 GooSeeker分词和情感分析结果excel表怎样计算tf-idf 》做了详细说明,在这里就不重复说了。在本notebook中重点对比一下计算tf或者tf-idf会对原始数据产生什幺样的影响。
GooSeeker分词和情感分析软件 导出的含有词频和文档频率的表有:
词频表:一个数据集的所有词的词频和文档频率
选词结果表:如果手工筛选了被分析词,那幺这些词的词频和文档频率都存在这个表中
选词矩阵表:上面两个表的词频值都是全局的,就是一个词出现在所有文档的次数,而这个表中的词频分别展示了出现在每个文档的次数,显然,可以用这个表做更进一步的统计计算,比如,进行PCA运算用于降维、计算文档相似度、计算词与词的距离、用社交网络图的方法分析主题组成等等
下面就为这几个表计算tf或者tf-idf。
2 使用方法
本次分析任务的操作顺序是:
- 在GooSeeker分词和文本分析软件上创建文本分析任务并导入包含待分析内容的excel,分析完成后导出词频表、选词结果表和选词矩阵表
- 将导出的excel表放在本notebook的data/raw文件夹中
- 从头到尾执行本notebook的单元
注意:GooSeeker发布的每个notebook项目目录都预先规划好了,具体参看 Jupyter Notebook项目目录规划参考 。如果要新做一个分析项目,把整个模板目录拷贝一份给新项目,然后编写notebook目录下的ipynb文件。
3 修改历史
2022-08-18:第一版发布
4 版权说明
本notebook是GooSeeker大数据分析团队开发的,所分析的源数据是GooSeeker分词和文本分析软件生成的,本notebook中的代码可自由共享使用,包括转发、复制、修改、用于其他项目中。
5 准备运行环境
5.1 引入需要用到的库
# -*- coding: utf-8 -*- import os import math import numpy as np import pandas as pd
5.2 常量和配置
在我们发布的一系列Jupyter Notebook中,凡是处理GooSeeker分词软件导出的结果文件的,都给各种导出文件起了固定的名字。为了方便大家使用,只要把导出文件放在data/raw文件夹,notebook就会找到导出文件,赋值给对应的文件名变量。下面罗列了可能用到的文件名变量:
file_all_word:词频表
file_chosen_word: 选词结果表
file_seg_effect: 分词效果表
file_word_occurrence_matrix: 选词矩阵表(是否出现)
file_word_frequency_matrix: 文档词频对应矩阵
file_word_document_match: 选词匹配表
file_co_word_matrix: 共词矩阵表
pd.set_option('display.width', 1000) # 设置字符显示宽度 pd.set_option('display.max_rows', None) # 设置显示最大 # np.set_printoptions(threshold=np.inf) # threshold 指定超过多少使用省略号,np.inf代表无限大 # 存原始数据的目录 raw_data_dir = os.path.join(os.getcwd(), '../../data/raw') # 存处理后的数据的目录 processed_data_dir = os.path.join(os.getcwd(), '../../data/processed') filename_temp = pd.Series(['词频','分词效果','选词矩阵','选词匹配','选词结果','共词矩阵']) file_all_word = '' file_seg_effect = '' file_word_occurrence_matrix = '' file_word_document_match = '' file_chosen_word = '' file_co_word_matrix = ''
5.3 检测data/raw目录下是否有待分析的GooSeeker分词结果表
本notebook只使用选词矩阵表和共词矩阵表,下面的代码将检查data/raw中有没有这两个表,如果没有会报错,后面的程序就没法执行了。
# 0:'词频', 1:'分词效果', 2:'选词矩阵', 3:'选词匹配', 4:'选词结果', 5:'共词矩阵' print(raw_data_dir + '\r ') for item_filename in os.listdir(raw_data_dir): if filename_temp[0] in item_filename: file_all_word = item_filename continue if filename_temp[1] in item_filename: file_seg_effect = item_filename continue if filename_temp[2] in item_filename: file_word_frequency_matrix = item_filename continue if filename_temp[4] in item_filename: file_chosen_word = item_filename continue if filename_temp[5] in item_filename: file_co_word_matrix = item_filename continue if file_all_word: print("词频表:", "data/raw/", file_all_word) else: print("词频表:不存在") if file_seg_effect: print("分词效果表:", "data/raw/", file_seg_effect) else: print("分词效果表:不存在") if file_word_frequency_matrix: print("选词矩阵表:", "data/raw/", file_word_frequency_matrix) else: print("选词矩阵表:不存在") if file_chosen_word: print("选词结果表:", "data/raw/", file_chosen_word) else: print("选词结果表:不存在") if file_co_word_matrix: print("共词矩阵表:", "data/raw/", file_co_word_matrix) else: print("共词矩阵表:不存在")
输出结果像这样:
/Users/work/workspace/notebook/GooSeeker分词软件导出的选词矩阵和共词矩阵的关系-二舅/notebook/eda/../../data/raw 词频表: data/raw/ 词频表-知乎-二舅.xlsx 分词效果表: data/raw/ 分词效果-知乎-二舅.xlsx 选词矩阵表: data/raw/ 选词矩阵-知乎-二舅.xlsx 选词结果表: data/raw/ 选词结果-知乎-二舅.xlsx 共词矩阵表: data/raw/ 共词矩阵-知乎-二舅.xlsx
6 读取数据表并存入矩阵
6.1 词频表
词频表含有所有自动分词得到的词,但是不含有手工添加的词。
6.1.1 读入Pandas DataFrame
df_all_word = pd.read_excel(os.path.join(raw_data_dir, file_all_word)) df_all_word.head()
6.1.2 统计总词数
参考 Get the number of rows in a Pandas DataFrame ,可以用shape[0]或者len()函数得到DataFrame的行数。
#num_word = df_all_word.shape[0] num_word = len(df_all_word) num_word
输出结果:14217
6.1.3 统计总文档数
在分词效果表中有所有文档,所以,用这个表统计文档数。先用Pandas读入该表,然后统计文档数。
df_seg_effect = pd.read_excel(os.path.join(raw_data_dir, file_seg_effect)) df_seg_effect.head(2)
num_doc = df_seg_effect.shape[0] num_doc
输出结果:829
6.1.4 增加TF列
df_all_word['TF'] = df_all_word['词频'] / num_word df_all_word.head(5)
6.1.5 增加IDF_2列和IDF列和IDF_10列
分别对应以2为底的对数,e和10为底的对数,以便对比
# math库中的log函数没有能力对一列数据逐个求log,要使用numpy库 #df_all_word['IDF_2'] = math.log2(num_doc / (df_all_word['文档频率'] + 1)) df_all_word['IDF_2'] = np.log2(num_doc / (df_all_word['文档频率'] + 1)) df_all_word['IDF'] = np.log(num_doc / (df_all_word['文档频率'] + 1)) df_all_word['IDF_10'] = np.log10(num_doc / (df_all_word['文档频率'] + 1)) df_all_word.head(5)
6.1.6 增加TF-IDF_2列和TF-IDF列和TF-IDF_10列
tf-idf = tf * idf,计算很简单
df_all_word['TF-IDF_2'] = df_all_word['TF'] * df_all_word['IDF_2'] df_all_word['TF-IDF'] = df_all_word['TF'] * df_all_word['IDF'] df_all_word['TF-IDF_10'] = df_all_word['TF'] * df_all_word['IDF_10'] df_all_word.head()
6.2 选词结果表
6.2.1 读入Pandas DataFrame
df_chosen_word = pd.read_excel(os.path.join(raw_data_dir, file_chosen_word)) df_chosen_word.head()
6.2.2 统计选词数
num_chosen_word = len(df_chosen_word) num_chosen_word
输出结果:133
6.2.3 增加TF列
df_chosen_word['TF'] = df_chosen_word['词频'] / num_word df_chosen_word.head(5)
6.2.4 增加IDF_2,IDF,IDF_10列
df_chosen_word['IDF_2'] = np.log2(num_doc / (df_chosen_word['文档频率'] + 1)) df_chosen_word['IDF'] = np.log(num_doc / (df_chosen_word['文档频率'] + 1)) df_chosen_word['IDF_10'] = np.log10(num_doc / (df_chosen_word['文档频率'] + 1)) df_chosen_word.head(5)
6.2.5 增加TF-IDF_2,TF-IDF,TF-IDF_10列
df_chosen_word['TF-IDF_2'] = df_chosen_word['TF'] * df_chosen_word['IDF_2'] df_chosen_word['TF-IDF'] = df_chosen_word['TF'] * df_chosen_word['IDF'] df_chosen_word['TF-IDF_10'] = df_chosen_word['TF'] * df_chosen_word['IDF_10'] df_chosen_word.head()
6.3 选词矩阵表
6.3.1 读入Pandas DataFrame
df_word_frequency_matrix = pd.read_excel(os.path.join(raw_data_dir, file_word_frequency_matrix)) df_word_frequency_matrix.head()
6.3.2 统计匹配上的文档数
num_chosen_doc = df_word_frequency_matrix.shape[0] num_chosen_doc
输出结果:729
6.3.3 创建TF-IDF_2矩阵
从一个DataFrame拷贝到另一个DataFrame的方法参看: Pandas Create New DataFrame By Selecting Specific Columns 。也可以参看 Pandas官网关于copy的用法
df_word_tfidf_2 = df_word_frequency_matrix.copy() df_word_tfidf_2.head()
6.3.4 在Pandas中像Excel一样做统计
参看 SUMIF and COUNTIF in pandas ,该文讲解了跟EXCEL对应的统计方法。
为了数出来每个词出现在多少个文档中,需要一长串处理,为了搞清楚这一长串处理是什幺意思,我们分解成多个步骤做演练。
6.3.4.1 用切片方法把选词矩阵矩阵中的数字切出来
下面这行代码其实生成了一个新DataFrame,只是我们没有赋值给一个变量存下来。
df_word_frequency_matrix.iloc[:, 2:].head(10)
6.3.4.2 找出符合条件的所有行
在上一步的基础上,我们再套一层处理,把数量>0的找出来。下面这行代码其实生成了一个新的DataFrame
df_word_frequency_matrix[df_word_frequency_matrix.iloc[:, 2:] > 0].head(10)
6.3.4.3 针对每一列统计不是NaN的数量
统计结果存到一个新的Series中
word_doc_count = df_word_frequency_matrix[df_word_frequency_matrix.iloc[:, 2:] > 0].iloc[:, 2:].count() word_doc_count.head(20)
可以试试怎样从Series中取得统计值
print(word_doc_count.iloc[0]) print(word_doc_count.iloc[1]) print(word_doc_count.iloc[2]) print('total ', len(word_doc_count), ' words. Same as ', num_chosen_word)
输出结果:
403
293
184
total 133 words. Same as 133
6.3.4.4 计算TD-IDF_2
计算方案1 : 使用下面的公式,df_word_frequency_matrix这个二维结构和word_doc_count这个一维结构一起计算,竟然自动匹配地如此准确。为了验证这个结果,接下来还有计算方案2和计算方案3,计算方法越来越初级。可以看到,计算结果一模一样。
df_word_tfidf_2.iloc[:, 2:] = (df_word_frequency_matrix.iloc[:, 2:] / num_word) * np.log2(num_doc / (word_doc_count.iloc[:] + 1)) df_word_tfidf_2.head()
计算方案2 :手工写一个循环,循环每一个所选词,注意,循环次数是num_chosen_word,不是num_word。
for idx in range(num_chosen_word): #print('idx: ', idx, '; value: ', df_word_frequency_matrix.iloc[0, idx + 2]) df_word_tfidf_2.iloc[:, idx + 2] = (df_word_frequency_matrix.iloc[:, idx + 2] / num_word) * np.log2(num_doc / (word_doc_count.iloc[idx] + 1)) df_word_tfidf_2
计算方案3 :手工写一个两层循环,分别循环所选词和匹配上的文档。注意,要用num_chosen_doc,不是num_doc,因为很多文档没有匹配上。
for i in range(num_chosen_doc): for j in range(num_chosen_word): df_word_tfidf_2.iloc[i, j + 2] = (df_word_frequency_matrix.iloc[i, j + 2] / num_word) * np.log2(num_doc / (word_doc_count.iloc[j] + 1)) df_word_tfidf_2.head()
6.3.5 把TD-IDF_2保存到excel中
在后续的notebook中,我们将用这些数据计算词与词之间的相关度,然后做网络分析,利用一些社会网络分析法进行计算和探索,所以,把计算好的td-idf选词矩阵存入excel中,放在data/processed文件夹中。
file_word_tdidf2_matrix = os.path.join(processed_data_dir, 'word_tdidf2_matrix.xlsx') with pd.ExcelWriter(file_word_tdidf2_matrix, engine='xlsxwriter') as writer: df_word_tfidf_2.to_excel(writer, sheet_name='Sheet1') workbook = writer.book worksheet = writer.sheets['Sheet1'] cell_format = workbook.add_format({'text_wrap': True}) worksheet.set_column('A:Z', cell_format=cell_format)
6.3.6 计算其他对数底数的TD-IDF
6.3.6.1 计算TD-IDF
df_word_tfidf_e = df_word_frequency_matrix.copy() df_word_tfidf_e.iloc[:, 2:] = (df_word_frequency_matrix.iloc[:, 2:] / num_word) * np.log(num_doc / (word_doc_count.iloc[:] + 1)) df_word_tfidf_e.head()
6.3.6.2 把TD-IDF保存到excel中
file_word_tdidf_matrix = os.path.join(processed_data_dir, 'word_tdidf_matrix.xlsx') with pd.ExcelWriter(file_word_tdidf_matrix, engine='xlsxwriter') as writer: df_word_tfidf_e.to_excel(writer, sheet_name='Sheet1') workbook = writer.book worksheet = writer.sheets['Sheet1'] cell_format = workbook.add_format({'text_wrap': True}) worksheet.set_column('A:Z', cell_format=cell_format)
6.3.6.3 计算TD-IDF_10
df_word_tfidf_10 = df_word_frequency_matrix.copy() df_word_tfidf_10.iloc[:, 2:] = (df_word_frequency_matrix.iloc[:, 2:] / num_word) * np.log10(num_doc / (word_doc_count.iloc[:] + 1)) df_word_tfidf_10.head()
6.3.6.4 把TD-IDF_10保存到excel中
file_word_tdidf10_matrix = os.path.join(processed_data_dir, 'word_tdidf10_matrix.xlsx') with pd.ExcelWriter(file_word_tdidf10_matrix, engine='xlsxwriter') as writer: df_word_tfidf_10.to_excel(writer, sheet_name='Sheet1') workbook = writer.book worksheet = writer.sheets['Sheet1'] cell_format = workbook.add_format({'text_wrap': True}) worksheet.set_column('A:Z', cell_format=cell_format)
7 总结
上面已经为词频表、选词结果表、选词矩阵计算了TD-IDF,期望压制一下高频词的打分,其实效果很有限:
TF-IDF会微调词频类似的高频词之间的排序
可以很明显调整文档频率极低的词的排序。
后面将利用选词矩阵进行社会网络分析,观察不同对数底数是否会有明显影响,以及对比与原始词频和经过协方差计算后再进行网络分析的不同。
Be First to Comment