9

Google Plus 文本提取与分析

 2 years ago
source link: https://luzhijun.github.io/2016/10/19/google+%E6%96%87%E6%9C%AC%E6%8F%90%E5%8F%96%E5%92%8C%E5%88%86%E6%9E%90/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Google Plus 文本提取与分析

本文所有数据源自google+,全篇围绕五个方面来进行文本提取和分析:

  1. 特征词提取
  2. 文本相似度

除此之外本文还设计到情感词分析,齐普夫定律等。其他方法像摘要自动提取、意见挖掘、文本聚类、新闻分类等常规文本分析内容并不适合google+的数据集,因此本文没有涉及。

google+ api 获取授权: 94917912.jpg 左侧栏第三个,点“凭据”,创建api密钥。这里用api密钥就可以,毕竟只采集公共数据信息,不是用户隐私数据(需要用户认证)。 60559851.jpg
Google+ API文档中具体列出了使用方法。此外,有专门的API浏览器可以根据查询条件快速生成RESTful对应的url地址,得到查询结果。(使用之前先设置右上角的API id)

RESTful API

以查询某个用户为例。

  1. 使用API浏览器 22885447.jpg72652739.jpg
  2. 直接浏览器抓取
curl "https://www.googleapis.com/plus/v1/people?query=Trucy+Luce&key=$api_key"

{
“kind”: “plus#peopleFeed”,
“etag”: “"xw0en60W6-NurXn4VBU-CMjSPEw/ycgzanUve1bCMxC0NXlP6C4MSTM"”,
“selfLink”: “https://www.googleapis.com/plus/v1/people?query=Trucy+Luce&key=AIzaSyB2_mjqVwT5IpqGO8wfASMdnHUuvxwQqlI”,
“title”: “Google+ People Search Results”,
“nextPageToken”: “CAESFTExMjAzMzk2OTk4NDI0NTc3MzQ3NQ”,
“items”: [
{
“kind”: “plus#person”,
“etag”: “"xw0en60W6-NurXn4VBU-CMjSPEw/xLkYpT8h4zlkDrhCUQcTzEZDl1U"”,
“objectType”: “person”,
“id”: “112033969984245773475”,
“displayName”: “Trucy Luce”,
“url”: “https://plus.google.com/112033969984245773475”,
“image”: {
“url”: “https://lh3.googleusercontent.com/-L0oIZ63NyHk/AAAAAAAAAAI/AAAAAAAAABg/xr0lpRdSDLM/photo.jpg?sz=50”
}
}
]
}

关于json中key的解释,可以在API文档中找到。

利用python SDK

google api for python 有两个版本,一个是oauth2授权的,另一个就是简单的api_key授权的。我们使用第二个,这是其API文档。该客户端已经支持python3版本,这里本文代码都以python3为基础。

import httplib2
import json
import apiclient.discovery # pip install google-api-python-client

Q = "Trucy Luce"
API_KEY = '自己输入' 
service = apiclient.discovery.build('plus', 'v1', http=httplib2.Http(), developerKey=API_KEY)
people_feed = service.people().search(query=Q).execute()
print (json.dumps(people_feed['items'], indent=2))

build方法详细查看代码中的api说明,返回一个与服务交互的资源对象(” A Resource object with methods for interacting with the service. “ )。而这个对象实际上是调动了 build_from_documen这个方法,这个方法返回的是googleapiclient.discovery.Resource资源对象,定位到这个Resource资源对象,但仔细查找发现其方法下面没有people()方法,但有三个生成方法的方法:

  1. _add_basic_methods
  2. _add_nested_resources
  3. _add_next_methods

实际上这三个方法是根据response的schem层次结构来生成的,这里的代码值得学习。 最后只打印items部分,程序执行结果如下:

[
{
“etag”: “"xw0en60W6-NurXn4VBU-CMjSPEw/xLkYpT8h4zlkDrhCUQcTzEZDl1U"”,
“displayName”: “Trucy Luce”,
“objectType”: “person”,
“image”: {
“url”: “https://lh3.googleusercontent.com/-L0oIZ63NyHk/AAAAAAAAAAI/AAAAAAAAABg/ xr0lpRdSDLM/photo.jpg?sz=50”
},
“id”: “112033969984245773475”,
“kind”: “plus#person”,
“url”: “https://plus.google.com/112033969984245773475”
}
]

