小白学R—复杂数据处理

这一关属于进阶关,难度相比前面提高了不少,所以花费的时间也多了一些。
本关的学习内容主要为:如何编写函数;数据处理: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 = <DATA> ) +  #创建画板
#   <GEOM_FUNCTION>(mapping=aes( <MAPPINGS>))  #添加图层

应用到本实例中,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)-重新执行代码-找到错误原因。
写的比较简单,大家可以找一些参考资料学习。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容