这篇文章接着上篇的分析。
工具准备:
python3.6 (jieba,scipy,matplotlib库)
上篇数据分析的主要问题在于一些非技术词拥有太高的IDF值,所以影响了最后的结果。
所以这次的解决方法是,先通过构造每节课的关键词one-hot向量,然后对one-hot向量用余弦定理来算相似度,把相似度较高的课聚在一起(层次聚类),理想的情况是,把所有计算机的课聚在一起,所有金融的课聚在一起。最后找到所有类里的那些公共词,把它们删除。
首先先恢复上次的数据,以及准备 构造one-hot所需要的索引,代码如下:
data_list=[]
with open('opencourse.json','r') as file_object:
data_list = json.load(file_object)
word_index={}
index_word={}
count=0
for item in data_list:
temp_analyse = jieba.analyse.extract_tags(item["productName"])
for temp in temp_analyse:
if word_index.get(temp) ==None:
word_index[temp]=count
index_word[count]=temp
count+=1
temp_analyse = jieba.analyse.extract_tags(item["description"])
for temp in temp_analyse:
if word_index.get(temp) ==None:
word_index[temp]=count
index_word[count]=temp
count+=1
在这里总共有15955个关键词,所以one-hot 向量的维度是15955,接下来就是使用scipy进行聚合。
import scipy
import scipy.cluster.hierarchy as sch
import matplotlib.pylab as plt
word_tensor=scipy.zeros((3000,count)) #3000 courses * 15955 key words
for i in range(3000): #iterate 3000 course to build keyword vector
temp_analyse = jieba.analyse.extract_tags(data_list[i]["productName"])
for temp in temp_analyse:
word_tensor[i][word_index[temp]]+=1
temp_analyse = jieba.analyse.extract_tags(data_list[i]["description"])
for temp in temp_analyse:
word_tensor[i][word_index[temp]]+=1
disMat = sch.distance.pdist(word_tensor,'cosine') #using cosine as distance
Z=sch.linkage(disMat,method='average')
P=sch.dendrogram(Z) #build the figure
plt.savefig('figure.png')
plt.show()
cluster= sch.fcluster(Z, t=1.15465) #get different classes
画出来的图会变成如下:
然而由于数据太多,显示效果略差,数据少的图应该是如下:
值得一提的是最后一行代码,有兴趣的朋友可以直接去看官方文档。fcluster()可以将我们计算好的Z分成不同类,实际上还有一个参数criterion,默认为“inconsistent”。意思是两个nodes的间距大于t参数,那么就分开。还有一个模式是“maxclust”,意思是强行分成t个clust。明显,后者更适合我们,我们需要程序自动分成 计算机,金融,平面设计等等的clust。然而结果并不好,这是代码和分类的结果:
cluster= sch.fcluster(Z, t=10,criterion='maxclust')
plt.plot(cluster)
显而易见的是大部分数据被分在了第10类。因为这种模式下,程序直接取了前9类,剩下的所有类归位第10类。所以我们更希望得到的是均匀分布的clust。于是在“inconsistent”模式下,我就用二分法试出了1.15465这个值。它会分成79类,结果如下:
显然分布更均匀,接下来就是把在所有类里普遍出现过的词统计出来,并把它们删除。
words_in_group={}
useless_words = []
for i in range(3000):
if words_in_group.get(cluster[i])==None:
words_in_group[cluster[i]]=scipy.zeros((1,count))
words_in_group[cluster[i]]+=word_tensor[i]
for i in range(count):
c=0
for j in range(1,80):
if words_in_group[j][0][i]>0: #error, forget to reshape
c+=1
if c>15: #word appeared more than 15 is useless word
useless_words.append(index_word[i])
new_word={}
for item in word_count:
if item not in useless_words:
new_word[item]=word_count[item]
x=sorted(new_word.items(),key=lambda item:item[1],reverse=True)
无用词结果如下:
['课程',
'一起',
'答疑',
'教程',
'课时',
'2017',
'购买',
'课堂',
'案例',
'更新',
'网易',
'视频',
'分钟',
'QQ',
'微信',
'进阶',
'学习',
'章节',
'设计',
'讲解',
'内容',
'高手',
'下载',
'速成',
'老师',
'软件',
'欢迎',
'入门',
'主讲',
'培训',
'考试',
'同学',
'使用',
'学员',
'系统',
'我们',
'轻松',
'提升',
'职场',
'技能',
'学会',
'掌握',
'可以',]
截取了一小部分,这些词的确就是上一章想要排出的词。最后的结果如下:
[('开发', 218),
('study', 211),
('163', 201),
('PPT', 199),
('英语', 179),
('Excel', 163),
('PS', 162),
('htm', 138),
('编程', 119),
('摄影', 117),
('游戏', 112),
('动画', 103),
('Java', 98),
('项目', 88),
('导图', 87),
('series', 85),
('Photoshop', 82),
('玩转', 81),
('数学', 79),
('图表', 78),
('时间', 78),
('运营', 78),
('网页', 75),
('高级', 72),
('会计', 72),
('直播', 71),
('1001284001', 70),
('产品', 70),
('企业', 69),
('语法', 68),
('搞定', 66),
('交流', 66),
('Python', 66),
('面试', 66),
('UI', 65),
('微课', 65),
('函数', 63),
('阅读', 62),
('APP', 60),
('C语言', 60),
('数据库', 60),
('course', 59),
('日语', 59),
('淘宝', 58),
('排版', 58),
('平面设计', 57),
('全套', 57),
('iOS', 57),
('PHP', 57),
('读书', 56)]
新的单词更有指向性,都是更明确的专业术语,虽然还残留一些无用词,但是改进一些系数应该可以或多或少提高准确性。改进空间在于,删除了那些无用词,vector也会随之而改变,可以继续迭代多次同样的操作,可以使得分类更准确。
模型改进和更多的数据分析将在下一章。