2303 字

微博是否符合齐普夫定律?

最近看到一篇论文,作者利用微博关键词出现的频率来预测空气污染的状况并认为来自社交媒体的数据能为环境监测提供更多的细节。这个想法很不错,但其实抛开文章的视角,微博的文本分析技术上实现并不困难,下面以齐普夫定律的验证做一个展示。

首先找一个开源的微博语料库,我找到的是NLPIR微博内容语料库,里面有23万条微博内容。然后从里面提取词汇与词频,目的是用来验证下文献计量学中的齐普夫定律,也就是发现字词的使用次数(f)与字词的使次数排名(r)之乘积,会等于常数C。

上图来自维基百科

分析代码

以下代码可在下载数据并设定数据路径后重复。

# 读入xml包
library(XML)
# 读取数据并提取文本信息
doc <- xmlTreeParse('NLPIR微博内容语料库.xml',useInternal=TRUE)
rootNode <- xmlRoot(doc)
doc1 <- xpathSApply(rootNode,"//article",xmlValue)
# 去除无关标点与数字
doc2 <- gsub(pattern="http:[a-zA-Z\\/\\.0-9]+","",doc1)
# 中文分词
library(Rwordseg)
doc3 <- segmentCN(doc2)
# 构建语料库 去掉标点与数字与高频词
library(tm)
doc4 <- Corpus(VectorSource(doc3))
doc5 <- tm_map(doc4, removePunctuation)
doc6 <- tm_map(doc5, removeNumbers)
# 高频无意义词在这里可以搞到 https://github.com/yufree/democode/tree/master/data
x <- scan("stopwords.txt", what="")
doc7 <- tm_map(doc6, removeWords, x)
doc8 <- tm_map(doc7, stripWhitespace)
# 构建全范围的词频矩阵
control=list(minDocFreq=5,wordLengths = c(1, Inf),bounds = list(global = c(5,Inf)),weighting = weightTf,encoding = 'UTF-8')
doc.tdm=TermDocumentMatrix(doc8,control)
# 这里截取词频高于5长度为2的词
control2=list(minDocFreq=5,wordLengths = c(2, 2),bounds = list(global = c(5,Inf)),weighting = weightTf,encoding = 'UTF-8')
doc.tdm2=TermDocumentMatrix(doc8,control2)
# 这里截取词频高于5长度为3的词
control3=list(minDocFreq=5,wordLengths = c(3, 3),bounds = list(global = c(5,Inf)),weighting = weightTf,encoding = 'UTF-8')
doc.tdm3=TermDocumentMatrix(doc8,control3)
# 这里截取词频高于5长度为4的词
control4=list(minDocFreq=5,wordLengths = c(4, 4),bounds = list(global = c(5,Inf)),weighting = weightTf,encoding = 'UTF-8')
doc.tdm4=TermDocumentMatrix(doc8,control4)
# 这里截取词频高于5长度为5的词
control5=list(minDocFreq=5,wordLengths = c(5, 5),bounds = list(global = c(5,Inf)),weighting = weightTf,encoding = 'UTF-8')
doc.tdm5=TermDocumentMatrix(doc8,control5)
# 得到词频列表
library(slam)
freq <- rowapply_simple_triplet_matrix(doc.tdm,sum)
freq2 <- rowapply_simple_triplet_matrix(doc.tdm2,sum)
freq3 <- rowapply_simple_triplet_matrix(doc.tdm3,sum)
freq4 <- rowapply_simple_triplet_matrix(doc.tdm4,sum)
freq5 <- rowapply_simple_triplet_matrix(doc.tdm5,sum)
# save(freq,freq2,doc8,file ='constellation.RData')
# 验证齐普夫定律
order <- order(freq[order(freq,decreasing = T)],decreasing = T)
freq0 <- freq[order(freq,decreasing = T)]
order2 <- order(freq2[order(freq2,decreasing = T)],decreasing = T)
freq20 <- freq2[order(freq2,decreasing = T)]
order3 <- order(freq3[order(freq3,decreasing = T)],decreasing = T)
freq30 <- freq3[order(freq3,decreasing = T)]
order4 <- order(freq4[order(freq4,decreasing = T)],decreasing = T)
freq40 <- freq4[order(freq4,decreasing = T)]
order5 <- order(freq5[order(freq5,decreasing = T)],decreasing = T)
freq50 <- freq5[order(freq5,decreasing = T)]
# 结果可视化
# plot(log(order)~log(freq0))
png('logzipfplot.png')
par(mfrow=c(2,2))
plot(log(order2)~log(freq20),main="word length: 2")
plot(log(order3)~log(freq30),main="word length: 3")
plot(log(order4)~log(freq40),main="word length: 4")
plot(log(order5)~log(freq50),main="word length: 5")
dev.off()
png('czipfplot.png')
par(mfrow=c(2,2))
plot(order2*freq20,main="word length: 2")
plot(order3*freq30,main="word length: 3")
plot(order4*freq40,main="word length: 4")
plot(order5*freq50,main="word length: 5")
dev.off()

现象描述与讨论

结果很意外,我在很多帖子中看到人们肆无忌惮的使用该定律作为论据,但事实上且不论这本来就是一个经验定律,从我对微博数据分析的结果上看,齐普夫定律似乎并不符合微博语言习惯。

理论上第一张图会都是直线,但只有我们把词按5个一组进行区分时才能勉强看到一条直线。如果看下前50个词我们会发现这种分法可能捕捉到的更多是英文单词,所以可能是微博中大量出现的英文反映了齐普夫定律的语言使用环境。

zynga 发展中国家      happy      phone 
       504        189        148        131 
     webos      china 南京大屠杀      party 
       130        125        119        108 
     gmail      world      store      style 
       106        104         98         98 