接下来挖掘下某个用户的近期活动,实际上就像推特或者一条说说。这次挑个说中文的“Mulin Hong”。

USER_ID = '102121409478764742904' # Mulin Hong
service = apiclient.discovery.build('plus', 'v1', http=httplib2.Http(), developerKey=API_KEY)
activity_feed = service.activities().list(
  userId=USER_ID,
  collection='public',
  maxResults='100' # 最大允许记录条数
).execute()
print (json.dumps(activity_feed, ensure_ascii=False,indent=2))

service.activities().list方法有几个必要参数,userId:活动发起者Id。可选参数:collection:活动归属的集,默认为public,还是看下面图片吧:

84664354.jpg

其他参数可以通过命令help(service.activities().list)来查看。 由于共7000多行,不方便直接放入文章,可以点击查看内容。

如果仔细观察内容,你会发现content中有许多html标签,像<br>之类的在文本中应该去除,这里用到python Beautifulsoup4包1,(Beautiful Soup)已成为和lxml、html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度,提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据。更多关于Beautiful Soup的内容可以参见学习教程2

随便拿条内容: 58368208.jpg 可以发现里面除了含有html标签还有BOM字符(\ufeff),使用bs4去除: 17333322.jpg

我们上面只拿了100条记录,能不能拿全部记录呢?我们在看一下爬下的json文件,发现第一行显示nextPageToken,也就是说还有下一页,我们可以通过service.activities().list_next方法拿到下一页的resopnse。最后我们拿到所有json并用上面方法清洗整理。

import os
import httplib2
import json
import apiclient.discovery
from bs4 import BeautifulSoup

USER_ID = '102121409478764742904' # Mulin Hong
MAX_RESULTS = 400 # 最大纪录数,每页100条,也就是说最多5页(0~4页)
API_KEY = '你自己的api_key' 

def cleanHtml(html):
  if html == "": return ""
  return BeautifulSoup(html,'lxml').get_text()[:-1]

service = apiclient.discovery.build('plus', 'v1', http=httplib2.Http(), 
                                    developerKey=API_KEY)
activity_feed = service.activities().list(userId=USER_ID,
  collection='public',
  maxResults='100' 
)

activity_results = []

while activity_feed != None and len(activity_results) < MAX_RESULTS:
  activities = activity_feed.execute()
  if 'items' in activities:
    for activity in activities['items']:
      if activity['object']['objectType'] == 'note' and activity['object']['content'] != '':        
        activity['title'] = cleanHtml(activity['title'])
        activity['object']['content'] = cleanHtml(activity['object']['content'])
        activity_results += [activity]
#查看下一页
  activity_feed = service.activities().list_next(activity_feed, activities)
# 写到一个json文件中去
f = open(os.path.join('resources', USER_ID + '.json'), 'w')
f.write(json.dumps(activity_results,ensure_ascii=False, indent=2))
f.close()
print (str(len(activity_results)), "activities written to", f.name)

最后输出结果”422 activities written to resources/102121409478764742904.json”,共422条被输出。查看

为了进一步对每条记录分析,有必要进行中文分词。文章3中提到11款开放中文分词引擎,从分词效果和调用难度角度考虑,这里采用商业化的BosonNLP工具(关键被他一句广告吸引“现在加入BosonNLP,可获得分词与词性标注引擎不限量调用额度!”)。 注册波森后会给你一个api_key,和google+一个原理。安装python版SDK: pip install -U bosonnlp 。api文档很简单,看一遍就直接用了。

引用方法:

In [1]: from bosonnlp import BosonNLP

In [2]: nlp = BosonNLP('你自己的api_key')

In [3]: s='当年北京市长夸下海口: 2017年治不了雾霾就提头来见      2016年10月16日,北京市空气污染指数读数    嗯,
   ...: 北京市长同志,你只有两个多月的时间了……'

