/textClustering

Primary LanguageJupyter Notebook

背景介绍

由于项目需要,需要对旅游游记文本进行聚类,为打标签做指导,所以调研了主流的短文本聚类方法,文本聚类主要还是分成两个方面。

1. 提取文本特征

在《数学之美》前几章中,详细讲了为何要将文本这个自然语言领域的事物,转换成数学领域能处理的向量、矩阵。为了分析一段文本,我们需要首先得到这段文本的表示向量,这个向量就可以作为文本的特征输入决策器中进行判决。

2. 聚类算法选择

这里的聚类算法就是上面说的决策器。聚类算法主要分成两大类,一类是基于距离的迭代算法,比如k-means,还有一类是基于密度的流式聚类算法,比如DBSCAN。他们各有优劣,通常由于我们并不清楚聚类的簇数量,并且由于海量文本迭代的效率比较低,真实应用场景中,我们在聚类算法的选择上,更加倾向选DBSCAN这类的算法。

本文做了几组对照实验,分别使用tf-idf或word2vec作为文本的特征,采用k-means或者DBSCAN进行聚类分析。实验流程如下:

实验流程

1. 中文文本预处理

将清洗过的数据进行分词、去停用词。其中分词的时候,载入预先设置好的自定义词典,提高分词精度。笔者自己写了一个分词的类,提高代码复用率。

from tools.tokenizer.wordCut import WordCut


mydict = ["mysenicdict.txt", "myfooddict.txt"]
file_path = '/home/zcy/haiNan/texttravelgen/data/clean_comments.txt'
# 默认是精确模式
test = WordCut()
test.addDictionary(mydict) # 加载自定义词典
 # 分词,去停用词(集成在类中了),不显示在console,保存分词后的文件到file_path目录
test.seg_file(file_path, show=False, write=True)

2. 特征提取

- Tf-idf
# 词频矩阵:矩阵元素a[i][j] 表示j词在i类文本下的词频 
vectorizer = CountVectorizer()
# 统计每个词语的tf-idf权值
transformer = TfidfTransformer() 
freq_word_matrix = vectorizer.fit_transform(corpus)
#获取词袋模型中的所有词语
word = vectorizer.get_feature_names()
tfidf = transformer.fit_transform(freq_word_matrix)
# 元素w[i][j]表示j词在i类文本中的tf-idf权重
weight = tfidf.toarray()z
- word2vec
# doc2vec
#训练并保存模型
import gensim

sentences = gensim.models.doc2vec.TaggedLineDocument(token_path)
model = gensim.models.Doc2Vec(sentences, size=100, window=2, min_count=3)
model.train(sentences,total_examples=model.corpus_count, epochs=1000)
model.save('../model/demoDoc2Vec.pkl')

3. 聚类算法

- k-means
# K-means聚类
print 'Start K-means:'
from sklearn.cluster import KMeans
clf = KMeans(n_clusters=20)
s = clf.fit(model.docvecs)
print s
#20个中心点  
print(clf.cluster_centers_)        
#每个样本所属的簇  
print(clf.labels_)  
i = 1  
while i <= len(clf.labels_):
    print i, clf.labels_[i-1]  
    i = i + 1    
#用来评估簇的个数是否合适,距离越小说明簇分的越好,选取临界点的簇个数  
print(clf.inertia_)
- DBSCAN
# dbscan 密度聚类
from sklearn.cluster import DBSCAN

# Compute DBSCAN
db = DBSCAN(eps=0.005, min_samples=10).fit(weight)
print db.core_sample_indices_
db.labels_

实验结果

为了将聚类后的类别信息与原文信对照起来,方便查看,笔者写了一个类提高重用效率,将结果写到ori_path的路径下,并提供了排序的功能,代码如下:

from tools.labelMap.labelText import LabelText

label = clf.labels_
ori_path = "../data/clean_comments.txt"
labelAndText = LabelText(label, ori_path)
labelAndText.sortByLabel(write=True)

