R语言数据清洗作业
R语言数据清洗作业
此为本次作业需要的文件
链接:https://pan.baidu.com/s/1PXClUp6CVvFNM6MP9YS6nw?pwd=sdkz
提取码:sdkz
我们通过简单的爬虫抓取了当当网的机器学习相关的图书数据,并保存为 ./books_total.csv 文件。通过爬虫采集原始数据,但是由于各种原因,原始数据往往会存在许多问题,例如数据格式不正确,数据存在冗余等等。因此第一手获得的原始数据不能直接使用,需要进行数据清洗。所以我们需要对基于爬取的书籍数据进行数据清洗,使其称为符合我们要求的数据。
目录
- 读取数据
- 提取价格数值
- 提取评论数
- 转换星级
- 获取出版信息
5.1 提取作者
5.2 提取出版社
5.3 提取出版日期 - 提取书名和书简介
- 数据筛选和汇总
- 总结
1.读取数据
- 首先,我们借助 readr 包中的函数,读取原始数据,将其转换成 R 中的 Data.Frame 格式。注意由于数据中包含中文,需要正确设置字符编码。
# 将数据读入R中
library(tidyverse)
library(readr)
library(dplyr)
#book1=data.frame(read.csv('G:/r数据/作业2/book.csv',header=TRUE,encoding = 'UTF-8'))
book1 <- read_delim("G:/r数据/作业2/books_total.csv","\t", escape_double = FALSE, trim_ws = TRUE)
book1
view(book1)
############################# 结果为 enviroment 中的变量 单击查看
- 通过 dim() 函数查看数据的行数和列数。
rowcol <-dim(book1)
rownum<-rowcol[1]
colnum<-rowcol[2]
cat("行数:",rownum," 列数:",colnum)
- 使用 head() 函数查看前10行数据
# qianshihang 前十行数据
qianshihang <-head(book1,10)
可以看出原始数据中有许多问题,例如当前价格带有人民币符号’¥’,评论数含有文本等等。在本案例中我们按照步骤完成数据清洗,主要任务为:
1)去掉当前价格这一列中的 '¥' 符号,转换成数值格式。
2)星级列转换成数字格式,取值范围为{0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5}。例如width:90%先转换为0.9,然后以最高星分数5乘以0.9最终得到4.5。
3)对于评论数这一列直接提取数值。
4)出版信息分为三列分别是作者、出版日期、出版社。
5)将原始数据中的书名拆分为为书名和简介两列。
2.提取价格数值
对于价格最主要的目的是提取数据中的数值,经过分析,我们发现价格是由“¥+价格”组成的,所以,我们只需要把第一个“¥”去掉就行了
#k 为提取的表
K <-book1 %>%
mutate(当前价格=as.numeric(str_sub(`当前价格`,2,str_length(`当前价格`))))
K
扩展:
我们可以使用正则匹配将数值提取出来,同学们可以自行看《R数据科学》的P135,学习正则表达式。
3.提取评论数
由于评论是也是通过 str_sub() 提取数值,但是“条评论”是在后面的,所以,需要结合其他函数 str_locate。
#q 为提取的表
q <-K %>%
#mutate(评论数=str_sub(`评论数`,1,str_length(`评论数`)-3))%>%
#mutate(locate=str_locate(`评论数`,"条")-1)%>%
mutate(评论数=as.numeric ( str_sub(`评论数`,str_locate(`评论数`, "([0-9])+"))))
q
4.转换星级
对于星级,首先要提取出数值,然后对数值进行计算,计算方法为用提取后的数值除以20,就得到最终的星级。对应关系如下表:
原始数据 | 数值 | 星级 |
---|---|---|
width: 0%; | 0 | 0 |
width: 10%; | 10 | 0.5 |
width: 20%; | 20 | 1 |
width: 30%; | 30 | 1.5 |
width: 40%; | 40 | 2 |
width: 50%; | 50 | 2.5 |
width: 60%; | 60 | 3 |
width: 70%; | 70 | 3.5 |
width: 80%; | 80 | 4 |
width: 90%; | 90 | 4.5 |
width: 100%; | 100 | 5 |
我们可以使用 str_match() 进行匹配,也可以组合使用 str_sub() 进行字符串的截取。
#w 为提取的表
w <-q %>%
mutate(星级= as.double( str_sub(`星级`,str_locate(`星级`, "([0-9])+")))/20)
w
5.获取出版信息
接下来我们处理出版信息这一列,从原始数据中可以看到,这一列主要包含三个信息,分别是作者、出版日期、出版社。它们以/分隔,并且存放在一个数据单元中,因此我们将它们分别取出,然后单独存为三列。
5.1 提取作者
从原始数据中可以看出以/分隔的第一个数据是作者,因此我们可以直接提取。
使用字符串的 str_split() 函数可以对字符串按照特定字符分割,并且分割后是列表形式:
e<-mutate(w,"作者"="暂无作者信息")
#由于作者当中含有 作者//作者 所以做了判断 和对作者为空的情况也做了判断
for(i in 1:rownum){
if(length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))==3){
author=str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,1]
e["作者"][[1]][i]<-author
}else if(length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))>3){
author=str_c(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,1],str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,2]," ",str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,3])
e["作者"][[1]][i]<-author
}else if(length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))<3){
if(str_detect((str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,1]),"出版社")||str_detect((str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,1]),"([0-9])+") ){
e["作者"][[1]][i]<-"暂无作者信息"
}
}
}
e
test <- “周志华/2016-01-01/清华大学出版社”
str_split(test,“/”,simplify = TRUE)1
[,1] [,2] [,3]
[1,] “周志华” “2016-01-01” “清华大学出版社”
对出版信息这一列的每一个数据按照/分隔后取第一个数据就是作者,提取后我们将它保存在作者这一列。
5.2提取出版社
r<-mutate(e,"出版社"="暂无出版社信息")
# 对出版社为空的情况也做了判断
for(i in 1:rownum){
if(length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))==3){
publishHouse=str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,3]
r["出版社"][[1]][i]<-publishHouse
}else if(length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))>3){
publishHouse=str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,5]
r["出版社"][[1]][i]<-publishHouse
}else if(length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))<3&&length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))>=1){
if(str_detect((str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,1]),"出版社")){
publishHouse=str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,1]
r["出版社"][[1]][i]<-publishHouse
}else if(length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))>1){
if(str_detect((str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,2]),"出版社")){
publishHouse=str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,2]
r["出版社"][[1]][i]<-publishHouse
}
}else{
r["出版社"][[1]][i]<-"暂无出版社信息"
}
}else{
r["出版社"][[1]][i]<-"暂无出版社信息"
}
}
r
5.3提取出版日期
出版社的提取,以此类推
t<-mutate(r,"出版日期"="暂无出版日期信息")
#对出版日期为空的情况也做了判断
for(i in 1:rownum){
if(length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))==3){
publishDate=str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,2]
t["出版日期"][[1]][i]<-publishDate
}else if(length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))>3){
publishDate=str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,4]
t["出版日期"][[1]][i]<-publishDate
}else if(length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))<3&&length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))>=1){
if(str_detect((str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,1]),"([0-9])")){
publishDate=str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,1]
t["出版日期"][[1]][i]<-publishDate
}else if(length(str_split(w["出版信息"][[1]][i],"/",simplify = TRUE))>1){
if(str_detect((str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,2]),"([0-9])")){
publishDate=str_split(w["出版信息"][[1]][i],"/",simplify = TRUE)[,2]
t["出版日期"][[1]][i]<-publishDate
}
}else{
t["出版日期"][[1]][i]<-"暂无出版日期信息"
}
}else{
t["出版日期"][[1]][i]<-"暂无出版日期信息"
}
}
t
6.提取书名和书简介
书名信息中混合这书的简介信息,观察原始数据中书名一列,能找到一些规律。书名和其他内容基本是由空格隔开的,我们可以按照空格分隔字符串,第一个内容便是书名。
需要注意的是,我们不能用直接使用str_split()函数,因为简介中也会有空格。
所以,我们可以组合使用str_replace() 和 str_split()
str_replace(books_total$书名, " “,”_____")
#先把书名中的所有空格替换为_____
t["书名"][[1]]<- str_replace(t["书名"][[1]], " ","_____")
bookname<- str_split(t["书名"][[1]],"_____",simplify = TRUE)[,1]
得到书名后,剩余的内容便是简介。
#将简介为空也做了判断 ,在提取简介的时候把书名作为了分隔符,选择了分割以后的第二个向量 并将其中含有的 "_____" 替换为了 "" .
t<-mutate(t,"简介"="暂无简介")
for(i in 1:length(bookname)){
introduction=str_split(t["书名"][[1]][i], fixed(bookname[i]),simplify = TRUE)[2]
introduction <-str_replace(introduction, "_____","")
if(introduction!=""){
t["简介"][[1]][i] <- introduction
}
}
t<-mutate(t,"书名"=bookname)
提取出书名称和简介信息后,我们可以将数据中的原始书名列删除。
最后,将清洗完成的数据保存到 CSV 文件中。
# booksIntroduction 为最终的表格,并将最终表格的列的次序重新排列
booksIntroduction<-t %>%
select(书名,简介,当前价格,星级,评论数,作者,出版社,出版日期)
booksIntroduction
#将 booksIntroduction 写入到 booksIntroduction.csv 文件中 并采用TAb作为分隔符 UTF-8的编码格式
write.table(booksIntroduction,"booksIntroduction.csv",row.names = FALSE,col.names = TRUE,sep="\t",fileEncoding ="UTF-8" )
7.数据筛选和汇总
(1) 统计出 清华大学出版社 出版的图书数
U<- booksIntroduction
U<-U %>%
filter(`出版社` %in% "清华大学出版社") -> qhcbs
cat("(1)清华大学出版社出版的图书数为",dim(qhcbs)[1],"本")
(2) 2019年之后出版的,价格大于100元的图书
o<- booksIntroduction
o <- mutate(booksIntroduction,"tag"=0)
for(i in 1:rownum){
if(str_detect(booksIntroduction["出版日期"][[1]][[i]],"[1-9]+")){
if(as.numeric(format(as.Date(booksIntroduction["出版日期"][[1]][[i]],Orange = "%Y-%m-%d"),"%Y"))>2019){
o["tag"][[1]][[i]] <- 1
}
}
}
o %>%
filter(`tag`==1) %>%
filter(`当前价格`>100)%>%
select(书名,简介,当前价格,星级,评论数,作者,出版社,出版日期) -> o
(3) 评论超过100条,评价大于4星的图书,并且按照 星数,评论数以此逆序排序
p<-booksIntroduction
p %>%
filter(`评论数`>100) %>%
filter(`星级`>4) %>%
arrange(desc(`星级`),desc(`评论数`)) -> p
(4) 统计出各出版社,出版5星图书的数量
g<-booksIntroduction
g %>%
filter(`星级`==5) %>%
group_by(出版社) %>%
summarise("五星数量"= n()) -> g
8.总结
由于数据采集时获得的数据可能并不规范,不能直接用来分析,因此需要做数据清洗。本练习对爬虫抓取的书籍数据进行清洗,主要使用stringr中的众多函数。
首先提取了价格、评论以及星级的数值;然后对于出版信息中的数据分别获取书籍的作者、出版社和出版日期;最后基于原始数据的书名,进一步提取书的简介和名称,相较于前几步来说,提取书简介和书名可能相对复杂一些,当然在实际数据清洗时可能有多种方法,本作业仅提供其中一种方法供同学们参考。

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐
所有评论(0)