In [4]: nlp.tag(s)[0]['word']
Out[6]:
['当年',
 '北京',
 '市长',
 '夸',
 '下',
 '海口',
 ':',
 '2017年',
 '治',
 '不',
 '了',
 '雾霾',
 ...

直接使用里面的api进行情感分析:

from bosonnlp import BosonNLP
nlp = BosonNLP('你的api_key')
all_content = [a['object']['content'] for a in activity_results ]
emos=nlp.sentiment(all_content[:100], model='weibo')#单词最多只能分析100个,每日最多500个
drawdata=list(zip(*emos))[0]

绘制箱线图和统计直方图:

23871192.jpg

94976039.jpg

从图中可以看出,整体情感偏上,这里只计算了100条,有兴趣把一天的免费记录数500条全计算完了看看结果。当然情感算法用的很普遍了,自己实现个也非难事。 hrKOofx5.10057.yUUmemEd43Dm

斯坦福大学自然语言处理组是世界知名的NLP研究小组,他们提供了一系列开源的Java文本分析工具,包括分词器(Word Segmenter),词性标注工具(Part-Of-Speech Tagger),命名实体识别工具(Named Entity Recognizer),句法分析器(Parser)等,可喜的事,他们还为这些工具训练了相应的中文模型,支持中文文本处理。NLTK4是针对python的一个自然语言处理平台,在windows、mac、linux平台上通用,并且是开源免费的,国内好多项目都是在它基础上做的。 下面用nltk分析下抓到的数据。

import nltk
from bosonnlp import BosonNLP

nlp = BosonNLP('你自己的api_key')

#将所有记录转化为一个词语数组tokens
contents='。'.join(all_content)
tokens=nlp.tag(contents)[0]['word']
text = nltk.Text(tokens)

text.concordance("三星")#查看出现‘三星’的语句,可选参数包括语句数目和语句长度
'''
Displaying 4 of 4 matches:
 北京 市长 准备 如何 收场 ? 。 # 看 图 不 说话 1016 : 三星 手机 名不虚传 。 How to mess up # StarWars a
假 论文 , 那 就 是 丢脸 了 。 # 看 图 不 说话 0923 : 三星 一生 黑 http://cinacn.blogspot.com/2016/
 : 心里 想 说 没事 了 。 # 看 图 不 说话 0917 : 使用 三星 手机 的 后果 。 这个 错误 有点 大 了 。 看看 朝鲜 战争 大事记
 你们 开学 一次性 交 多少 钱 。 # 看 图 不 说话 0906 : 三星 手机 的 中东 版 。 舆情 监控 , 已经 是 大陆 媒界 不用 公开 
'''
text.collocations()#最搭配的用词
'''
Displaying 4 of 4 matches:
 北京 市长 准备 如何 收场 ? 。 # 看 图 不 说话 1016 : 三星 手机 名不虚传 。 How to mess up # StarWars a
假 论文 , 那 就 是 丢脸 了 。 # 看 图 不 说话 0923 : 三星 一生 黑 http://cinacn.blogspot.com/2016/
 : 心里 想 说 没事 了 。 # 看 图 不 说话 0917 : 使用 三星 手机 的 后果 。 这个 错误 有点 大 了 。 看看 朝鲜 战争 大事记
 你们 开学 一次性 交 多少 钱 。 # 看 图 不 说话 0906 : 三星 手机 的 中东 版 。 舆情 监控 , 已经 是 大陆 媒界 不用 公开 
'''
text.collocations()#最搭配的用词
'''
@Homebaby Wen; little pink; sounds cute; 核废料 处理厂; 诺贝尔 文学奖; 连云港 核废料;
创业者 越来越
'''
fdist = text.vocab()#{词1:词1出现的个数,词2:词2出现的个数,...}
print(fdist["大陆"])
print(fdist["老百姓"])
print(fdist["的"])
print(fdist["不"])
'''
25
27
1250
351
'''
print(len(tokens)) #总共的词数
print(len(fdist.keys())) #不重复词
print(fdist.freq('的'))#1250/27232
print(fdist.most_common(20))# 出现次数最大的前20个
'''
27232
6465
0.04590188014101058
[(',', 1651), ('的', 1250), ('。', 959), (':', 568), ('是', 495), ('了', 380), ('不', 351), ('”', 257), ('“', 255), ('#', 242), ('一', 222), ('就', 207), ('在', 200), ('有', 162), ('?', 150), ('你', 130), ('我', 129), ('这', 129), ('人', 127), ('都', 124)]
'''
nltk.download('stopwords')
'''
[nltk_data] Downloading package stopwords to /Users/Trucy/nltk_data...
[nltk_data]   Unzipping corpora/stopwords.zip.
然后在解压的停词目录中添加china文件,里面添加停词,这里用的哈工大停词库
'''
comm=list(zip(*fdist.most_common(100)))[0]#100个热词中非停词
print([w for w in comm if w not in nltk.corpus.stopwords.words('china')])
'''
['中国', '说', '国家', '毛', '微', '语录', '精选', '图', '说话', '中共', '日', '政府', '年', '爱国', '美国', '天', '钱', '荟萃', '段子', '里', '想']
'''
# 非url的长词语
print([w for w in fdist.keys() if len(w) > 12 and not w.startswith("http")])
'''
['@jianshenbiao', '@Jackstraw_PRC', '@Andrew19751110', '@boattractor_cj', '@_markhorton搞得后者不得不', '@Weaponmagazine-肖宁)', '@YE5MQ5Vtp2jlWX7', '@Menghuanlangqi2', '@szstupidcool', '@zhifangnvren', 'HappyBirthday', '@freedomandlaw', '@_mackhorton结果攻击了一个字母之差的无辜鬼佬', '@和菜头)——中国人能接受么?丝毫没有对他国的尊重', '@BattlerHenry', '@c338ki_selina', '@shangguanluan', '@zhanghui8964', '@fedsneighbor']
'''

相信你肯定听过二八原则,如果把所有的单词(字)放在一起看呢?会不会20%的词(字)占了80%的出现次数?答案是肯定的。

早在上个世纪30年代,就有人(Zipf)对此作出了研究,并给出了量化的表达——齐普夫定律(Zipf’s Law):一个词在一个有相当长度的语篇中的等级序号(该词在按出现次数排列的词表中的位置,他称之为rank,简称r)与该词的出现次数(他称为frequency,简称f)的乘积几乎是一个常数(constant,简称C)。用公式表示,就是 r × f = C 。(此处的C一般认为取0.1)。Zipf定律是文献计量学的重要定律之一,它和洛特卡定律、布拉德福定律一起被并称为文献计量学的三大定律。

我们直观地验证下,100个热词频度和排名的规律:

#前100热词统计
comm=list(zip(*fdist.most_common(400)))
top=[(w,comm[1][i]) for i,w in enumerate(comm[0]) \
if w not in nltk.corpus.stopwords.words('china')]
dd=list(zip(*top[:100]))
plt.plot(range(1,101),dd[1],'-',linewidth=5,alpha=0.6)
plt.xticks(arange(1,101,2),dd[0][::2],rotation=90)
plt.xlabel('前100热词',fontsize='x-large')
plt.ylabel('频数',fontsize='x-large')
plt.title('前100热词统计',fontsize='x-large')
plt.show()

30574312.jpg

很明显如果去拟合的话是反比例曲线,有兴趣的使用最小二乘法拟合下,看下c等于多少。同样可以看到,热词中涉及政治词汇比较多,实际上好多中文说说都涉及敏感词汇,这已经是我挑的不怎么敏感的了,万恶腐朽的google+,天朝早晚取缔你😁。

特征词提取

这节主要介绍TFIDF,高手直接跳过。

特征词/关键词提取最简单最基础的就是TFIDF,记得5年前我同学让我帮做DI-TFIDF的论文,也就只多了个类内离散度(DI),今年阿里校招笔试题都有,用mapreduce实现的,很是广泛。实际上tfidf算法的岁数估计比我还大,目前应用还是很广。其他特征提取方法还有TF、MI、ECE、QEMI、IG、OR、GA、SA、PCA、N-Gram等,各有好坏,个人喜欢SA(模拟退火算法)。

简单介绍下TFIDF,TFIDF的主要思想是:如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。TFIDF实际上是:TF * IDF,TF词频(Term Frequency),IDF反文档频率(Inverse Document Frequency)。TF词频(Term Frequency)指的是某一个给定的词语在该文件中出现的次数)。IDF反文档频率(Inverse Document Frequency)是指果包含词条的文档越少,IDF越大,则说明词条具有很好的类别区分能力。公式看看阮一峰的文章5就懂。