- tf-idf + k-means聚类结果

只举几个label来看:

new file saved in /home/zhouchengyu/haiNan/texttravelgen/data/sortedLabelText.csv
0	一下机场携程订的专车很准时的来接了我们,服务也很好,经过大约40分钟的车程,我们从凤凰机场来到了亚龙湾。
0	下午18:35坐动车返回美兰,住在机场附近小旅馆,老板人倒是挺好,挺便宜,装修这些也算对得起这个价格了。
0	中午十二点,飞机准时到达海口美兰国际机场。到达厅内,爷爷奶奶早已等待多时。
0	祥鹏航空8L9963,特价机票,加上机场建设费及燃油费等约300。我们老大火速抢完了27人的机票,带着这个超级散团,出发!
0	到了海南一下飞机,湿热的空气就迎面扑来。没几步路就出汗了。出了机场赶紧找订好的住宿的地方。
0	作为一个北方人去过的最南端就是福州了,也是今年才去的,一般都在武汉止步。终于在北京等了个把星期,可以坐上飞机出发啦~~~
0	新加坡的过境签相当方便,填一张入境卡就可以了,而且居然不用排队。兴冲冲地通过海关后发现机场的两小时的免费观光大巴居然是在转机区,而不是入境后,只好换了100人民币的新币开始自助公交游。从机场坐地铁到Raffles Palace,去找鱼尾狮公园(Merlion Park)。奇怪的是这么有名的地标性景点一路上居然没有任何指示……雕像附近合影的人超多,大家都是到此一游。
0	所有的机场大巴都绕来绕去从同一条线路开往机场了,40分钟后到达机场
0	樟宜机场被多家机构评为世界最佳机场是不无道理的。整个机场就像一个购物休闲中心,吃喝玩乐各项设施应有尽有。在这里转机丝毫不用担心如何消磨时间。新加坡机场的登机一般提前一个小时,因为安检被安排在了各个登机口。这样布局的好处是在机场里可以畅行无阻。加上新加坡机场实际上只有国际区没有国内区(全国就这一个机场嘛),因此除了边检,其他区域都是连成一片的。
0	上班之后,基本每次出门都是想要叫车。但是这次想来一次随心所欲的旅行,从出发开始就不再走便捷的方法了,机场大巴走起。这才发现,志诚丽柏那个酒店门口的大巴是半小时发一次,10分一次,40分一次。会先到西稍门,然后才出发。
0	用银行贵宾卡享受了机场贵宾室

label0都与机场有关,可以看出来聚类效果还是不错的。

