R语言学习笔记之——数据处理神器data.table
当前位置:以往代写 > 其他教程 >R语言学习笔记之——数据处理神器data.table
2019-06-14

R语言学习笔记之——数据处理神器data.table

R语言学习笔记之——数据处理神器data.table

数据处理在数据分析流程中的地位相信大家都有目共睹,也是每一个数据从业者面临的更为繁重的工作任务。
在实际应用场景下,虽然SQL(SQL类专业的etl语言)是数据处理的推荐明星语言,性能佳、效率高、容易培养数据思维,但是SQL没法处理构建全流程的数据任务,之后仍然需要借助其他数据分析工具来对接更为深入的分析任务。
R语言作为专业的统计计算语言,数据处理是其一大特色功能,事实上每一个处理任务在R语言中都有着不止一套解决方案(这通常也是初学者在入门R语言时,感觉内容太多无从下手的原因),当然这些不同方案确实存在着性能和效率的绝大差异。
合理选择一套自己的数据处理工具组合算是挺艰难的选择,因为这个涉及到使用习惯和迁移成本的问题,比如你先熟知了R语言的基础绘图系统,在没有强大的驱动力的情况下,你可能不太愿意画大把时间去研究ggplot2,你用会写for/while循环,就不太愿意去掌握apply组函数,甚至那些性能逆天的并行算运算包;刚开始会用基础字符串处理,看到stringr包就面临着技能工具更新的问题……
太多的选择,让人眼花缭乱,我自己也遇到过这种困惑,为了避免注意力分散,我的做法是先做可能性罗列——罗列一个可以实现同类功能的所有工具清单并做一套功能卡(也算是初步了解)。然后根据自己掌握的现状选择最熟练的一套,随着时间的推移慢慢发现现有工具组合的不足,开始尝试往更加高效、简介的工具迁移,这样以需求为推动力的技能升级和迁移更为彻底和明确。
最典型的几个技能组合迁移如下:基础字符串处理函数——stringr绘图系统:plot——ggplot2代码风格:函数嵌套——管道函数(`%>%`)列表处理:list(自建循环)——rlistjson处理:Rjson+RJSONIO——jsonlite数据抓取:RCurl+XML——httr+xml2循环任务:for/while——apply——plyr::a_ply——并行运算(foreach、parallel)切片索引:subset——dplyr::select+filter聚合运算:aggregate——plyr::ddply+mutate——dplyr::group_by+summarize数据联结:merge——plyr::join——dplyr::left/right/inner/outer_join数据塑型:plyr::melt/dcast——tidyr::gather/spread……
其实还有很多类型的同类功能组合技能升级的路径,不一给出,虽然工具迁移确实面临着很高昂的代价,特别是时间成本、学习成本,但是迁移之后获得的高效、代码简洁的体验还是很爽的,以上特别是管道函数的迁移感触最深,再也不存在自己写完的东西间歇性懵逼的场景了。
说了这么多,绕了这么大的弯子想干啥呢,没错今天又要给自己升级新技能啦,这次的主角儿是
data.table
一个R语言高性能数据处理包,一个包可以涵盖以上所说的数据处理的大部分内容,而且操作高度抽象化话(抽象化就意味着代码量少的可怕)。
其实很早就接触过data.table,之所以一直没有深入应用,因为它的理念与其他数据处理包偏离太远,可以说迁移成本很高,几乎就是技能重构而非迁移。
不过随着视野的开阔,发现确实有必要深入了解这个高性能包,尽管有点儿颠覆R的传统风格,但是性能和效率的提升可以弥补这一点。
data.table
1、I/O性能:data.table的被推崇的重要原因就是他的IO吞吐性能在R语言诸多包中首屈一指,这里以一个1.6G多的2015年纽约自行车出行数据集为例来检验其性能到底如何,希望我的小米本能扛得住折腾~_~
#清空内存rm(list=ls())gc()#使用传统的I/O函数read_csv2进行导入:setwd(“D:/Python/citibike-tripdata/”)system.time(     mydata1 <- read.csv(“2015-citibike-tripdata.csv”,stringsAsFactors = FALSE,check.names = FALSE)      )
  用户   系统   流逝 197.34   2.56 200.75 object.size(mydata1)1914019808 bytes数据量还是很大的,将近1.6G,900多万记录,16个字段。R语言学习笔记之——数据处理神器data.table
