这一关属于进阶关,难度相比前面提高了不少,所以花费的时间也多了一些。
本关的学习内容主要为:如何编写函数;数据处理:dplyr, ggplot2;如何编写业务模块;代码如何调试。
1.如何编写函数
1.1 自编函数模板
my_fun <- function(arg1,arg2,...){
body
ruturn(data)
}
例如下面,若add(1,2),结果z=3
add <- function(x,y) {
z <- x+y
return(z)
}
1.2 控制语句-循环和条件
1.2.1 for 循环的基本模板
for(i in data){
body
}
假设有一项重复性工作,如下:
library(stringr)
print(str_c("第几次吃饭",1,sep=":"))
print(str_c("第几次吃饭",2,sep=":"))
print(str_c("第几次吃饭",3,sep=":"))
重复去写1,2,3,...会很麻烦,我们可以用for循环来简化:
for(i in 1:3) {
print(
str_c("第几次吃饭",i,sep=":")
)
}
1.2.2 while循环的基本模板
while (condition){
body
}
例如:
i <- 10
while(i>0){
print(
i <- i-1)
}
注意:while 一定要有循环结束的判断条件,否则会无限循环下去。
1.2.3 条件语句的基本模板
if(condition){
body
}else{
body
}
例如钱包内有100,吃饭花费30,余额提醒:
money <- 100
if(money>0){
money <- money-30
print("钱包还有钱,不需要取钱")
}else{
print("钱包没有钱,去取款机吧")
}
再举一个复杂点的例子:饭卡余额1000,每天吃3顿饭,每顿5元,余额低于5元,提示:
everday <- function(eatNumber,money){
for(i in eatNumber){
eatNumber <- str_c("今天吃第几次饭:",i,sep="")
money <- money-5*i
print(money)
print(eatNumber)
}
if(money<5){
print("饭卡没钱了:去银行取钱")
}else{
print("饭卡还有钱:不用去银行")
}
}
2.数据处理-dplyr、ggplot2
dplyr是一套数据处理工具,它提供了多个函数来帮助你完成常见的数据处理工作:
- mutate()函数对已有列进行数据运算并添加为新列,类似transform()
- select()根据列名选择出需要的子集
- filter()基于数值挑选对象,可以按给定的逻辑条件筛选符合要求的子数据集
- summarise()对数据框调用函数进行汇总操作, 返回一维的结果
- arrange()按给定的列名依次对行进行排序,默认为升序,类似order()
ggplot2是R中重要的绘图工具: - ggplot2的核心理念是将绘图与数据分离,数据相关的绘图与数据无关的绘图分离
- ggplot2是按图层作图
- ggplot2保有命令式作图的调整函数,使其更具灵活性
- ggplot2将常见的统计变换融入到了绘图中。
接下来,我们利用一个例子,来深入学习这两个包。
2.1 数据分析流程
数据预分析步骤:理解数据-数据导入-数据预处理-数据计算-数据显示。
2.1.1 数据导入
首先加载包和数据集。
install.packages("dplyr")
install.packages("nycflights13")
library(dplyr)
library(nycflights13)
2.1.2 数据预处理步骤
进行数据预处理的步骤:选择子集-列重命名-删除缺失数据-处理日期-类型转换-数据排序。
2.1.2.1 选择子集
确定分析目标:航班航线距离与延误时间的关系
# 查看数据结构
str(flights)
myFlights <- select(flights,year,month,day,
dep_delay,arr_delay,distance,dest)
# select也可以进行模糊匹配
select(data,
starts_with("abc"), #以abc开头
ends_with("xyz"), #以xyz结尾
contains("ijk"), #包含ijk
matches("(.)\\1")) #正则表达式,字符或数据匹配
2.1.2.2 列名重命名
myFlights <- rename(myFlights,destination=dest)
#tips:新列名在前,旧列名在后
2.1.2.3 删除缺失数据
myFlights <- filter(myFlights,!is.na(dep_delay),!is.na(arr_delay))
filter()更多用法:
# 查找数据
filter(myFlights,month==12,day==25) #查找12.25的航班
filter(myFlights,arr_delay>120|dep_delay>120) #延误超2h的航班
2.1.2.4 数据排序
这里我们用的是dplyr中的arrange()函数,默认为升序,desc()让表示降序。
arrange(myFlights,dep_delay)
arrange(myFlights,desc(dep_delay))
2.1.3 数据计算
用dplyr包的分组函数group_by()和组合函数summarise()来进行计算。
数据处理的一般模式: Split(数据分组) - Apply(应用函数) - Combine(组合结果)
# 按照目的地进行分组
by_dest <- group_by(myFlights,destination)
# 求平均到达延误时间和平均航行里程
delay <- summarise(by_dest,
count=n(), #航班数-每个分组有多少数据
dist=mean(distance,na.rm = TRUE),
delay=mean(arr_delay,na.rm=TRUE))
# 移除噪音数据--移除样本数量较小的数据
delay <- filter(delay,count>20)
以上的过程,可以利用管道:%>% 进行简化
delays <- flights%>%
group_by(dest)%>%
summarise(
count=n(),
dist=mean(distance,na.rm = TRUE),
delay=mean(arr_delay,na.rm = TRUE)
)%>%
filter(count>20)
2.1.4 数据显示
数据显示要用到绘图包ggplot2,ggplot()是一个图层一个图层来绘制图形的,用其中的加号"+"来结合各个图层,ggplot2绘图的一般模板为:
# ggplot(data = ) + #创建画板
# (mapping=aes( )) #添加图层
应用到本实例中,ggplot()括号内的参数是要使用的数据,然后是geom_point(mapping = aes(x = dist, y = delay)),这是用来绘制散点图的,x轴为距离dist,y轴为延迟时间delay。 geom_smooth(mapping = aes(x = dist, y = delay))用来给图加入平滑的曲线,以展示x和y的关系。
ggplot(data=delay)+
geom_point(mapping = aes(x=dist,y=delay))+
geom_smooth(mapping = aes(x=dist,y=delay))
3.如何编写业务模块
3.1 模块介绍
一个项目通常会有以下几个模块:
- 视图模块(view):数据显示的实现代码
- 业务逻辑模块(service):数据处理的代码
- 数据层模块(db):数据分析要连接的数据库
各个模块的文件会放在相同名字的文件夹里面,根据需要还可以创建其他模块: - 公共模块(util):放项目的公共材料,比如项目的配置信息
- 公共数据(data):数据分析用到的数据
- 日志模块(log):数据处理流程
- 数据输出模块(output):放数据分析的结果,比如绘制的图形和Excel文件等
例如本例中,util里的packageManager.R代码:
#管理安装包
# 数据包
packages <- c("nycflights13")
if (length(setdiff(packages, rownames(installed.packages()))) > 0) {
install.packages(setdiff(packages, rownames(installed.packages())))
}
#字符串包
packages <- c("stringr")
if (length(setdiff(packages, rownames(installed.packages()))) > 0) {
install.packages(setdiff(packages, rownames(installed.packages())))
}
#图形包
packages <- c("ggplot2")
if (length(setdiff(packages, rownames(installed.packages()))) > 0) {
install.packages(setdiff(packages, rownames(installed.packages())))
}
#数据处理包
packages <- c("dplyr")
if (length(setdiff(packages, rownames(installed.packages()))) > 0) {
install.packages(setdiff(packages, rownames(installed.packages())))
}
3.2 业务逻辑模块
在业务逻辑模块的文件夹(service)里创建R脚本flight.R:
install.packages("dplyr")
install.packages("nycflights13")
library(dplyr)
library(nycflights13)# for data
#航班航行距离与延误时间的关系
#输入:不需要输入参数
#输出:返回每个目的地的平均航行距离,平均延误时间
disDelay <- function(){
#选择子集
myFlights <- select(flights,
year,month,day,
dep_delay,arr_delay,
distance,dest)
#列名重命名,等号左边是新列名,右边是就列名
myFlights <- rename(myFlights, destination = dest)
#删除缺失数据,这里的空值NA代表航班取消
myFlights <- filter(myFlights,
!is.na(dep_delay),
!is.na(arr_delay))
#数据排序
myFlights <- arrange(myFlights, desc(dep_delay))
#数据计算:航班航行距离与延误时间的关系
delay <- myFlights %>%
group_by(destination) %>%
summarise(
count = n(),
dist = mean(distance, na.rm = TRUE),
delay = mean(arr_delay, na.rm = TRUE)
) %>%
filter(count > 20)
return(delay)
}
3.3 视图模块
在视图模块文件夹(view)里把前面的数据显示实现代码(flightView.R)存入:
library(ggplot2)
library(stringr)
#获取当前项目运行根路径
projectPath <- getwd()
#获取service路径
servicePath <- str_c(projectPath,
"service",
"flight.R",
sep="/")
#编译R文件,利用source()调用外部代码并运行
source(servicePath)
#业务逻辑:航班航行距离与延误时间的关系
delay <- disDelay()
#绘制散点图
view <- ggplot(data = delay) +
geom_point(mapping = aes(x = dist, y = delay)) +
geom_smooth(mapping = aes(x = dist, y = delay))
#定义散点图保存路径
outputpath <- str_c(projectPath,"output","delayFlight.jpg",sep="/")
#利用ggsave()来保存散点图到上面的路径中
ggsave(filename=outputpath, plot=view)
4.代码如何调试
Rstudio中的代码搜索功能,例如想知道业务逻辑模块中的disDelay 具体代码,可以双击选中函数-进入函数定义的地方:Rstudio-Code-Go to Function Definition。
一个简单的代码调试过程:
代码出现错误-错误在哪块代码-理解错误代码大概什么意思-打断点(stop)-编译(source)-重新执行代码-找到错误原因。
写的比较简单,大家可以找一些参考资料学习。