3	在沙滩上玩了一会我就去附近泳池边的WC换泳衣,回来和LILY扑向大海试图游泳。其实浪还是挺大的,我们在靠近沙滩的地方都不太能稳住自己,远处几个金发的外国姑娘却能在浪里漂浮自如,也许人家从小在海滩玩到大的吧!羡慕啊。    我在水里玩的不亦乐乎,LILY时刻紧盯着我的皮肤怕我晒伤,我很惊讶他有着能看出我皮肤被晒黑程度的能力,我自己看不出来……在海里玩了半小时的样子他果断拖回乐不思蜀的我,说再晒我就要回去哭了。
3	南湾猴岛其实是个半岛,但这里的位置得天独厚,三面环海,景色和离岛一样的美。除了拥有优越的热带海岛生态环境、猕猴特色资源、优质的海水以及滨海沙滩,还有水上疍家鱼排的独特民俗风情。全国最长的跨海观光索道,犹如一条凌空彩链横跨新村港湾,将神秘的南湾猴岛、迷人的热带港湾、浓郁的疍家民俗、喧闹的渔港风情等串成一线。
3	大东海是三亚我常去的沙滩,其他地方不是下饺子就是煮馄饨。
3	刚上船的时候心情还是挺激动的~想象岛上迷人的风景,结果到站之后看到码头左边的天空还有点蓝色了,就先往左边走去看看,一路上人都很多,零星的开着几个小店,大概走了100多m的样子都都到头了,路封着的,一堆建筑垃圾在哪儿堆着,也没看见机械设备动工。于是只能调头往回网右边走,其实右边一来我就看见了只有很小一片沙滩,我还以为左边会有一大片沙滩和浮潜的海域等着我们呢~越往右边走越是失望啊,先经过美食一条街,各种高价的食品和纪念品出售,等终于穿过美食街的人群到了海边那更是失望,比大东海划分的每个游泳区域还要小一半以上~还只有三个区域,完全没得浮潜地方!我也是醉了,我还以为是像东南亚那些海岛一样,上岛都是很宽泛的游泳和浮潜区域,结果。。。而且这个区域离码头也不远,水质可想而知,当然人也非常多,瞬间没了下海的欲望~真不知道网上那些好评怎么来的~商业化的气息太重了,我不相信大多数人来这里是为了去深潜去玩那些海上项目~家人都说还不如在大东海游泳,还要花100多的门票来看这乌泱泱的水~还好海边沙滩椅收费不贵,15块一张随便躺
3	三亚自游行心得1、我不想去景点打卡,只为纯度假。所以选择住大东海,我住在大菠萝(类似于京华城)附近的哈曼酒店。去年才开的五星酒店,设施完备,吃住行都方便!哈曼有私家沙滩,有酒店电瓶车接送,服务很贴心!不是所有酒店都有私家沙滩,需看清。如果住在没有私家沙滩的酒店,各种不便!我住的是哈曼的16楼行政山海房,(最高17层)记住:一定要高楼层,楼层低了什么都看不到2、大东海商业发达,价廉物美,只是海水和沙滩略逊亚龙湾一筹。                               3、交通:因为我住大东海,很便利,没有租车的必要。去较远的景点、接送机等,我全程易到专车、滴滴专车,非常方便4、关于第一市场:易到司机告诉我们,那已经相当于旅游商店的性质了,大东海区域用餐,我都在大菠萝。
3	从照片看就知道这时候的三亚天气不是很好,时常乌云甚至下雨,所以找出来的照片好不好看很大程度取决于天气怎么样啦大东海海滩上人很多,长长的海岸线上都是人,我去的这个时候天不是很热,海水还是有些凉的,多以游泳的人并不多,大多数都在沙滩上捡贝壳或石头。
3	收拾完毕!步行至大东海广场的沙滩~脱鞋玩水啦~!
3	亚龙湾是很长一个海湾。沙滩除了名地细腻。有很多的星级酒店私人沙滩。当然我们去的是公共开放海滩,建议四点以后再去游泳,否则日晒很严重。我和小果果都在阴凉下。

第3类都与沙滩有关,聚类效果也不错。

- word2vec + k-means 聚类结果