先用波森来玩一下。

#第100到109条记录各前五个关键字分析
nlp.extract_keywords(all_content[100:110],top_k=5)

[[[0.7099039005468386, ‘林志颖’], [0.6618791162771835, ‘说话’], [0.16548951440531323, ‘图’], [0.1391678971188951, ‘真’], [0.08401698377794771, ‘看’]],
[[0.4023478548923522, ‘面试’], [0.37301990285926334, ‘秋月’], [0.3067035017321436, ‘程序员’], [0.3039517495852464, ‘月饼’], [0.30299584457854634, ‘语录’]],
[[0.47362866866222336, ‘朝鲜’], [0.3352703984048265, ‘兼听则明’], [0.2612360542645001, ‘志愿军’], [0.25878030672041646, ‘战争’], [0.21926520954291415, ‘脸红’]],
[[0.49721835098126743, ‘战争’], [0.32820426275864795, ‘共产党’], [0.3033420749749608, ‘朝鲜’], [0.22718247058147462, ‘亲华派’], [0.21472859448533965, ‘保家’]],
[[0.2454776400796074, ‘老头’], [0.2404142762073897, ‘导游’], [0.18403709160053647, ‘平壤’], [0.1753006540352852, ‘首都’], [0.1462342959779542, ‘坦克’]],
[[0.611209874316231, ‘语录’], [0.47971562974594106, ‘精选’], [0.3914587127344426, ‘女生’], [0.32629224154255926, ‘复杂’], [0.24636184499215347, ‘到底’]],
[[0.49698250604754796, ‘响吧’], [0.41302611057797883, ‘老百姓’], [0.34093105823385067, ‘太监’], [0.3321228504052302, ‘大陆’], [0.2893273489670021, ‘税负’]],
[[0.40325177993397743, ‘导游’], [0.3096728358372618, ‘韩战’], [0.2929205806460173, ‘游客’], [0.2480119777270853, ‘带劲’], [0.22704285072733602, ‘自以为是’]],
[[0.7242722832662252, ‘哥们儿’], [0.5061338668467491, ‘着急’], [0.4404639544540359, ‘说话’], [0.11012912198474084, ‘图’], [0.07352170001676955, ‘太’]],
[[0.39101364028081176, ‘鸦片’], [0.27683827573410325, ‘种植’], [0.22542041392575338, ‘zhuo’], [0.22542041392575338, ‘nanjun’], [0.22461629498500293, ‘缩头’]]]

