引用 r-tutor上的定义:css
DataFrame 是一个表格或者相似二维数组的结构,它的各行表示一个实例,各列表示一个变量。
没错,DataFrame就是相似于Excel表格和MySQL数据库同样是一个结构化的数据体。而这种结构化的数据体是当代数据流编程中的中流砥柱,几乎全部先进算法的载体都是DataFrame,好比如今咱们耳熟能详的逻辑回归算法、贝叶斯算法、支持向量机算法、XGBoost算法等等都创建在这个数据流编程的基础之上,咱们能够在R、Python、Scala等函数式编程中找到他们的身影。html
参考前文 [[原]基于RStudio Webinars的统计报告Web化与工程化实践总结](https://segmentfault.com/a/11...、数据清洗、数据处理、数据可视化以及数据建模五个模块。git
readr简化了咱们读取多种格式表格型数据的方法,包括分割文件withread_delim()
,read_csv()
、read_tsv()
、read_csv2()
、固定宽度文件读取的read_fwf()
、read_table()
以及read_log()
来读取Web日志文件。在参数配置方面是和原生的read.xxx()
函数族是看齐的。github
readr是利用C++和RCpp编写的,因此执行的速度是至关快的,不过相对于直接用C语言写的data.table::fread()
就稍微慢大概1.2-2倍左右。在实际使用中,data.talbe::fread()
的读取速度能够比原生的read.csv
有3-10倍的提高速度。算法
httr是一个高级的网络请求库,相似于Python中的Tornado和Requests,除了提供基本的Restful接口设计功能,好比GET()
, HEAD()
, PATCH()
, PUT()
, DELETE()
和 POST()
,还提供了OAuth的调用,好比oauth1.0_token()
和oauth2.0_token()
。并且httr
还提供了诸如session、cookie、SSL、header、proxy、timeoutd等更太高级管理功能。固然你能够用它来作简单的爬虫应用,若是须要更高级的爬虫,咱们须要投入rvest的怀抱来支持诸如xpath
等高级爬虫特性。sql
DBI是一个为R与数据库通信的数据库接口。至关于Java里面的DAO,Python里的Torndb和Tornlite,方便多种关系型数据库的SQL请求。其中最亮眼的是,R中的DataFrame和数据库以前能够以整个数据框插入的形式插入数据而不须要再拼接SQL语句。数据库
如下是一个官方文档的示例:apache
library(DBI) # 建立一个临时内存的 RSQLite 数据库 con <- dbConnect(RSQLite::SQLite(), dbname = ":memory:") dbListTables(con) # 直接插入整个数据框到数据库中 dbWriteTable(con, "mtcars", mtcars) dbListTables(con) dbListFields(con, "mtcars") dbReadTable(con, "mtcars") # 你能够获取全部结果: res <- dbSendQuery(con, "SELECT * FROM mtcars WHERE cyl = 4") dbFetch(res) dbClearResult(res) # 或者一次取一块 res <- dbSendQuery(con, "SELECT * FROM mtcars WHERE cyl = 4") while(!dbHasCompleted(res)){ chunk <- dbFetch(res, n = 5) print(nrow(chunk)) } dbClearResult(res) dbDisconnect(con)
tidyr
是一个数据清洗的新包,正在取代reshape2
、spreadsheets
等包。清洁的数据在数据处理的后续流程中十分重要,好比数据变化(dplyr),可视化(ggplot2/ggvis)以及数据建模等。tidyr
主要提供了一个相似Excel中数据透视表(pivot table)的功能,提供gather
和spread
函数将数据在长格式和宽格式之间相互转化,应用在好比稀疏矩阵和稠密矩阵之间的转化。此外,separate
和union
方法提供了数据分组拆分、合并的功能,应用在nominal数据的转化上。编程
相似于Python中的json库,参考前文 [[原]数据流编程教程:R语言与非结构化数据共舞](https://segmentfault.com/a/11...,咱们能够知道jsonlite是一个标准的json转化库,依赖于jsonlite咱们能够自由地在JSON和DataFrame之间相互转化。json
dplyr包是如今数据流编程的核心,同时支持主流的管道操做 %>%
,主要的数据处理方法包括:
select()
: 按列变量选择filter()
: 按行名称分片slice()
: 按行索引分片mutate()
: 在原数据集最后一列追加一些数据集summarise()
: 每组聚合为一个小数量的汇总统计,一般结合gruop_by()
使用arrange()
: 按行排序
inner_join(x, y)
: 匹配 x + yleft_join(x, y)
: 全部 x + 匹配 ysemi_join(x, y)
: 全部 x 在 y 中匹配的部分anti_join(x, y)
: 全部 x 在 y 中不匹配的部分
intersect(x, y)
: x 和 y 的交集(按行)union(x, y)
: x 和 y 的并集(按行)setdiff(x, y)
: x 和 y 的补集 (在x中不在y中)
更多详细操做能够参考由SupStats翻译的 数据再加工速查表,比Python的老鼠书直观不少。
参考前文 数据流编程教程:R语言与非结构化数据共舞,咱们知道,区别于dplyr
包,rlist
包是针对非结构化数据处理而生的,也对以list为核心的数据结构提供了相似DataFrame的高级查询、管道操做等等方法。
purrr
向Scala这样的具备高级类型系统的函数式编程语言学习,为data frame的操做提供更多的函数式编程方法,好比map、lambda表达式。此外,purrr
引入了静态类型,来解决原生的apply
函数族类型系统不稳定的状况。
我遇到过一个很是头疼的apply
函数的问题:apply内的表达式计算结果不一致。
# 原来表达式是这样的,可是返回的计算结果不对: # x1,x2,x3都是一个含有NA值的一个10x10的矩阵 apply(x1*x2-x1*x3,1,sum,na.rm=T)
因而改为分步计算才能获得正确答案。
t1 <- apply(x1 * x2,1,sum,na.rm=T) t2 <- apply(x1 * x3,1,sum,na.rm=T) t3 <- t1 - t2
若是使用purrr
包就能够很好的解决这一问题。参考 Wisdom's Quintessence: Purrr package for R is good for performance 的例子:
library(purrr) mtcars %>% split(.$cyl) %>% map(~ lm(mpg ~ wt, data = .)) %>% map(summary) %>% map_dbl("r.squared")
具体使用能够参考Rstudio Blog:purrr 0.2.0。
ggplot2 是一个加强的数据可视化R包,帮助咱们轻松建立使人惊叹的多层图形。它的设计理念相似于PhotoShop,具体参数包含设计对象、艺术渲染、统计量、尺寸调整、坐标系统、分片显示、位置调整、动画效果等等。
更多操做能够查看ggplot2与数据可视化速查表 和 官方文档
实战能够参考R Graphics Cookbook一书。
ggvis
是吸取了ggplot2、vega以及d3的精华,目标旨在配合shiny打造动态可交互的可视化组件。ggvis
最明显的区别就是在做图时直接支持%>%
的管道操做,好比:
diamonds %>% ggvis(~carat, ~price, fill=~clarity) %>% layer_points(opacity:=1/2)
ggplot2与ggvis的关系相似于plyr与dplyr的关系,都是一种演化过程。
在机器学习的本质其实就是各类姿式的回归,而在R中的各类回归分析每每不会返回一个整齐的data frame 结果。好比:
lmfit <- lm(mpg ~ wt, mtcars) lmfit
## ## Call: ## lm(formula = mpg ~ wt, data = mtcars) ## ## Coefficients: ## (Intercept) wt ## 37.285 -5.344
这时候broom
包就派上用场了,直接将统计结果转化为data frame格式:
library(broom) tidy(lmfit)
## term estimate std.error statistic p.value ## 1 (Intercept) 37.285126 1.877627 19.857575 8.241799e-19 ## 2 wt -5.344472 0.559101 -9.559044 1.293959e-10
augment()
函数返回data frame格式的s其全部他参数结果
head(augment(lmfit))
## .rownames mpg wt .fitted .se.fit .resid .hat .sigma .cooksd .std.resid ## 1 Mazda RX4 21.0 2.620 23.28261 0.6335798 -2.2826106 0.04326896 3.067494 1.327407e-02 -0.76616765 ## 2 Mazda RX4 Wag 21.0 2.875 21.91977 0.5714319 -0.9197704 0.03519677 3.093068 1.723963e-03 -0.30743051 ## 3 Datsun 710 22.8 2.320 24.88595 0.7359177 -2.0859521 0.05837573 3.072127 1.543937e-02 -0.70575249 ## 4 Hornet 4 Drive 21.4 3.215 20.10265 0.5384424 1.2973499 0.03125017 3.088268 3.020558e-03 0.43275114 ## 5 Hornet Sportabout 18.7 3.440 18.90014 0.5526562 -0.2001440 0.03292182 3.097722 7.599578e-05 -0.06681879 ## 6 Valiant 18.1 3.460 18.79325 0.5552829 -0.6932545 0.03323551 3.095184 9.210650e-04 -0.23148309
glance()
函数,返回data frame格式的部分参数结果
glance(lmfit)
## r.squared adj.r.squared sigma statistic p.value df logLik ## 1 0.7528328 0.7445939 3.045882 91.37533 1.293959e-10 2 -80.01471 ## AIC BIC deviance df.residual ## 1 166.0294 170.4266 278.3219 30
众所周知,data.frame的几个缺点有:
针对这几个问题,data.table应运而生。data.table完美兼容data.frame,这意味着以前对data.frame的操做咱们能够彻底保留,而且支持更多方便的数据操做方法。
data.table还参考了NoSQL中流行的Key-Value形式,引入了setkey()
函数,为数据框设置关键字索引。
值得一提的是data.table引入了全新的索引形式,大大简化了data frame的分片形式,提供接近于原生矩阵的操做方式并直接利用C语言构造底层,保证操做的速度。
对比data.table 和 dplyr 的操做:
操做 | data.table | dplyr |
---|---|---|
按行分片 | DT[1:2,] | DF[1:2,] |
按列分片 | DT[,1:2,with=False] | DF[,1:2] |
分组summarise | DT[, sum(y), by=z] | DF %>% group_by(z) %>% summarise(sum(y)) |
分组mutate | DT[, y := cumsum(y), by=z] | ans <- DF %>% group_by(z) %>% mutate(y = cumsum(y)) |
筛选后分组汇总 | DT[x > 2, sum(y), by=z] | DF %>% filter(x>2) %>% group_by(z) %>% summarise(sum(y)) |
筛选后分组更新 | DT[x > 2, y := cumsum(y), by=z] | ans <- DF %>% group_by(z) %>% mutate(y = replace(y, which(x>2), cumsum(y))) |
分组后按条件汇总 | DT[, if(any(x > 5L)){y[1L]-y[2L]}else{y[2L], by=z]} | DF %>% group_by(z) %>% summarise(if (any(x > 5L)) y[1L]-y[2L] else y[2L]) |
操做 | data.table | dplyr |
---|---|---|
分组扩展各list | DT[, (cols) := lapply(.SD, sum), by=z] | ans <- DF %>% group_by(z) %>% mutate_each(funs(sum)) |
分组汇总各list | DT[, lapply(.SD, sum), by=z] | DF %>% group_by(z) %>% summarise_each(funs(sum)) |
分组汇总各list | DT[, c(lapply(.SD, sum),lapply(.SD, mean)), by=z] | DF %>% group_by(z) %>% summarise_each(funs(sum, mean)) |
分组汇总各list | DT[, c(.N, lapply(.SD, sum)), by=z] | DF %>% group_by(z) %>% summarise_each(funs(n(), mean)) |
setkey(DT1, x, y)
操做 | data.table | dplyr |
---|---|---|
通常join | DT1[DT2] | left_join(DT2, DT1) |
择列join | DT1[DT2, .(z, i.mul)] | left_join(select(DT2, x,y,mul), select(DT1, x,y,z)) |
聚合join | DT1[DT2, .(sum(z)*i.mul), by=.EACHI] | DF1 %>% group_by(x, y) %>% summarise(z=sum(z)) %>% inner_join(DF2) %>% mutate(z = z*mul) %>% select(-mul) |
更新join | DT1[DT2, z := cumsum(z)*i.mul, by=.EACHI] | join and group by + mutate |
滚动join | DT1[DT2, roll = -Inf] | / |
其余变量控制输出 | DT1[DT2, mult = "first"] | / |
操做 | data.table | dplyr |
---|---|---|
分组再分list聚合 | DT[, list(x[1], y[1]), by=z] | DF %>% group_by(z) %>% summarise(x[1], y[1]) |
分组再分list拼接 | DT[, list(x[1:2], y[1]), by=z] | DF %>% group_by(z) %>% do(data.frame(.$x[1:2], .$y[1])) |
分组取分位数聚合 | DT[, quantile(x, 0.25), by=z] | DF %>% group_by(z) %>% summarise(quantile(x, 0.25)) |
分组取分位数拼接 | DT[, quantile(x, c(0.25, 0.75)), by=z] | DF %>% group_by(z) %>% do(data.frame(quantile(.$x, c(0.25, 0.75)))) |
分组分list聚合拼接 | DT[, as.list(summary(x)), by=z] | DF %>% group_by(z) %>% do(data.frame(as.list(summary(.$x)))) |
更多操做详情可查看data.table速查表。
DT
包是谢溢辉老师的大做,为data frame数据提供了很是好的可视化功能,而且提供了筛选、分页、排序、搜索等数据查询操做。
library(DT) datatable(iris)
此外,DT
包还提供了大量的UI定制的功能,对html、css和js进行深度定制。好比:
m = matrix(c( '<b>Bold</b>', '<em>Emphasize</em>', '<a href="http://rstudio.com">RStudio</a>', '<a href="#" onclick="alert(\'Hello World\');">Hello</a>' ), 2) colnames(m) = c('<span style="color:red">Column 1</span>', '<em>Column 2</em>') datatable(m) # 默认 escape = TRUE
datatable(m, escape = FALSE)
raw_matrix %>% DT::datatable(options = list(pageLength = 30, dom = 'tip')) %>% DT::formatStyle(columns = c("A","B") background = styleColorBar(c(0, max(raw_matrix,na.rm = TRUE)), 'steelblue'), backgroundSize = '100% 50%', backgroundRepeat = 'no-repeat', backgroundPosition = 'center')
sparklyr是 rstudio 公司为连接spark 和dataframe 编写的一套分布式数据处理框架,用一个统一的跨引擎API简化了多数据源的分析操做,进一步将data frame底层的分布式傻瓜化。
在R中使用sparklyr::spark_apply,咱们不须要修改以前任何的代码,而且绕过Hadoop的绝对限制,就可让data frame格式的数据,自动得到分布式处理的能力!
# 建立 spark连接 管理器来运行Spark引擎 sc <- sparklyr::spark_connect(master = "local", version = "2.2.0", method = "livy", config = sparklyr::config()) # 经过SQL读取spark数据 ddf <- DBI::dbGetQuery(sc, "select * from mtcars") /*Basic Stats*/ # 返回行/列的值 ncol(ddf) nrow(ddf) # 在 DF 上进行运行标准汇总 summary(ddf)
更多具体操做能够参考官方指南
操做 | R | Python | Spark |
---|---|---|---|
库 | base | Pandas | spark SQL |
读取csv | read.csv() | read_csv() | spark-csv |
计数 | nrow() | pandasDF.count() | sparkDF.count() |
分片 | head(data,5) | pandasDF.head(5) | sparkDF.show(5) |
推断类型 | 自动推断 | 自动推断 | 默认为string类型 |
标准差计算中的NaN处理 | 视为NA | 自动排除 | 视为NaN |
特征工程 | dplyr::mutate() | pandasDF['new'] | sparkDF.withColumn() |
sqldf
经过SQL直接操做DataFrame,在Python中可使用 pysqldf
。tidyverse
或者 pandas
,使用这样的链式调用方法能够提高数据流的处理效率,规避一些原生SQL在不一样数据库中执行状况不一样或者可读性较差的问题。data.table
或者 scala
,使用这样高性能的方法能够在关键步骤提高数据处理效率到极致,不过会牺牲一部分维护性。做为分享主义者(sharism),本人全部互联网发布的图文均听从CC版权,转载请保留做者信息并注明做者 Harry Zhu 的 FinanceR专栏: https://segmentfault.com/blog...,若是涉及源代码请注明GitHub地址: https://github.com/harryprince。微信号: harryzhustudio 商业使用请联系做者。