1	直到回来后还在流连成都老火锅的味道。真的很好吃。用牛油做锅底,加热后牛油化了,根本不用加水的。
1	离开宽窄巷子,回酒店附近吃了小天鹅,午睡过后下午去人民广场喝茶采耳。
1	黄流老鸭:海南最有特色的美食之一,在三亚,最正的黄流老鸭还是在胜利路的光明黄流老鸭店,十多年的老店,黄流老鸭必然是白切的才是最好的,也是最好吃的,再加上微热的蘸料,就更美味了,我们俩人点了白切黄流老鸭、虾酱地瓜叶和冬瓜海螺汤,冬瓜海螺汤,可以说是此次去三亚吃到的最好吃的汤品,其他地方吃到的总有那么些不新鲜的无奈~,这的冬瓜海螺汤太让我喜欢了,现在想起来都能感觉到的味美~当然,鸭肉那可是吃得精光的~,海南的特色美食啊~~
1	很多老人在这里,聊天,喝茶,打牌,老成都的生活。我们也喝了盖碗茶,叫了师傅来采耳,享受安逸。
1	第三次登临这座热带岛屿。2013年来的时候还是一个刚上大一的小姑娘,在海边遇到同是一个人来三亚游玩的泥巴,后来成为了朋友,在上海的时候还一起约着吃过饭,逛过上海博物馆,在夜晚的浦江边散步拍照。    2014年清明,趁着假期,去了海口,约见了在海南念书的闺蜜,住在海口巴纳纳国际青旅和一群来自五湖四海的朋友一起玩杀人游戏到凌晨三点多,第二天醒来和青旅认识的姑娘一起逛海南的菜市场。来自济南的她对南方的蔬果特别感兴趣,她说,因为海南的水果多,于是她就考了个海大的研究生,准备过来捞水果了。    2015年国庆过后,和一起奋战过高考的好朋友一起,在不同的城市出发来到三亚找在三亚念书的闺蜜。一起住在三亚老班长国际青旅,和青旅的义工老板们,去吃了三亚最好吃的炒冰炸鸡,去大东海游泳玩沙子,好是快活。
1	从北京西开出的Z201次列车,在漫长的27小时行驶后来到了我的城市。晚上吃过晚饭,八点多到火车站候车,第二天早上八点就能到三亚了。全程762公里,途中跨越琼州海峡,火车会被拆分成五节运上粤海轮渡,抵达海南岛接驳后将继续行驶。(前三图来自网络,侵删。)
1	海南鸡饭:鸡饭的主料是鸡和大米,最好的鸡饭选用的作料是“文昌鸡”。由于“文昌鸡”供不应求,一般鸡饭摊档选用本地杂色鸡,要求是刚成熟而尚未下蛋的鸡,以1至1.5公斤重为宜。大米选用上等新鲜的优质米,鸡是白切鸡。鸡饭皮色油黄,肉白且嫩,骨髓带血,吃来清甜爽口。这种米饭,油润软滑,香浓味爽。
1	出发前在老班长国际青旅订好住宿。位置就在吉祥街,径直往海边走不到五分钟,吉祥街口有到各个景点的汽车公交,招手即停,交通十分便利。周围有海南最大的超市旺豪超市,还有很多吃东西的小饭馆,住下来不用愁吃的。
1	三个人一起逛超市看海鲜买水果,海洋动物多的就像水族馆。因为海南气候原因,种出来的水果都像是放大版的。(如果不想在街头小贩那里买不足称的水果,可以来超市看看,一般海南的各种水果在这里都可以买到。)
1	清补凉是三亚当地的一种小吃。将红枣、薏米、绿豆、芋头、西瓜、汤圆等煮熟的东西,淋上椰子汁或糖水,清热消暑,是夏季必备的饮品。在冬天也可以吃到热的清补凉。清补凉摊多是设在路旁,摆上一席小桌子和小橱窗,旁边摆上一个保温冰桶,几套塑料的椅子和木桌。清补凉摊的小橱窗里放着一排塑料碗,碗里面分别装着糖水煮的芸豆、煮好的绿豆、通心粉、鹌鹑蛋、菠萝丁、西瓜丁、桂圆肉、红枣、薏米等等,很是诱人

可以发现,类别1的输出基本都是美食,但是也有一些错分的情况发生,考虑到Doc2Vec输出的向量跟向量大小、迭代次数等参数,影响较大,这只是一个Doc2Vec的baseline,这些错误聚类暂时还是可以接受的。

类别12主要是景区的介绍:

12	亚龙湾位于**最南端的热带滨海旅游城市——三亚市东南28公里处,是海南最南端的一个半月形海湾,全长约7.5公里,是海南名景之一。亚龙湾沙滩绵延7公里且平缓宽阔,浅海区宽达50-60米。沙粒洁白细软,海水澄澈晶莹,而且蔚蓝。能见度7-9米,适合潜水。海底世界资源丰富,有珊瑚礁、各种热带鱼、名贵贝类等。年平均气温25.5°C,海水温度22-25.1°C,终年可游泳,被誉为“天下第一湾”。.
12	继续前行,今天的目标是另一个好地方,这里虽然现在知名度不高,但其实开发的很早,曾经和五公祠、鹿回头、天涯海角、大小洞天等景点齐名,既有景色,又有深厚的人文,也是海南四大名菜的出产地之一,东山羊的那个东山,就是这里。好了,不卖关子了,这里就是万宁的东山岭,虽然海南最高的山是五指山,但这里才是传说中的“海南第一山”。东山岭风景区在万宁市区往东2公里,因为三峰并峙,形似笔架,历史上又叫笔架山。这里海拔虽然只有184米高,但是遍山都是奇石,“一线天”胜景之处有块风动石,重达百余吨,能在海风的吹拂和人力的推摇下产生晃动。当年《红楼梦》剧组拍片头的飞来石,也曾经到这里来考察过,虽然最后选择了黄山之巅的飞来石,但说明那个时候的东山岭就已经很著名了。可惜三亚的崛起,已经让人们快要把这里淡忘了。
12	拉市海位于丽江县城西面10公里处的拉市坝中部,是云南省第一个以“湿地”命名的自然保护区。“拉市”,是古纳西语的音译,“拉”为荒坝,“市”为新,意为新的荒坝。拉市海是迁徙候鸟的栖息地,每年到此越冬或停歇的候鸟有80多种,为滇西北之冠。拉市海边山清水秀,森林茂密,花草繁盛,清幽秀美。在拉市海一日游,内容大都差不多,无非就是骑马、划船、马帮饭等。但价格不等,从几十元到几百元都有,这就需要游客擦亮双眼。价钱特别便宜的最好别选,很可能隐藏其他强制性消费,200左右价格比较适中,较为靠谱。总体来讲,拉市海作为丽江的著名景点,值得一去。
12	我给大家按照从海口出发顺时针环岛方向推荐一下比较值得去的地方(没去过的肯定还有很多好地方,但只推荐比较了解的,高门票景点一律排除,只保留了南山寺和冯小刚,我觉得可以值回票价):海口市的海南省博物馆、琼台书院、五公祠、骑楼老街、世纪大桥、冯小刚电影公社、火山群地质公园;文昌市的孔庙、铜鼓岭、石头公园、东郊椰林;琼海市的博鳌禅寺、和乐镇港北港;万宁市的东山岭、大花角、大洲岛、加井岛;陵水县的日月湾海门游览区、陵水新村疍家渔排;三亚市的海棠湾海棠广场、亚龙湾海底世界、三亚湾椰梦长廊、太阳湾、大东海、小东海、鸿洲国际游艇码头夜游三亚湾、半山半岛帆船港、鹿回头山顶公园、凤凰岭、临春岭、白鹭公园、南山文化旅游区、崖城学宫;五指山市的水满河热带雨林风景区;乐东县的莺歌海盐场、尖峰岭;东方市的鱼鳞洲、大广坝、白查村;昌江县的棋子湾峻壁角;儋州市的东坡书院、千年古盐田、峨蔓火山海岸、石花水洞、松涛天湖;澄迈县的罗驿古村、邻昌礁。安排出行计划就从这里面挑吧,这些景点就足够玩上半个多月了。如果不喜欢历史人文,只喜欢风光的就少选其中的人文景点。如果像我们一样都喜欢,那么这些景点一定都不会让你们失望的。

可以看出,两种特征聚类得到的文本,粒度层次是有差别的,这正好有利于提取不同层次的聚类信息,构建不同粒度的文本语料库。

DBSCAN的聚类效果跟参数eps设置关系很大,虽然理论上基于密度的聚类算法要更优一些,但是实验过程表明,在文本数量较少时,还是k-means这样的迭代算法,来的实用些(调参更简单....)