用tfidf来做一下,分四步走:

  1. 计算tfidf
  2. 排序,topK
cts=[]
#1.十条记录的分词
for c in nlp.tag(all_content[100:110]):
    cts.append(c['word'])
tfidfC=[]
#2.去停词
for ac in cts: 
    tfidfC.append([w for w in ac 
                   if w not in nltk.corpus.stopwords.words('china')])
tc = nltk.TextCollection(tfidfC)
tfidfR=[]
topK=5
#3.计算tfidf
for c in tfidfC:
    res=[]
    for sc in list(set(c)):
        val=tc.tf_idf(sc,c)
        res.append([val,sc])
    #4.topK
    sres=sorted(res, key=lambda p: p[0], reverse=True)[:topK]
    tfidfR.append(sres)
print(tfidfR)

[[[0.4605170185988092, ‘林志颖’], [0.3218875824868201, ‘说话’], [0.3218875824868201, ‘真’], [0.3218875824868201, ‘0913’], [0.3218875824868201, ‘图’]],
[[0.24237737820989955, ‘面试’], [0.24237737820989955, ‘官’], [0.12118868910494977, ‘从前’], [0.12118868910494977, ‘秋月’], [0.12118868910494977, ‘原因’]],
[[0.1485538769673578, ‘中’], [0.11651349719283252, ‘朝鲜’], [0.07767566479522169, ‘战争’], [0.0742769384836789, ‘贡献’], [0.0742769384836789, ‘话’]],
[[0.15703993099903515, ‘战争’], [0.10496334211526741, ‘共产党’], [0.1001123953475672, ‘场’], [0.07851996549951758, ‘朝鲜’], [0.0500561976737836, ‘课本’]],
[[0.03868841135658895, ‘说’], [0.033210361918183356, ‘健康’], [0.033210361918183356, ‘老头’], [0.033210361918183356, ‘首都’], [0.03095072908527116, ‘抢’]],
[[0.3837641821656743, ‘关系’], [0.3837641821656743, ‘0912’], [0.3837641821656743, ‘女生’], [0.26823965207235, ‘微’], [0.26823965207235, ‘精选’]], [[0.14631253749400913, ‘大陆’], [0.14631253749400913, ‘老百姓’], [0.10466295877245664, ‘总得’], [0.10466295877245664, ‘倒数’], [0.10466295877245664, ‘毛’]],
[[0.10233711524417982, ‘想’], [0.07153057388596001, ‘导游’], [0.07153057388596001, ‘说’], [0.07153057388596001, ‘游客’], [0.07153057388596001, ‘年’]],
[[0.3837641821656743, ‘着急’], [0.3837641821656743, ‘哥们儿’], [0.3837641821656743, ‘0911’], [0.26823965207235, ‘说话’], [0.26823965207235, ‘图’]],
[[0.1151292546497023, ‘鸦片’], [0.1151292546497023, ‘种植’], [0.05756462732485115, ‘zhuo’], [0.05756462732485115, ‘补习’], [0.05756462732485115, ‘充当’]]]

