此为本次作业需要的文件

链接:https://pan.baidu.com/s/1PXClUp6CVvFNM6MP9YS6nw?pwd=sdkz
提取码:sdkz

我们通过简单的爬虫抓取了当当网的机器学习相关的图书数据,并保存为 ./books_total.csv 文件。通过爬虫采集原始数据,但是由于各种原因,原始数据往往会存在许多问题,例如数据格式不正确,数据存在冗余等等。因此第一手获得的原始数据不能直接使用,需要进行数据清洗。所以我们需要对基于爬取的书籍数据进行数据清洗,使其称为符合我们要求的数据。

目录

  1. 读取数据
  2. 提取价格数值
  3. 提取评论数
  4. 转换星级
  5. 获取出版信息
    5.1 提取作者
    5.2 提取出版社
    5.3 提取出版日期
  6. 提取书名和书简介
  7. 数据筛选和汇总
  8. 总结

1.读取数据

  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 中的变量 单击查看 

在这里插入图片描述

  1. 通过 dim() 函数查看数据的行数和列数。

rowcol <-dim(book1)

rownum<-rowcol[1]
colnum<-rowcol[2] 
cat("行数:",rownum," 列数:",colnum)

在这里插入图片描述

  1. 使用 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中的众多函数。
首先提取了价格、评论以及星级的数值;然后对于出版信息中的数据分别获取书籍的作者、出版社和出版日期;最后基于原始数据的书名,进一步提取书的简介和名称,相较于前几步来说,提取书简介和书名可能相对复杂一些,当然在实际数据清洗时可能有多种方法,本作业仅提供其中一种方法供同学们参考。

Logo

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

更多推荐