可怜的机器呀,内存和磁盘要撑爆了~
使用data.table内的I/O函数进行导入:
rm(list=ls())gc()
library(“data.table”)
system.time(     mydata1 <- fread(“2015-citibike-tripdata.csv”)      )
Read 9937969 rows and 16 (of 16) columns from 1.606 GB file in 00:00:45 用户  系统  流逝 43.44  0.48 44.43五倍效率,45秒钟900万1.606G的数据,还是很有说服力的(虽然没有传说中的十倍性能)。
rm(list=ls())gc()
2、索引切片聚合data.table中提供了将行索引、列切片、分组功能于一体的数据处理模型。
DT[i,j,by]如果这个过程是SQL中是由select …… from …… where …… groupby …… having 来完成的,在R的其他基础包中起码也是分批次完成的。
dplyr::fliter() %>% select() %>% group_by() %>% summarize()虽然可以借助管道函数进行代码优化,但是仍然无法与data.table的简洁想抗衡。
mydata <- fread(“https://raw.githubusercontent.com/wiki/arunsrinivasan/flights/NYCflights14/flights14.csv”)这里使用一个在线数据集,包含2014年纽约机场发出的所有航班信息。
class(mydata)
[1] “data.table” “data.frame”R语言学习笔记之——数据处理神器data.table
使用fread函数导入之后便会自动转化为data.table对象,这是data.table所特有的高性能数据对象,同时继承了data.frame传统数据框类,也意味着他能囊括很多数据框的方法和函数调用。
str(mydata)一共253316条记录,17个字段。“year”      航班日期——年“month”     航班日期——月“day”       航班日期——天“dep_time”  航班起飞时间“dep_delay” 航班延误时长“arr_time”  航班到达时间“arr_delay” 航班到达延误时间“cancelled” 航班是否取消“carrier”“tailnum”“flight”“origin”    起飞地“dest”      目的地“air_time”“distance”  距离“hour”“min”

R语言学习笔记之——数据处理神器data.table
data.table行索引
carrier <- unique(mydata$carrier)[1] “AA” “AS” “B6” “DL” “EV” “F9” “FL” “HA” “MQ” “VX” “WN” “UA” “US” “OO”
tailnum <- sample(unique(mydata$tailnum),5)[1] “N332AA” “N813MQ” “N3742C” “N926EV” “N607SW”
origin  <- unique(mydata$origin)[1] “JFK” “LGA” “EWR”
dest    <- sample(unique(mydata$dest),5)[1] “BWI” “OAK” “DAL” “ATL” “ALB”“
mydata[carrier == “AA” ]#等价于mydata[carrier == “AA”,]#行索引可以直接引用列表,无需加表明前缀,这一点儿数据框做不到,而且i,j,by三个参数对应的条件支持模糊识别,无论加“,”与否都可以返回正确结果。
mydata[carrier %in% c(“AA”,”AS”),]
支持在行索引位置使用%in% 函数。data.table列索引列索引与数据框相比操作体验差异比较大,data.table的列索引摒弃了data.frame时代的向量化参数,而使用list参数进行列索引。
mydata[,list(carrier,tailnum)]R语言学习笔记之——数据处理神器data.table
为了操作体验更佳,这里的list可以简化为一个英文句点符号。即:
mydata[,.(carrier,tailnum)]#但心里要清楚列索引接受的条件是含有列表的列表,而且这里的列表作为变量给出,而非data.frame时代的字符串向量。行列同时索引毫无压力。
mydata[carrier %in% c(“AA”,”AS”),.(carrier,tailnum)]
R语言学习笔记之——数据处理神器data.table列索引的位置不仅支持列名索引,可以直接支持内建函数操作。
mydata[,.(flight/1000,carrier,tailnum)]支持直接在列索引位置新建列,赋值符号为:=。
mydata[,delay_all := dep_delay+arr_delay]#销毁某一列:mydata[,delay_all := NULL]R语言学习笔记之——数据处理神器data.tableR语言学习笔记之——数据处理神器data.table

批量新建列:mydata[,c(“delay_all”,”delay_dif”) := .((dep_delay+arr_delay),(dep_delay-arr_delay))]等价于写法2:mydata[,`:=`(delay_all = dep_delay+arr_delay,delay_dif =dep_delay-arr_delay )]#销毁新建列:mydata[,c(“delay_all”,”delay_dif”) := NULL]R语言学习笔记之——数据处理神器data.table
R语言学习笔记之——数据处理神器data.table

注意以上新建列时,如果只有一列,列名比较自由,写成字符串或者变量都可以,但是新建多列,必须严格按照左侧列名为字符串向量,右侧为列表的模式,当然你也可以使用第二种写法。
DT[,`:=`(varname1 = statement1 ,varname1 = statement2)]可以直接使用data.table内建的函数。
mydata[carrier %in% c(“AA”,”AS”),.N][1] 26876.N是一个计数函数,相当于plyr中的count,或者基础函数中的length。基本的统计函数都可以直接支持。
mydata[carrier %in% c(“AA”,”AS”),.(sum(dep_delay),mean(arr_delay))]       V1       V21: 228913 5.263841
mydata[carrier %in% c(“AA”,”AS”),.(dep_delay,mean(arr_delay))]
mydata[carrier %in% c(“AA”,”AS”) & dep_delay %between% c(500,1000),.(dep_delay,arr_delay)]
R语言学习笔记之——数据处理神器data.table

当整列和聚合的单值同时输出时,可以支持自动补齐操作。
当聚合函数与data.table中的分组参数一起使用时,data.table的真正威力才逐渐显露。
mydata[,.(sum(dep_delay),mean(arr_delay)),by = carrier]
R语言学习笔记之——数据处理神器data.table
多分组聚合。
mydata[,.(sum(dep_delay),mean(arr_delay)),by = .(carrier,origin)]R语言学习笔记之——数据处理神器data.table
多分组计数。
mydata[,.N,by = .(carrier,origin)]
R语言学习笔记之——数据处理神器data.table

自定义名称:mydata[,.(dep_delay_sum = sum(dep_delay),arr_delay_mean = mean(arr_delay)),by = carrier]mydata[,.(dep_delay_sum = sum(dep_delay),arr_delay_mean = mean(arr_delay)),by = .(carrier,origin)]mydata[,.(carrier_n = .N),by = .(carrier,origin)]R语言学习笔记之——数据处理神器data.table

数据排序:排序行:setorder(mydata,carrier,-arr_delay)setorder函数作用于mydata本身,运行无输出。如果想要运行的同时进行输出则可以在结尾加上[]
setorder(mydata,carrier,-arr_delay)[]
R语言学习笔记之——数据处理神器data.table
这个功能有点儿类似于基础函数中,在语句外部加上圆括号。(a <- 1+1)
排序列:sample(names(mydata),length(names(mydata))) [1] “arr_time”  “air_time”  “distance”  “dep_time”  “dest”      “arr_delay” “month”     “min”       “tailnum”   “origin”   [11] “year”      “hour”      “cancelled” “flight”    “day”       “carrier”   “dep_delay”
setcolorder(mydata,sample(names(mydata),length(names(mydata))))
mydata[carrier == “AA”,        lapply(.SD, mean),        by=.(carrier,origin,dest),        .SDcols=c(“arr_delay”,”dep_delay”)        ]
R语言学习笔记之——数据处理神器data.table
R语言学习笔记之——数据处理神器data.table
以上语法加入了新的参数.SDcols和.SD,咋一看摸不着头脑,其实是在按照carrier,origin,dest三个维度分组的基础上,对每个子块特定列进行均值运算。
这里的执行逻辑是这样的:by=.(carrier,origin,dest) 先按照三个维度进行全部的分组;.SDcols=c(“arr_delay”,”dep_delay”)则分别在筛选每一个子数据块儿上的特定列;lapply(.SD, mean)则将各个子块的对应列应用于均值运算,并返回最终的列表。数据合并:
data.table的数据合并方式非常简洁;
DT <- data.table(x=rep(letters[1:5],each=3), y=runif(15))DX <- data.table(z=letters[1:3], c=runif(3))设置各自的主键:
setkey(DT,x)setkey(DX,z)
DT[DX]
R语言学习笔记之——数据处理神器data.table就是如此简单,连接的执行逻辑是,内侧是左表,外侧是右表,所以是DX left join DT
如果没有设置主键,需要显式声明内部的on参数,指定连接主键,单主键必须在左右表中名称一致。
当然你要是特别不习惯这种用法,还是习惯使用merge的话,data.table仍然是支持的,因为他本来就继承了数据框,支持所有针对数据框的函数调用。
欢迎加入本站公开兴趣群商业智能与数据分析群兴趣范围包括各种让数据产生价值的办法,实际应用案例分享与讨论,分析工具,ETL工具,数据仓库,数据挖掘工具,报表系统等全方位知识QQ群:81035754

    关键字:

在线提交作业