两者比较下波森要稍好一些,底层估计是改进的tfidf。

文本相似度

我们看今日头条新闻,看完后下面会有推荐相似的文章,提供你更多阅读的机会。相似文本推荐最基本的方法用到”余弦相似性“(cosine similiarity)。举个简单例子: 两个文本,先分词:

文本1:google/和/百度/相似
文本2:百度/比不了/谷歌

文本1:google:1,和:1,百度:1,相似:1
文本2:百度:1,比不了:1,谷歌:1

列出所有词,按词频排序:

文本1:google:1,和:1,百度:1,相似:1,比不了:0
文本2:google:1,和:0,百度:1,相似:0,比不了:1

提取词频向量:

文本1:[1,1,1,1,0] 文本2:[1,0,1,0,1]

接下来计算余弦相似度:

CosineDistance(u,v)=u⋅v|u||v|CosineDistance(u,v)=u⋅v|u||v|

这个公式代表两个向量的夹角,二维向量夹角高中不就是这个公式么,推广到三维甚至多维也一样。 6547011.jpg

余弦值越接近1,就表明夹角越接近0度,也就是两个向量越相似,这就叫”余弦相似性”。所以上面两文本相似度为:

212+12+12+12+02−−−−−−−−−−−−−−−−−√×12+02+12+02+12−−−−−−−−−−−−−−−−−√=3–√3212+12+12+12+02×12+02+12+02+12=33

下面我们来统计下内容较长的记录相似文本(内容较短相似度不明显)。 第一步:找出内容长度大于700的记录,并做好分词和停词

#筛选要比较的文本数据,共24条记录
data=[]#保存object.content内容大于700的所有数据
all_posts=[]#只保留发布的内容数据
for ac in activity_results:
    if len(ac['object']['content'])>700:
        c=ac['object']['content']
        data.append(ac)
        #分词和停词
        all_posts.append([w for w in nlp.tag(c)[0]['word'] if w not in nltk.corpus.stopwords.words('china')])

第二步:构造词条文档矩阵。形式如tdmatrix=(titlei,urli):termj:tfidfj,…,…tdmatrix=(titlei,urli):termj:tfidfj,…,…

tc = nltk.TextCollection(all_posts)
#构造词条文档矩阵
td_matrix = {}
for idx in range(len(all_posts)):
    post = all_posts[idx]
    fdist = nltk.FreqDist(post)

    doc_title = data[idx]['title']
    url = data[idx]['url']
    td_matrix[(doc_title, url)] = {}

    for term in fdist.keys():
        td_matrix[(doc_title, url)][term] = tc.tf_idf(term, post)

第三步:计算相似度
这里用到nltk.cluster.util.cosine_distance,这个函数说明如下: nltk.cluster.util.cosine_distance(u, v)[source] Returns 1 minus the cosine of the angle between vectors v and u. This is equal to 1 - (u.v / |u||v|). 可以看到返回的是1-余弦相似度,表示的是余弦距离,也就是说余弦距离越小相似度越高。

