标签归档:分词

标题党统计学

如果你是被这个标题骗进来的,那么说明标题党的存在的确是有原因的。在网络高度发达(以及“大数据”泛滥)的今天,数据动不动就是以 GB 和 TB 的级别存储,然而相比之下,人类接受信息的速度却慢得可怕(参见大刘《乡村教师》)。试想一下,你一分钟能阅读多少文字?一千?五千?总之是在 KB 的量级。所以可以说,人们对文字的“下载速度”基本上就是 1~10KB/min。如果拿这个速度去上网的话你还能忍?

既然如此,每天网上有成千上万的新闻、报告、文章和八卦,怎么看得过来呢?没办法,只能先对正文进行一次粗略的筛选——看标题。俗话说得好,这是一个看脸的世界。于是乎,文章的作者为了吸引读者,就要取个足够博眼球的标题,而所谓标题党便是充分利用这种心理,用各种颇具创意的标题来吸引读者的注意。

好了,既然看官已经看到了这里,我就可以承认本文其实也是标题党了。这篇小文并不是要讨论标题党的前世今生,而是研究一个与此有关的统计问题:怎样的标题会更加吸引读者的关注?

这个问题有点太大了,所以我们缩小一下范围。既然是统计问题,就拿自家的一个例子下手吧:做统计学研究的,都得读各种各样的统计论文,那么论文的标题是否会对这篇文章的阅读量产生影响呢?巧的是,美国统计协会期刊(JASA)的网站上正好提供了该期刊旗下文章的下载访问量,所以我们可以以此做一个小分析,来研究一下标题与文章阅读量之间的关系。

可能有读者要问,为什么要使用文章的访问量,而不是引用率呢?这是因为 JASA 在其网站上说明,访问量数值是指从 JASA 官网下载的统计量,不包括从其他途径(比如购买的论文数据库)的来源。在 JASA 网站上,下载文章之前读者能获取到的主要是文章的标题和作者信息,所以访问量的主要驱动因素就是读者在阅读标题和作者之后产生的好奇感,从而减少了数据中的噪音。相反,引用一篇文章,通常是对文章有了充分理解之后产生的行为,这时候标题的作用可能就非常微弱了。总而言之,JASA 文章的下载量可以较好地代表读者在获取了文章的基本信息后对它感兴趣的程度。

jasa

继续阅读标题党统计学

中文文本处理简要介绍

本文作者李绳,博客地址 http://acepor.github.io/。作者自述:

一位文科生曾励志成为语言学家
出国后阴差阳错成了博士候选人
三年后交完论文对学术彻底失望
回国后误打误撞成了数据科学家

作为一个处理自然语言数据的团队,我们在日常工作中要用到不同的工具来预处理中文文本,比如 Jieba Stanford NLP software。出于准确性和效率的考虑,我们选择了Stanford NLP software, 所以本文将介绍基于 Stanford NLP software 的中文文本预处理流程。

中文文本处理简要介绍

与拉丁语系的文本不同,中文并不使用空格作为词语间的分隔符。比如当我们说“We love coding.”,这句英文使用了两个空格来分割三个英文词汇;如果用中文做同样的表述, 就是“我们爱写代码。”,其中不包含任何空格。因而,处理中文数据时,我们需要进行分词,而这恰恰时中文自然语言处理的一大难点。

下文将介绍中文文本预处理的几个主要步骤:

  1. 中文分词
  2. 标注词性
  3. 生成词向量
  4. 生成中文依存语法树

Stanford NLP software 简要介绍

Stanford NLP software 是一个较大的工具合集:包括 Stanford POS tagger 等组件,也有一个包含所有组件的合集 Stanford CoreNLP。各个组件是由不同的开发者开发的,所以每一个工具都有自己的语法。当我们研究这些组件的文档时,遇到了不少问题。下文记录这些问题和相对应的对策,以免重蹈覆辙。

Stanford NLP 小组提供了一个简明的FAQ——Stanford Parser FAQ 和一份详细的Java文档 ——Stanford JavaNLP API Documentation。在这两份文档中,有几点格外重要:

尽管PSFG分词器小且快,Factored分词器更适用于中文,所以我们推荐使用后者。

中文分词器默认使用GB18030编码(Penn Chinese Treebank的默认编码)。

使用 -encoding 选项可以指定编码,比如 UTF-8,Big-5 或者 GB18030。

中文预处理的主要步骤

1. 中文分词

诚如上面所言,分词是中文自然语言处理的一大难题。Stanford Word Segmenter 是专门用来处理这一问题的工具。FAQ请参见 Stanford Segmenter FAQ。具体用法如下:

bash -x segment.sh ctb INPUT_FILE UTF-8 0

其中 ctb 是词库选项,即 Chinese tree bank,也可选用 pku,即 Peking University。UTF-8是输入文本的编码,这个工具也支持 GB18030 编码。最后的0指定 n-best list 的大小,0表示只要最优结果。

继续阅读中文文本处理简要介绍

jiebaR中文分词——R的灵活,C的效率

本文作者:覃文锋,厦门大学公共卫生学院本科生,研究兴趣为生物统计和数据挖掘。

主页:http://qinwenfeng.com/cn/jiebaR-dev/

R是什么?

记得刚接触R的时候,有一种莫名的抵触,A、B、C、D、E那么多种语言了,为什么又多冒出来一个R?为了时间序列的课程,我又要多记忆一大堆乱七八糟的语法。当发现居然有dd<-23333 23333->ee 这样的语法时,更瞬间奠定了R语言在我心中的逗比地位。

因为老师没有专门教授R的相关细节,毕竟课程的主题不是那个,加之R的语法与众不同,这导致我的R语言相关作业的绝大部分时间一般都在百度、谷歌各种R语言的表达、实现方法中度过。

记得有位哲人说过:“人并没有真正喜欢吃的东西,只是吃的次数多了,就‘喜欢’了。”

我对R语言的看法也差不多。随着对R了解的深入,我才发现,丰富的可视化工具、可重复性研究、匿名函数、延迟求值、元编程,还有6000+的CRAN包等等特性,都是R赫赫的闪光点。

R是一门统计学用的语言,这是这门语言给我的第一印象。看了 John Chambers 在 USER!2014 的视频,以及他对R的定义“a software interface into the best algorithms.” 的时候,我感受到了R的“最初的价值”。

magrittr让我们更欢乐地操纵各种命令,knitr让统计报告和编程文学化,dplyr更方便地处理数据,R还有shiny让你轻松地构建动态内容。我很难想象没有R,让我用其他语言来完成完成这些事情需要多少的工作量。

灵活而高效的接口

有人说R慢,只能说这些人应该不够“本质”,效率和灵活性总是需要平衡的。用C和FORTRAN来实现算法,用R(S)来解决问题,这是S诞生的初衷之一。英语渣渣的理解,不对请轻轻地喷。R的底层C接口对初学者有些复杂,Rcpp的出现很大程度上降低了写出高效率R包和代码的成本。

之前因为对文本挖掘比较感兴趣,所以打算用R来做一些分析,但是发现在R上,文本挖掘最基本的中文分词的模块还没有较好的实现。R是开源的,开源的意义不只是Free使用,还有贡献社区这一层,于是jiebaR诞生了。

jiebaR是“结巴”中文分词(Python)的R语言版本,支持最大概率法(Maximum Probability),隐式马尔科夫模型(Hidden Markov Model),索引模型(QuerySegment),混合模型(MixSegment)共四种分词模式,同时有词性标注,关键词提取,文本Simhash相似度比较等功能。项目使用了Rcpp和CppJieba进行开发。目前托管在GitHub上。安装很简单,你可以下载Windows的二进制包或者:

library(devtools)
install_github("qinwf/jiebaR")

是的,然后你就可以开始分词了,再也没有rJava那头痛的Path设置。

继续阅读jiebaR中文分词——R的灵活,C的效率

新浪微博文本分析初探v0.1

v0.1版本说明:本文发在主站上之后,站友们经常评论代码跑着有问题。经过和lijian大哥等人进行咨询,自己也摸索了一些之后,发现了之前代码非常多的漏洞。因此,给广大站友带来了困扰。在这里我表示万分的抱歉。最近邮箱中收到让我整理代码的需求越来越多。我也非常想整理下,但是由于工作也非常繁忙,所以很难抽出时间。前两天说5.1期间会整理一下代码发出来。但是事实上因为5.1小长假期间我可能无法上网,导致无力更新代码。所以今晚抽时间对代码进行了简单的修改。对本文也进行了一些调整。目前的状况是,基本上到生成待分析的语料库已经没有问题了。聚类分析的模型可以跑出来,但是最终的图画不出来。我暂时也没能找到原因。所以进一步的调整可能要等到5.1过完以后再抽时间来做了。这篇文章我会负责到底的哈。(20130429)

完整代码如下:weibo_analysis

—————————–分割线————————————————-

自从lijian大哥的Rweibo包问世以来,便成了R爱好者们获取新浪微博数据的最为重要的工具。在该包的中文主页上,作者对如何连接新浪微博的API,获取授权,并以此为基础开发应用的原理讲解的非常清楚。对于我这种连基本的网页开发神马原理都一点也不清楚的菜鸟来说,Rweibo是一种非常趁手的获取微博数据的工具。

有了获取数据的工具,对于中文文本分析来说,最重要的是分词。这里使用的分词算法来自中科院 ictclas算法。依然是沾了lijian大哥Rwordseg的光,直接拿来用了。

有了这两样利器,我们便可以来分析一下新浪微博的数据了。我选取的话题是最近热映的国产喜剧电影《泰囧》,在微博上拿到了998条和“泰囧”有关的微博文本。代码如下(以下代码不能直接执行,请首先阅读链接中Rweibo的关于授权帮助文档):

#关键词搜索并不需要注册API
require(Rweibo)
#registerApp(app_name = "SNA3", "********", "****************")
#roauth <- createOAuth(app_name = "SNA3", access_name = "rweibo")
res <- web.search.content("泰囧", page = 10, sleepmean = 10,
           sleepsd = 1)$Weibo

获取了数据之后,首先迫不及待对微博文本进行分词。代码如下(Rwordseg包可以在语料库中自助加入新词,比如下面的insertWords语句):

require(Rwordseg)
insertWords("泰囧")
n = length(res[, 1])
res = res[res!=" "]
words = unlist(lapply(X = res, FUN = segmentCN))
word = lapply(X = words, FUN = strsplit, " ")
v = table(unlist(word))
v = sort(v, decreasing = T)
v[1:100]
head(v)
d = data.frame(word = names(v), freq = v)

继续阅读新浪微博文本分析初探v0.1

统计词话(一)

不知道这个标题是否有足够的吸引力把你骗进来。如果你认为统计是一个到处充满了期望方差分布回归随机多元和概率的东西,那么……你可能是对的,不过本文想要告诉你的是,你其实还可以用统计来做一些你关心的事情,比如现在,我们既谈风月,也谈统计。:D

相信大家对宋词都不会陌生。无论你是否喜欢,总还是可以吟诵出几句名篇来的。如果你经常找一些宋词来读的话,你可能会发现一个有趣的现象,那就是有些词语或意象似乎特别受到词人的青睐,像是东风,明月,芳草等等。当然,对于这个现象,不同的人有不同的看法。一种观点是这些意象往往具有特定的含义,或是抒发离恨,或是寄托相思,总之是把人们的情感倾注在了这些最常见的事物之中,让人触景生情;而另一种看法则觉得词的雕琢痕迹太明显,内容也相对单调,使得用词容易造成重复。本文当然不是来探讨这些话题的,而是想用统计的方法来给大家展示一下究竟有哪些话语被词人一次一次地书写,被读者一遍一遍地传唱。

从统计的角度来看,上面这个问题其实非常简单,无非就是计算一下宋词之中词语出现的频率,然后做一个排序就可以了。但这个问题对于中文来说恰恰是最难攻克的一个环节。在英语中,词语与词语之间有着天然的分隔符,但对于中文,只有句子之间有标点符号,句子之内只能通过词语的含义来进行辨别。这也就是为什么在文本挖掘领域中,中文的分词依然是一个富有挑战性的任务的原因。

不过好在宋词本身的形式帮了我们很大的忙。首先,宋词的句子一般都非常短,这相当于已经有了一次粗略的词语划分;其次,宋词的用词也很简洁,一个词一般是两个字,偶尔可能有三个字、四个字,超过四个字的词就非常罕见了。于是我们就有一种比较“野蛮”的做法,来对宋词中的用词进行划分。

举个例子来说,《青玉案》中的这句“东风夜放花千树”,如果把所有可能的两个字的组合列出来,就是:

东风  风夜  夜放  放花  花千  千树

如果再把三个字的可能组合列出来,则有:

东风夜  风夜放  夜放花  放花千  花千树

如果不考虑其它的可能,那么总共就有11个词语。当然,这其中会有很多无意义的组合,但是我们可以预想的是,这些无意义的组合将不太可能大规模地重复出现,因此在排序的过程中它们自动地就被排在高频词语之后了。通过这种做法,宋词中的每句话大体都能分成10个左右的词语单位,然后对所有的这些词语单位进行频数统计,就可以得到最终的高频词语列表了。

下面就通过一段R程序来进行一次实际的分析,用到的数据是从网络上整理的《全宋词》电子资料,其中可能有部分字词不正确。完整的程序和数据可以从这里下载

首先,当然是读取数据。

txt=read.csv("SongPoem.csv",colClasses="character");

接下来提取出宋词的内容,并根据标点符号对句子进行分割。

sentences=strsplit(txt$Sentence,",|。|!|?|、");
sentences=unlist(sentences);
sentences=sentences[sentences!=""];

对句子进行分割后需要检查一遍,如果有些句子的长度超过了15个字,那么很可能是错误的字符,应该剔除掉。

s.len=nchar(sentences);
sentences=sentences[s.len<=15];
s.len=nchar(sentences);

下面的这个函数非常重要,其作用就是按照之前的做法把所有可能的字的组合计算出来。这里只是考虑了两个字的组合。

splitwords=function(x,x.len) substring(x,1:(x.len-1),2:x.len);

接下来就好办了,无非就是应用上面的函数对句子进行拆分,然后统计词频并排序。

words=mapply(splitwords,sentences,s.len,SIMPLIFY=TRUE,USE.NAMES=FALSE);
words=unlist(words);
words.freq=table(words);
words.freq=sort(words.freq,decreasing=TRUE);
words.freq[1:100];

最后的结果如下:

排序  词语    频数          排序  词语    频数
1     □□     1584         51    匆匆    357
2     东风    1379         52    芙蓉    356
3     何处    1231         53    今日    354
4     人间    1164         54    扁舟    351
5     风流    843          55    西湖    350
6     归去    818          56    憔瘁    349
7     春风    800          57    消息    347
8     西风    782          58    桃花    343
9     归来    768          59    何事    335
10    江南    760          60    一片    333
11    相思    759          61    神仙    332
12    梅花    725          62    一声    331
13    千里    668          63    黄花    330
14    多少    653          64    心事    330
15    回首    649          65    鸳鸯    328
16    如今    647          66    十分    327
17    明月    646          67    人生    324
18    阑干    632          68    断肠    323
19    年年    605          69    佳人    323
20    万里    587          70    长安    321     
21    一笑    579          71    东君    319     
22    黄昏    561          72    桃李    319     
23    当年    537          73    而今    318     
24    芳草    533          74    为谁    317     
25    天涯    531          75    无情    307     
26    相逢    523          76    去年    306     
27    尊前    519          77    天气    306     
28    一枝    510          78    不是    305     
29    风雨    500          79    海棠    305     
30    流水    481          80    少年    305     
31    风吹    474          81    今夜    304     
32    依旧    469          82    不似    303     
33    多情    458          83    十年    303     
34    风月    452          84    行人    300     
35    当时    451          85    谁知    300     
36    故人    445          86    寂寞    299     
37    斜阳    444          87    肠断    297     
38    无人    443          88    江上    297     
39    不知    426          89    悠悠    297     
40    深处    424          90    富贵    295     
41    不见    416          91    时候    295     
42    时节    407          92    昨夜    295     
43    凄凉    404          93    几度    292     
44    平生    394          94    月明    292     
45    春色    393          95    何时    291     
46    无限    381          96    青山    291     
47    一点    374          97    蓬莱    290     
48    功名    366          98    往事    290     
49    杨柳    363          99    如何    287     
50    天上    361          100   惟有    287

需要解释一下的是,排在第一位的方框是词库中的一些出错的字符,直接略去即可。

至此,真相大白。至于这个结果意味着什么,就留给读者自己细细品读吧。