个人所得税      ilook      never      there 
        93         90         89         88 
     gucci 高尔夫球场      touch      adobe 
        81         79         59         57 
     weico      weibo      hello      rovio 
        57         56         53         53 
     heart 印度尼西亚      icann      green 
        50         49         49         47 
     belle      kitty      leave 人民检察院 
        46         45         45         44 
原教旨主义      first      light 毛泽东思想 
        44         44         44         43 
中国科学院      black      david      kevin 
        42         42         42         42 
     brian      yahoo 中央气象台      nexon 
        41         41         40         40 
     nexus      apple      muddy      still 
        40         39         39         39 
     would      ralph 
        39         38 

但其实当分词在两三个时,出现的更多是中文词汇,这时候反而偏离了齐普夫定律,更像个抛物线规律。

两个字一个词

中国  腐败  城管  一个  北京  微博  问题  政府 
38951 37655 28787 24242 15834 14984 12972 12651 
 社会  今天  美国  国家  工作  公司  经济  已经 
11418 11310 11264 11261 10326  9722  8402  8227 
 现在  时间  表示  事件  香港  发现  世界  发生 
 8222  7941  7913  7755  7710  7466  7258  7196 
 进行  知道  人员  安全  生活  目前  新闻  调查 
 7189  7184  7077  7032  6985  6916  6901  6378 
 记者  今年  孩子  市场  官员  昨天  事故  企业 
 6043  6037  6034  5944  5919  5809  5748  5706 
 看到  图片  朋友  部门  视频  成为  全国  认为 
 5614  5587  5572  5496  5440  5386  5370  5339 
 大学  媒体 
 5317  5219 

三个字一个词

北京市 越来越 房地产 嫌疑人 公安局 老百姓 互联网 
  3266   2122   2074   2033   1928   1913   1804 
公务员 候选人 联合国 公安部 人民币 电视台 消费者 
  1789   1747   1728   1715   1657   1620   1577 
亿美元 负责人 委员会 国务院 铁道部 办公室 哈哈哈 
  1515   1514   1513   1457   1417   1243   1243 
进一步 中纪委 第一次 派出所 开发商    ceo    the 
  1241   1213   1125   1099   1096   1090   1068 
俄罗斯 幼儿园 临时工 董事长 发言人 意味着 机动车 
  1054   1006    982    952    916    902    897 
利比亚 大学生    you 万美元 全世界 新华社 朝阳区 
   821    798    796    781    766    764    762 
领导人 身份证 志愿者 一个月 总经理 自行车 发布会 
   750    741    717    705    688    661    651 
奢侈品 
   642

那么有人会说:你去掉了高频词,这个操作自然会导致齐普夫定律的不成立。没错,如果原本的数据集遵循齐普夫定律,那么我们去掉的高频词会导致常数C达不到。显然(我不是故意用这个词的),当排序被提前理论上会导致前面数值偏小,但不会导致后面也偏小,而应该是逼近常数C。

我们来看第二张图,如果微博数据符合齐普夫定律,那么我们应该看到一条水平线,结果出现了一个山峰,还是前坡陡后坡缓。

于是我接着探索,看下出现在顶峰的词是什么鬼:

两个字一个词

人心 阻止 一套 原文 随便 展开 男性 下次 无能 征集 
 421  442  422  443  420  643  421  442  422  441 
中方 轻松 手中 名人 走红 审判 借贷 滋生 水果 早安 
 423  443  420  421  425  442  422  426  643  423 
团购 森林   lt 债务 买房 观众 咖啡 环卫 遭到 警告 
 642  441  641  640  420  639  443  440  638  421 
嘉宾 城区 火锅 争取 选项 转型 原本 姐姐 震惊 角色 
 425  442  422  426  423  448  444  441  424  420 
军事 欧元 好多 好处 富人 商务 会长 有所 沉默 真心 
 443  643  440  421  425  641  422  640  442  445 

三个字一个词

执行官 侦查员 著作权 原材料 总公司    see 男朋友 
    91     91     91     92     84     63     91 
徐家汇 一口气 知情人 婴幼儿 交易日 信息化 小金库 
    90     92     84     63     91     90     92 
针对性    lte 写字楼 中文版    lee 银行家 直辖市 
    84     81     63     89     80     88     83 
专卖店 孙悟空 多一些 太阳能    tot 中南海 微生物 
    62     63     91     90     61     81     92 
抑郁症 手续费    fbi 自己人 小学校 新街口 一周年 
    84     89     80     64     62     83     88 
尼古丁    gif 从业者 国家队 一两个 演播室 芝加哥 
    63     61     91     90     81     84     71 
星期六 玉泉营 想象力 生产力 小博士 十多年 科技界 
    80     64     87     92     62     89     63 
债权人 
    60 

我对着这些词想半天也没搞出个所以然,但这里谈点直觉:我认为这批词词频与排序的乘积可以用来表征其在语料库中的影响力。在符合齐普夫定律的语料库中,影响力大的词无疑就是那些高频词,但这些词其实没什么卵用:因为太常见,常规自然语言处理都会有排除高频词的步骤。那么在不符合齐普夫定律且排除掉高频词的语料库中如何寻找有代表性的词?这些词不能太常见,但又不能不常见,否则形不成规律性。我感觉上面用词频与排序乘积大的词可能是符合这一要求的词汇,它们规模不大,但极有可能在不同分组中展示出巨大差别,而这种区别很有可能稀释到广泛意义上的微博日常讨论中。

半成品结论

  • 即使进行了高频词的去除,微博环境特别是中文语境也并不符合齐普夫定律
  • 中文语料库中展示出的词频与排序山峰式规律可能用来筛选分组中高影响力关键词
  • 微博语料库中的中英文混杂现象值得注意
  • 欢迎自行探索