distances = {}
for (title1, url1) in td_matrix.keys():

    distances[(title1, url1)] = {}
    (min_dist, most_similar) = (1.0, ('', ''))

    for (title2, url2) in td_matrix.keys():

        terms1 = td_matrix[(title1, url1)].copy()
        terms2 = td_matrix[(title2, url2)].copy()

        # 填充0使两向量长度相同
        for term1 in terms1:
            if term1 not in terms2:
                terms2[term1] = 0

        for term2 in terms2:
            if term2 not in terms1:
                terms1[term2] = 0

        # 产生v1,v2向量,向量元素映射一致
        v1 = [score for (term, score) in sorted(terms1.items())]
        v2 = [score for (term, score) in sorted(terms2.items())]

        # 计算余弦相似度
        distances[(title1, url1)][(title2, url2)] = \
            nltk.cluster.util.cosine_distance(v1, v2)

        if url1 == url2:
            continue
        # 标记余弦距离最小的(相似度最大)
        if distances[(title1, url1)][(title2, url2)] < min_dist:
            (min_dist, most_similar) = (distances[(title1, url1)][(title2,
                                         url2)], (title2, url2))
    
    print ("%s\n(%s) \n 最相似的是:\n %s\n(%s) \n 相似度: %f \n ------------------------------\n"
           % (title1, url1,most_similar[0], most_similar[1], 1-min_dist))

查看部分结果:

#一日段子荟萃
2016-9-5

@kxxj: 新歇后语:包子宽衣——露馅儿了。

@CasperYang:通商宽衣已加入敏感词豪华午餐。

@szeyan1220:宽衣解带新白娘。轻关易道寻佳人,..
(https://plus.google.com/+MulinHong/posts/FJuFWhykUhU) 
 最相似的是:
 #一日段子荟萃
2016-9-7

@boattractor_cj:“吃饱了没事干”,代表了习帝的外交思路,反映了他对洋夷的了解水平;“吃饭砸锅”代表了习帝的内政思路,反映了他蔑视屁民的霸气;“打断骨头..
(https://plus.google.com/+MulinHong/posts/BfAsHEk3Dfs) 
 相似度: 0.018108 
 ------------------------------

#一日段子荟萃
2016-8-9

@blogtd:我奇怪的是,不管作为一个国家,还是一个族群,中国从未向世界展现过羞愧这种情绪。

@hnjhj:各类辱华事件频发,但因星星角度不对而辱华还是始料未及..
(https://plus.google.com/+MulinHong/posts/Y4DMUPtSSTB) 
 最相似的是:
 #一日段子荟萃
2016-9-26

@zhanghui8964:就目前形态而言,我一直不认为渐进改良是一种政治存在,也不认为激进革命是一种政治存在。在一定意义上大家都是口炮党。区别只在于部分努力者搞了..
(https://plus.google.com/+MulinHong/posts/BNqkLxd9YCP) 
 相似度: 0.026590 
 ------------------------------

#一日段子荟萃
2016-8-29

@侯虹斌:警力配置吧。主要精力放在维稳上,这类诈骗案几乎不会投入警力资源;到全社会都关注了,就变成维稳的事件了,警方马上就有资源对接了。

@baidu冷兵器吧:..
(https://plus.google.com/+MulinHong/posts/RTDgVPKvbyM) 
 最相似的是:
 #一日段子荟萃
2016-8-23

@MyDF:昨天下午路过洪都南大道,发现沿途增加了不少交警,诡异的是,大热天的街边还站着或坐着不少可疑的群众,几公里都是,象是在等什么大人物。今天看了新闻,才知ß道..
(https://plus.google.com/+MulinHong/posts/UVZVyshut8R) 
 相似度: 0.082137 
 ------------------------------

为查看方便,绘制相似度矩阵图: 4103503.jpg

  • Russell, Matthew A. Mining the Social Web: Data Mining Facebook, Twitter, LinkedIn, Google+, GitHub, and More. O’Reilly Media, Inc. 2013.
  1. python3.4学习笔记(十七) 网络爬虫使用Beautifulsoup4抓取内容.http://www.cnblogs.com/zdz8207/p/python_learn_note_17.html 

  2. Beautiful Soup 4.2.0 文档.https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html 

  3. 11 款开放中文分词引擎评测.http://www.cnblogs.com/croso/p/5349517.html 

  4. Natural Language Toolkit.http://www.nltk.org/index.html 

  5. TF-IDF与余弦相似性的应用(一):自动提取关键词.http://www.ruanyifeng.com/blog/2013/03/tf-idf.html 



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK