前面进行了微博数据的抓取,简单的处理,这一篇进行学校微博的相似度分析。
这里试图计算任意两个学校之间的微博用词的相似度。
思路:首先对学校微博进行分词,遍历获取每个学校的高频用词词典,组建用词基向量,使用该基向量构建每个学校的用词向量,最后使用TF-IDF算法和余弦函数计算两个学校微博之间的相似度。
注:TF-IDF算法和余弦函数使用可以参照我前面记录的博客。余弦函数的计算使用了numpy模块。
按学校划分,每个学校微博先进行分词,遍历获取每个学校的用词词典worddict,将worddict以pickle方式保存在本地。
伪码如下:
word_results = 获取分词后学校微博
# 两重循环获取所有的单词,存储到worddict词典中
for r in word_results:
for w in r[0].split():
if worddict.has_key(w) == False:
worddict[w] = 1
else:
worddict[w] += 1
# 将该词典以pickle文件方式保存到本地
save_to_pickle_file(worddict)
利用前面的学校用词词典,遍历,提取出现次数大于10次的词组,保存为该学校的高频用词词典,以pickle方式保存。
伪码如下:
#高频用词词典
highworddict = {}
for word in worddict:
if worddict[word] > 10:
highworddict[word] = worddict[word]
# 将该词典以pickle文件方式保存到本地
save_to_pickle_file(highworddict)
用给定的两个学校的高频用词字典组合成一个基向量。构建基向量的意义是,这样两个学校的所有高频用词在基向量中都有特定的对应的位置,方便之后构建对应学校的用词向量。
伪码如下:
# 基向量字典
baseworddict = {}
# 添加第一个学校的高频词典到基向量字典
for word in highworddict1:
if baseworddict.has_key(word) == False:
baseworddict[word] = 1
# 添加第二个学校的高频词典到基向量字典
for word in highworddict2:
if baseworddict.has_key(word) == False:
baseworddict[word] = 1
# 基向量数组
basewordlist = []
# 将dict再转成list保存起来,这样每个词在数组中的位置就固定起来了
for bd in baseworddict:
basewordlist.append(bd)
构建两个与基向量等长度的list,所有在学校高频字典中出现的词均赋值对应的数值,所有没有在学校高频词典出现的词赋值为1。
伪码如下:
# 学校用词向量
school1_list = []
school2_list = []
# 保证学校用词向量的长度与基向量长度相同
for i in basewordlist:
# 所有出现在学校高频用词词典中的单词全部添加到学校用词向量的列表中,所有没出现的,列表中添加1
if highworddict1.has_key(i) == True:
school1_list.append(highworddict1[i])
else:
school1_list.append(1)
for i in basewordlist:
if highworddict2.has_key(i) == True:
school2_list.append(highworddict2[i])
else:
school2_list.append(1)
利用前面的学校用词向量计算词频值,再结合idf文档计算tf*idf值。
伪码如下:
# 学校用词向量的长度
sum_school_1,sum_school_2 = sum(school1_list),sum(school2_list)
# 得到学校常用词的tf频率列表
for i, value in enumerate(school1_list):
school1_list[i] = school1_list[i]*1.0/sum_school_1 * 1
for i, value in enumerate(school2_list):
school2_list[i] = school2_list[i]*1.0/sum_school_2 * 1
# 加载idf文件,这里已经处理成idf词典了
idfdict = get_idf_dict()
# 生成自己的idf列表
for i, value in enumerate(basewordlist):
if idfdict.has_key(value.encode('utf-8')) == True:
basewordlist[i] = idfdict[value.encode('utf-8')]
else:
basewordlist[i] = 3
# 得到学校常用词的tf*idf列表
for i, value in enumerate(school1_list):
school1_list[i] = school1_list[i] * basewordlist[i]
for i, value in enumerate(school2_list):
school2_list[i] = school2_list[i] * basewordlist[i]
最后使用numpy模块计算学校常用词tf-idf列表之间的余弦值。
伪码如下:
# 转化为numpy数组
array_1,array_2 = np.array(school1_list),np.array(school2_list)
# 计算两个向量的长度
len_1, len_2 = np.sqrt(array_1.dot(array_1)), np.sqrt(array_2.dot(array_2))
# 计算夹角的cos值
cos_angle = array_1.dot(array_2)/(len_1*len_2)
# 计算弧度制夹角
angle = np.arccos(cos_angle)
每个学校的高频(出现次数大于10次)用词数量在三千到四千左右,任意两个学校之间的高频词差异在五百左右。
任意两个学校的微博高频用词相似度结果为:
学校名称 | 大工 | 清华 | 北大 | 南大 | 华政 |
---|---|---|---|---|---|
大工 | 33.35 | 34.21 | 28.25 | 32.37 | |
清华 | 33.35 | 24.77 | 24.46 | 32.86 | |
北大 | 34.21 | 24.77 | 26.16 | 33.50 | |
南大 | 28.25 | 24.46 | 26.16 | 27.36 | |
华政 | 32.37 | 32.86 | 33.50 | 27.36 |
由上表可以看出,其五个学校的微博用词相似度是差不多的,任意两个学校的用词相似程度均在30度左右。而余弦角度取值在[0,90],其0度表示完全相同,90度表示完全无关,30度可以认为较为相似。
这里的基向量构建是使用两个学校之间高频用词组建的,进行了十组比较,也就构建了十组基向量,而我觉得,这样构建基向量的方式应该不恰当,而应该以一个包含所有用词的词组为基向量,在这个的基础上进行微博相似度的比较。当然,这里TF-IDF的使用只是依葫芦画瓢,并不清楚这样做得到的结果是否代表两个学校用词相似度。