练习2 文本处理
R需要包:Rwordseg包、rJava包
需要知识:正则表达式、配置Java环境
通过爬虫某热门微博评论得到五万余条数据,对其进行文本挖掘和数据分析
爬虫使用Python,分析使用R。与他人合作所做,本人负责数据处理,故此处仅说明分析
练习来源于想在某条微博上找到某个人,仅知其手机型号和评论内容,需寻找其用户名,后续分析属于无聊产物
-
数据收集
截至日前“微博搞笑排行榜”的一条关于“评论留下你想听的歌,看会不会有人私信给你唱”的微博已有三百五十余万条评论。通过Python编程针对此进行网页爬虫,根据评论时间截取2017年6月22日至25日四天时间获得50243条有效样本。
为匹配微博用户具体手机品牌,爬虫手机中国网站得到手机品牌库。评论中某些是想听某位歌手的任意歌曲,故爬虫百度音乐网站歌手大全获得5399位歌手。同时为根据不同需求得到歌曲不同曲库,称为小曲库与大曲库。小曲库是爬虫网易云音乐的一只歌单188首热门歌曲,大曲库是爬虫虾米音乐华语标签下1193只歌单共46914首歌曲。
1、微博评论
http://weibo.com/1713926427/Etq2WnSiR?filter=hot&root_comment_id=4070117551679469&type=comment#_rnd1498672693809
2、手机品牌
http://product.cnmo.com/manu.html
3、百度歌手
http://music.baidu.com/artist/
4、网易云歌单
http://music.163.com/#/playlist?id=625735202
5、虾米歌单
http://www.xiami.com/search/collect?spm=a1z1s.2943601.6856185.15.CZWfVA&key=%E5%8D%8E%E8%AF%AD
五个数据文件,分别名为微博weibo.csv、手机phone.csv、歌手artist.csv 、网易云music.summary.csv、虾米music.xiami.csv。
-
数据预处理
对得到的百度音乐歌手数据进行唯一化处理,同时将网易云音乐歌单中歌曲名进行初步文本处理。对虾米音乐文件中标签(Tag)以及音乐名(MusicName)进行拆分,将标签分为多个词组,将音乐名拆分为歌曲名和歌手名。
考虑到用户回复其他人的非有效信息,对于微博评论数据根据用户ID进行唯一化处理,通过建立索引找出用户ID重复的无效值,得到删除重复值的数据。
# unique user ID unique.uid <- duplicated(weibo1$uid) weibo <- weibo1[!unique.uid, ] str(weibo)
最终得到16686个有效样本,其中具体的变量指标含义如下: 用户ID(uid)、评论文本(text)、手机类型(source)、评论时间(time)、性别(sex)、用户名(name)、用户地址(location)、用户简介(intro)、注册时间(data),用户名与简介未分析。
-
数据分析
1. 注册时间
微博用户注册时间格式如:2017/06/25,我们需要提取其注册的年份,首先我们将其转化为2017-06-25这样R软件能识别的日期格式,然后提取前四位即2017,根据最终所得数据绘制出样本微博账号年注册量变化折线图。
# registered date png(file = "weibo.picture3.png") regi.date <- as.Date(weibo$date, format="%Y/%m/%d") #不同电脑版本Excel时间格式不同需要调整 regi.date.y <- substr(regi.date,1,4) str(regi.date.y) regi.date1 <- table(regi.date.y) plot.regi <- plot(regi.date1, type = "b", col="red", xlab = "年份", ylab = "注册量", main = "微博账号年注册量") tmp <- as.vector(regi.date1) text(plot.regi, tmp, labels=tmp, pos=3) # 添加值标签 dev.off()
2014、2015年注册账号评论的较多,其微博使用时长为2-3年,微博注册时间过早或者过晚评论量都有所下降。
2. 评论时间
comment.time1 <- weibo2$time comment.time2 <- as.POSIXlt(comment.time1, format="%Y/%m/%d %H:%M") comment.time <- comment.time2[!is.na(comment.time2)] hist(comment.time, breaks = 24)
3. 性别
评论此条微博账号中女性占了绝大一部分比例,高达74%
# sex png(file = "weibo.picture1.png") weibo.sex <- weibo$sex weibo.sex <- table(weibo.sex) lals <- paste(names(weibo.sex), round(weibo.sex/sum(weibo.sex)*100, 2), "%", sep="") pie(weibo.sex, col = c("deepskyblue", "#ff1493"),labels = lals) dev.off()
4. 用户地区
微博用户地址格式是“省份 市名”,提取前面两个字符即得到微博用户所在省份,并计算各省样本微博用户人数,统计前10位地区微博使用量最多的地区,绘制其直方图
# address png(file = "weibo.picture2.png") weibo.address <- substr(weibo$location, 1, 2) weibo.address.sort <- sort(table(weibo.address), decreasing = TRUE) bar.weibo <- barplot(weibo.address.sort[1:10],xlab = "地区", ylab = "人数",ylim=c(0,3000), col = "chocolate", main = "微博部分用户所在地") tmp <- as.vector(weibo.address.sort[1:10]) text(bar.weibo, tmp, labels=tmp, pos=3) # 添加值标签 dev.off()
5. 手机类型
微博用户为显示手机型号的个性化,都对其手机品牌名称都进行了自定义命名,手机品牌名称并不是单一的品牌名,比如“某某某的iPhone 6s Plus”。需要利用手机词库进行匹配,通过爬虫得到现有市面上各种手机品牌的名称,将手机品牌整合为一个向量添加进词库。分别将每个人的手机按照手机品牌进行分词,然后将每个人手机品牌分词与手机品牌大全进行匹配,若观测值所有变量都不能进行匹配就作为未知品牌处理
# all phone type all.phone <- read.csv(file="phone.csv", stringsAsFactors = FALSE) all.phone1 <- all.phone[215:332, 2] #仅部分需要 allphone <- c(all.phone1, "荣耀", "红米", "魅蓝", "HUAWEI", "IPad", "iPhone", "乐", "iPad", "OnePlus") #加入部分品牌的子品牌或别称
# phone type insertWords(allphone) #词库添加 phone.type1 <- segmentCN(weibo$source) #分词 # JAVA配置出现问题可用以下方法 # phone.exa <- enc2utf8(weibo$source) #转utf-8,有些格式它不支持 # phone.exa <- phone.exa[Encoding(phone.exa) != "unknown"] # phone.type1 <- segmentCN(phone.exa) # 筛选所需词汇 keep.word <- function(x, y, txt){ y <- x[x %in% txt] y } phone.type2 <- c() phone.type2 <- lapply(phone.type1, keep.word, phone.type2, allphone) phone.type <- unlist(phone.type2) #列表转为向量 str(phone.type) # 手机厂商分析 phone.type3 <- phone.type for (i in 1:length(phone.type)) { if(phone.type[i] == "魅蓝") phone.type3[i] <- "魅族" if(phone.type[i] == "HUAWEI") phone.type3[i] <- "华为" if(phone.type[i] == "荣耀") phone.type3[i] <- "华为" if(phone.type[i] == "红米") phone.type3[i] <- "小米" if(phone.type[i] == "乐") phone.type3[i] <- "乐视" if(phone.type[i] == "OnePlus") phone.type3[i] <- "一加" if(phone.type[i] == "苹果") phone.type3[i] <- "iPhone" } phone.type4 <- sort(table(phone.type3),decreasing = T) phone.num1 <- sum(phone.type4 > 300) phone.num2 <- sum(phone.type4 > 0) phone.else <-sum(phone.type4[phone.num1:phone.num2]) phone.na <- length(phone.type2)-sum(phone.type4) phone.type5 <- c(phone.type4[1:phone.num1], phone.else,phone.na) phone.type5.name <- c(names(phone.type5)[1:(length(names(phone.type5))-2)],"其他","未知类型")
# 画图 png(file = "weibo.picture4.png") lals <- paste(phone.type5.name, "", round(phone.type5/sum(phone.type5), 2)*100, "%", sep="") pie(phone.type5,labels = lals, main = "手机类型占比", col = c("lightskyblue","lawngreen","lightcoral", "yellow","red", "cyan", "chocolate","magenta", "pink")) dev.off() pdf(file = "weibo.picture5.pdf") bar.phone <- barplot(phone.type5,col = "chocolate", xlab = "手机类型", ylab = "人数", main = "手机类型使用情况", ylim = c(0,5500),names.arg=phone.type5.name) tmp <- as.vector(phone.type5) text(bar.phone, tmp, labels=tmp, pos=3) # 添加值标签 dev.off()
6. 评论文本
微博用户在微博下的评论较为杂乱,没有固定的评论格式,有的介绍自己喜欢的歌手,有的写出自己喜欢的歌曲,部分回复消息以及广告信息。首先分析微博用户评论中提及的歌手,然后分析评论中提及的歌曲。
对于评论数据的预处理,首先要剔除大量回复的数据,然后利用正则表达式删除“<>”中不需要的词
weibo.index <- substr(weibo$text, 1, 2) weibo.text1 <- weibo$text[which(weibo.index != "回复")] weibo.text2 <- gsub("<.*>", "", weibo.text1) # 删除<>中不需要词句
(1)歌手匹配
通过爬虫找到歌手名单,建立相应的歌手词库,利用歌手全部名单匹配各条评论里所提及的歌手,最后统计各个歌手被提到的次数
# singer list singer1 <- read.csv("artist.csv", header=FALSE, stringsAsFactors = FALSE) singer <- singer1[201:nrow(singer1), 2] # commment singer insertWords(singer) weibo.singer1 <- segmentCN(weibo.text2) weibo.singer2 <- c() weibo.singer2 <- lapply(weibo.singer1, keep.word, weibo.singer2, singer) weibo.singer <- unlist(weibo.singer2) weibo.singer3 <- sort(table(weibo.singer), decreasing = TRUE)
歌手 |
薛之谦 |
陈奕迅 |
五月天 |
周杰伦 |
林宥嘉 |
林俊杰 |
太阳 |
陈粒 |
鹿晗 |
张学友 |
杨千嬅 |
方圆 |
天空之城 |
王力宏 |
王菲 |
评论数 |
202 |
131 |
96 |
88 |
68 |
60 |
49 |
42 |
30 |
28 |
26 |
25 |
21 |
21 |
20 |
当前最热门的歌手薛之谦被评论的次数最多,其次是陈奕迅、五月天、和周杰伦等大众熟知的歌手。但是其中出现了太阳、方圆两位歌手,这主要是由于文本分词时有一定的缺陷,有些语句中出现了太阳和方圆两个词,但指的并非这两位歌手,而在统计词频时被统计进去。
(2) 歌曲匹配
(i)对评论里歌曲进行挖掘时方法一是将书名号里的内容摘选出来,得到《彩虹》、《心酸》、《独家记忆》等639首歌曲。
# comment music weibo.text3 <- grep("《.*》", weibo.text2) weibo.text4 <- gsub(".*《", "", weibo.text2[weibo.text3]) weibo.text5 <- gsub("》.*", "", weibo.text4) weibo.text5[1:20]
(ii)爬虫网易云一只歌单188首热门歌曲,建立相应的小曲库,将其导入进词库中,由此进行分词,将分词后的结果与上述曲库进行匹配摘选出有效信息。
# part music matching music.part1 <- read.csv("music.summary.csv", header=FALSE, stringsAsFactors = FALSE) music.part2 <- as.vector(as.matrix(music.part1)) music.part <- gsub("(.*)", "", music.part2) insertWords(music.part) weibo.text2[1:10] weibo.music.part1 <- segmentCN(weibo.text2) weibo.music.part2 <- c() weibo.music.part2 <- lapply(weibo.music.part1, keep.word, weibo.music.part2, music.part) weibo.music.part <- unlist(weibo.music.part2) weibo.music.part.sort <- sort(table(weibo.music.part), decreasing = TRUE) as.data.frame(weibo.music.part.sort[1:50])
序号 |
歌曲名 |
点歌数 |
序号 |
歌曲名 |
点歌数 |
序号 |
歌曲名 |
点歌数 |
1 |
可乐 |
211 |
11 |
说散就散 |
100 |
21 |
好久不见 |
61 |
2 |
安和桥 |
198 |
12 |
晚安 |
99 |
22 |
我们 |
58 |
3 |
有没有 |
195 |
13 |
理想三旬 |
95 |
23 |
小半 |
58 |
4 |
成全 |
154 |
14 |
那就这样吧 |
82 |
24 |
男孩 |
50 |
5 |
成都 |
148 |
15 |
突然好想你 |
81 |
25 |
浪费 |
48 |
6 |
暧昧 |
147 |
16 |
岁月神偷 |
73 |
26 |
春风十里 |
45 |
7 |
小幸运 |
140 |
17 |
我想 |
72 |
27 |
走马 |
42 |
8 |
晴天 |
120 |
18 |
白山茶 |
68 |
28 |
春雨里洗过的太阳 |
41 |
9 |
童话镇 |
120 |
19 |
睡不着 |
63 |
29 |
彩虹 |
39 |
10 |
追光者 |
113 |
20 |
刚好遇见你 |
61 |
30 |
奇妙能力歌 |
39 |
# xiami music music.xiami1 <- read.csv("music.xiami.csv", header=TRUE, stringsAsFactors = FALSE) music.xiami2 <- music.xiami1[ , c(1, 3, 4)]) music_name1 <- music.xiami2$MusicName music_name2 <- sub("-.*", "", music_name1) music_name <- gsub("\\(.*\\)", "", music_name2) music_singer <- gsub(".*-", "", music_name1) music_tag1 <- music.xiami2$Tag music_tag2 <- sub("虾.*", "", music_tag1) music_tag3 <- strsplit(music_tag2, "\\s") # duplicated(music_name)[1:50] # music_name3[which(duplicated(music_name))[1:6]] # music_tag3[which(music_name == "一千零一个愿望")] # sort(table(unlist(music_tag[which(music_name == "十年")])), decreasing = TRUE)
# all music matching insertWords(music_name) weibo.music1 <- segmentCN(weibo.text2) weibo.music2 <- c() weibo.music2 <- lapply(weibo.music1, keep.word, weibo.music2, music_name) weibo.music <- unlist(weibo.music2) # sort(table(weibo.music), decreasing = TRUE)[1:30] # weibo.music2[10:20]
用户ID |
评论 |
歌曲 |
标签 |
歌单 |
3194198775 |
杨千嬅的炼金术 |
炼金术 |
粤语 流行 安静 伤感 |
深情粤语 |
6118833189 |
我怀念的_. 萧敬腾 |
我怀念的 |
青春 时光 经典 |
那些感动过我们的华语声音 |
5519079950 |
想听《你爱上的我》,有人会么。 |
你爱上的我 |
爱情 抒情 流行 情歌 温暖 |
她爱他,后知后觉 |
5502421670 |
梁咏琪的短发<span class="url-icon">…… |
短发 |
女声 怀旧 经典 80后 |
那些和回忆有关的美丽声音 |
5677925408 |
还是想听海阔天空,beyond的,发了好几遍了,却始终没人唱给我听…… |
海阔天空 |
经典 怀旧 老歌 回忆 精选 追忆 励志 |
经典华语怀旧老歌一百首 |