首页 » 漏洞 » R语言数据科学新类型tibble

R语言数据科学新类型tibble

 

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹, 程序员R,Nodejs,Java
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:

http://blog.fens.me/r-tibble/

R语言数据科学新类型tibble

前言

最近正在整理用R语言进行数据处理的操作方法,发现了 RStudio 公司开发的数据科学工具包tidyverse,一下子就把我吸引了。通过2天时间,我把tidyverse项目整体的学了一遍,给我的启发是非常大的。tidyverse 重新定义了数据科学的工作路径,而且路径上每个核心节点,都定义了对应的R包。这真是一项造福数据分析行业的工程,非常值得称赞!!

tidyverse个项目,包括了一系列的子项目,其中tibble被定义为取代传统data.frame的数据类型,完全有颠覆R的数据操作的可能。跟上R语言领袖的脚步,领先进入数据科学新的时代。

目录

  1. tibble介绍
  2. tibble安装
  3. tibble包的基本使用
  4. tibble的源代码分析

1. tibble介绍

tibble是R语言中一个用来替换data.frame类型的扩展的数据框,tibble继承了data.frame,是弱类型的,同时与data.frame有相同的语法,使用起来更方便。tibble包,也是由Hadley开发的R包。

tibble对data.frame做了重新的设定:

  • tibble,不关心输入类型,可存储任意类型,包括list类型
  • tibble,没有行名设置 row.names
  • tibble,支持任意的列名
  • tibble,会自动添加列名
  • tibble,类型只能回收长度为1的输入
  • tibble,会懒加载参数,并按顺序运行
  • tibble,是tbl_df类型

tibble的项目主页: https://github.com/tidyverse/tibble

2. tibble安装

本文所使用的系统环境

  • Win10 64bit
  • R: 3.2.3 x86_64-w64-mingw32/x64 b4bit

tibble是在CRAN发布的标准库,安装起来非常简单,2条命令就可以了。

~ R > install.packages('tibble') > library(tibble)

RStudio官方把tibble项目,集成到了tidyverse项目中了,官方建议直接安装tidyverse项目,这样整个用来做数据科学的库都会被下载下来。

~ R > install.packages('tidyverse') > library(tidyverse) #> Loading tidyverse: ggplot2 #> Loading tidyverse: tibble #> Loading tidyverse: tidyr #> Loading tidyverse: readr #> Loading tidyverse: purrr #> Loading tidyverse: dplyr #> Conflicts with tidy packages ---------------------------------------------- #> filter(): dplyr, stats #> lag():    dplyr, stats

tidyverse项目,是一个包括了数据科学的一个集合工具项目,用于数据提取,数据清理,数据类型定义,数据处理,数据建模,函数化编程,数据可视化,包括了下面的包。

  • ggplot2, 数据可视化
  • dplyr, 数据处理
  • tidyr, 数据清理
  • readr, 数据提取
  • purrr, 函数化编程
  • tibble, 数据类型定义

tidyverse项目的地址: https://github.com/tidyverse/tidyverse 。高效的使用R语言做数据科学,请参考开源图书 R for Data Science .

3. tibble包的基本使用

对于tibble包的使用,主要需要掌握创建、数据转型、数据查看、数据操作、与data.frame的区别点。复杂的数据处理功能,是dplyr项目来完成,下一篇讲dplyr的文章再给大家介绍。

3.1 创建tibble

创建一个tibble类型的data.frame是非常简单的,语法与传统的data.frame是类似的。

# 创建一个tibble类型的data.frame > t1<-tibble(1:10,b=LETTERS[1:10]);t1 # A tibble: 10 x 2    `1:10`     b     <int> <chr>  1      1     A  2      2     B  3      3     C  4      4     D  5      5     E  6      6     F  7      7     G  8      8     H  9      9     I 10     10     J  # 创建一个data.frame > d1<-data.frame(1:10,b=LETTERS[1:10]);d1    X1.10 b 1      1 A 2      2 B 3      3 C 4      4 D 5      5 E 6      6 F 7      7 G 8      8 H 9      9 I 10    10 J

从上面的输出可以看到tibble类型,会在输出时多一行,用来指定每一列的类型。

tibble用缩写定义了7种类型:

  • int,代表integer
  • dbl,代表double
  • chr,代表character向量或字符串。
  • dttm,代表日期+时间(a date + a time)
  • lgl,代表逻辑判断TRUE或者FALSE
  • fctr,代表因子类型factor
  • date,代表日期dates.

查看类型,发现tbl_df继承了tbl继承是data.frame,所以tibble是data.frame的子类型。

# t1为tbl_df类型 > class(t1) [1] "tbl_df"     "tbl"        "data.frame"  # 是data.frame类型 > class(d1) [1] "data.frame"

让我们多角度来观察t1变量。

# 判断是不是tibble类型 > is.tibble(t1) [1] TRUE  # 查看t1的属性 > attributes(t1) $names [1] "1:10" "b"     $class [1] "tbl_df"     "tbl"        "data.frame"  $row.names  [1]  1  2  3  4  5  6  7  8  9 10  # 查看t1的静态结构 > str(t1) Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 10 obs. of  2 variables:  $ 1:10: int  1 2 3 4 5 6 7 8 9 10  $ b   : chr  "A" "B" "C" "D" ...

通过文本排列来创建一个tibble

> tribble( +   ~colA, ~colB, +   "a",   1, +   "b",   2, +   "c",   3 + ) # A tibble: 3 x 2    colA  colB   <chr> <dbl> 1     a     1 2     b     2 3     c     3

通过vector创建tibble

> tibble(letters) # A tibble: 26 x 1    letters      <chr>  1       a  2       b  3       c  4       d  5       e  6       f  7       g  8       h  9       i 10       j # ... with 16 more rows

通过data.frame创建tibble,这时就会报错了。

> tibble(data.frame(1:5)) Error: Column `data.frame(1:5)` must be a 1d atomic vector or a list

通过list创建tibble

> tibble(x = list(diag(1), diag(2))) # A tibble: 2 x 1               x          <list> 1 <dbl [1 x 1]> 2 <dbl [2 x 2]>

我们看到tibble其实是存储list类型,这是data.frame做不到的。

通过一个tibble,创建另一个tibble,这时也会报错了。

> tibble(x = tibble(1, 2, 3)) Error: Column `x` must be a 1d atomic vector or a list

3.2 数据类型转换

tibble是一个新的类型,R语言中大部分的数据都是基于原有的数据类型,所以原有数据类型与tiblle类型的转换就显的非常重要了。

把一个data.frame的类型的转换为tibble类型

# 定义一个data.frame类型变量 > d1<-data.frame(1:5,b=LETTERS[1:5]);d1   X1.5 b 1    1 A 2    2 B 3    3 C 4    4 D 5    5 E  # 把data.frame转型为tibble > d2<-as.tibble(d1);d2 # A tibble: 5 x 2    X1.5      b   <int> <fctr> 1     1      A 2     2      B 3     3      C 4     4      D 5     5      E  # 再转回data.frame > as.data.frame(d2)   X1.5 b 1    1 A 2    2 B 3    3 C 4    4 D 5    5 E

我们可以看到tibble与data.frame的转型是非常平滑的,一个转型函数就够,不需要中间做任何的特殊处理。

把一个vector转型为tibble类型,但是不能再转回vector了。

# vector转型到tibble > x<-as.tibble(1:5);x # A tibble: 5 x 1   value   <int> 1     1 2     2 3     3 4     4 5     5  # tibble转型到vector, 不成功 > as.vector(x) # A tibble: 5 x 1   value   <int> 1     1 2     2 3     3 4     4 5     5

把list转型为tibble。

# 把list转型为tibble > df <- as.tibble(list(x = 1:500, y = runif(500), z = 500:1));df # A tibble: 500 x 3        x          y     z    <int>      <dbl> <int>  1     1 0.59141749   500  2     2 0.61926125   499  3     3 0.06879729   498  4     4 0.69579561   497  5     5 0.05087461   496  6     6 0.63172517   495  7     7 0.41808985   494  8     8 0.78110219   493  9     9 0.95279741   492 10    10 0.98930640   491 # ... with 490 more rows  # 把tibble再转为list > str(as.list(df)) List of 3  $ x: int [1:500] 1 2 3 4 5 6 7 8 9 10 ...  $ y: num [1:500] 0.5914 0.6193 0.0688 0.6958 0.0509 ...  $ z: int [1:500] 500 499 498 497 496 495 494 493 492 491 ...

tibble与list的转型也是非常平滑的,一个转型函数就够。

把matrix转型为tibble。

# 生成一个matrix > m <- matrix(rnorm(15), ncol = 5)  # matrix转为tibble > df <- as.tibble(m);df # A tibble: 3 x 5           V1         V2         V3         V4         V5                                                                                       1  0.8436494  2.1420238  0.2690392 -0.4752708 -0.2334994 2  1.0363340  0.8653771 -0.3200777 -1.7400856  1.2253651 3 -0.2170344 -1.1346455  0.2204718  1.2189431  0.7020156  # tibble转为matrix > as.matrix(df)              V1         V2         V3         V4         V5 [1,]  0.8436494  2.1420238  0.2690392 -0.4752708 -0.2334994 [2,]  1.0363340  0.8653771 -0.3200777 -1.7400856  1.2253651 [3,] -0.2170344 -1.1346455  0.2204718  1.2189431  0.7020156                                         

从上面的转型测试可以看到,tibble类型是非常友好的,可以与data.frame, list, matrix 进行相互转型操作。tibble与vector是不能进行直接转型的,这与data.frame的行为是一致的,如果需要转型,我们可以分别取出每一列进行拼接,或转为matrix再操作。

3.3 tibble数据查询

通常我们是str()函数来观察数据的静态组成结果,在tibble包提供了一个glimpse(),可以方便我们来观察tibble和data.frame类型的数据。

比较glimpse()和str()对于data.frame的数据查看输出

> glimpse(mtcars) Observations: 32 Variables: 11 $ mpg             21.0, 21.0, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, 22.8, 19.2, 17.8, 16.4, 17.... $ cyl                 6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8, ... $ disp                    160.0, 160.0, 108.0, 258.0, 360.0, 225.0, 360.0, 146.7, 140.8, 167.6, 167.6... $ hp                          110, 110, 93, 110, 175, 105, 245, 62, 95, 123, 123, 180, 180, 180, 205, 215... $ drat                            3.90, 3.90, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.92, 3.92, 3.92, 3.07, 3.0... $ wt                                  2.620, 2.875, 2.320, 3.215, 3.440, 3.460, 3.570, 3.190, 3.150, 3.440, 3.440... $ qsec                                    16.46, 17.02, 18.61, 19.44, 17.02, 20.22, 15.84, 20.00, 22.90, 18.30, 18.90... $ vs                                          0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, ... $ am                                              1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, ... $ gear                                                4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 3, 3, ... $ carb                                                    4, 4, 1, 1, 2, 1, 4, 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, 1, 2, 1, 1, 2, 2, 4, 2, ...  # 打印静态结构 > str(mtcars) 'data.frame': 32 obs. of  11 variables:  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...  $ disp: num  160 160 108 258 360 ...  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...  $ qsec: num  16.5 17 18.6 19.4 17 ...  $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...                                                                                                                                                           

比较glimpse()和str()对于tibble的数据查看输出。

# 新建tibble > df <- tibble(x = rnorm(500), y = rep(LETTERS[1:25],20))  # 查看df > glimpse(df) Observations: 500 Variables: 2 $ x            -0.3295530, -2.0440424, 0.1444697, 0.8752439, 1.7705952, 0.5898253, 0.1991844,... $ y                "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P"...  # 查看df静态结构 > str(df) Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 500 obs. of  2 variables:  $ x: num  -0.33 -2.044 0.144 0.875 1.771 ...  $ y: chr  "A" "B" "C" "D" ...           

按列出数据,一层[]返回的结果还是tibbe,二层[]与$返回的结果为列组成的向量。

> df <- tibble(x = 1:3, y = 3:1)  # 按列取,返回tibble > df[1] # A tibble: 3 x 1       x   <int> 1     1 2     2 3     3  # 按列取,返回向量 > df[[1]] [1] 1 2 3 > df$x [1] 1 2 3

按行取数据,这时一定要用,来做分隔符

# 取第一行 > df[1,] # A tibble: 1 x 2       x     y   <int> <int> 1     1     3  # 取前2行 > df[1:2,] # A tibble: 2 x 2       x     y   <int> <int> 1     1     3 2     2     2  # 取第二列的2,3行 > df[2:3,2] # A tibble: 2 x 1       y   <int> 1     2 2     1

3.4 tibble数据操作

增加一列。

# 创建一个tibble > df <- tibble(x = 1:3, y = 3:1);df # A tibble: 3 x 2       x     y   <int> <int> 1     1     3 2     2     2 3     3     1  # 增加一列 > add_column(df, z = -1:1, w = 0) # A tibble: 3 x 4       x     y     z     w   <int> <int> <int> <dbl> 1     1     3    -1     0 2     2     2     0     0 3     3     1     1     0

增加一行,还是基于上面生成的df变量。

# 在最后,增加一行 > add_row(df, x = 99, y = 9) # A tibble: 4 x 2       x     y   <dbl> <dbl> 1     1     3 2     2     2 3     3     1 4    99     9  # 插入第二行,增加一行 > add_row(df, x = 99, y = 9, .before = 2) # A tibble: 4 x 2       x     y   <dbl> <dbl> 1     1     3 2    99     9 3     2     2 4     3     1

3.5 tibble与data.frame的区别

列名,可以自由定义,并且会自动补全。

> tb <- tibble( +   `:)` = "smile", +   ` ` = "space", +   `2000` = "number", +   `列名` = "hi", +   1,1L + ) > tb # A tibble: 1 x 6    `:)`   ` ` `2000`  列名   `1`  `1L`   <chr> <chr>  <chr> <chr> <dbl> <int> 1 smile space number    hi     1     1

数据,按顺序执行懒加载。

> a <- 1:5 > tibble(a, b = a * 2) # A tibble: 5 x 2       a     b   <int> <dbl> 1     1     2 2     2     4 3     3     6 4     4     8 5     5    10

打印输出控制,tibble的打印控制被重写了,所以执行print()函数时,模型会先进行类型匹配,然后调用print.tbl()。

# 创建tiblle > tb<-tibble(a=1:5, b = a * 2, c=NA, d='a', e=letters[1:5])  # 打印前10行,不限宽度 > print(tb,n = 10, width = Inf) # A tibble: 5 x 5       a     b     c     d     e   <int> <dbl> <lgl> <chr> <chr> 1     1     2    NA     a     a 2     2     4    NA     a     b 3     3     6    NA     a     c 4     4     8    NA     a     d 5     5    10    NA     a     e  # 打印前3行,宽度30 > print(tb,n = 3, width = 30) # A tibble: 5 x 5       a     b     c     d   <int> <dbl> <lgl> <chr> 1     1     2    NA     a 2     2     4    NA     a 3     3     6    NA     a # ... with 2 more rows, and 1 #   more variables: e             # 用print函数,打印data.frame > df<-data.frame(tb) > print(df)   a  b  c d e 1 1  2 NA a a 2 2  4 NA a b 3 3  6 NA a c 4 4  8 NA a d 5 5 10 NA a e     

3.7 特殊的函数

lst,创建一个list,具有tibble特性的list。 lst函数的工作原理,类似于执行[list()],这样的操作。

# 创建一个list,懒加载,顺序执行 > lst(n = 5, x = runif(n)) $n [1] 5 $x [1] 0.6417069 0.2674489 0.5610810 0.1771051 0.1504583

enframe,快速创建tibble。enframe提供了一个模板,只有2列name和value,快速地把2个向量匹配的tibble中,可以按行生成或按列生成。

# 按列生成 > enframe(1:3) # A tibble: 3 x 2    name value   <int> <int> 1     1     1 2     2     2 3     3     3  # 按行生成 > enframe(c(a = 5, b = 7)) # A tibble: 2 x 2    name value   <chr> <dbl> 1     a     5 2     b     7

deframe,把tibble反向转成向量,这个函数就实现了,tibble到向量的转换。它默认把name列为索引,用value为值。

# 生成tibble > df<-enframe(c(a = 5, b = 7));df # A tibble: 2 x 2    name value   <chr> <dbl> 1     a     5 2     b     7  # 转为vector > deframe(df) a b  5 7

3.8 用于处理data.frame函数

tibble还提供了一些用于处理data.frame的函数。

# 创建data.frame > df<-data.frame(x = 1:3, y = 3:1)  # 判断是否有叫x的列 > has_name(df,'x') [1] TRUE  # 判断是否有行名 > has_rownames(df) [1] FALSE  # 给df增加行名 > row.names(df)<-LETTERS[1:3];df   x y A 1 3 B 2 2 C 3 1  # 判断是否有行名 > has_rownames(df) [1] TRUE  # 去掉行名 > remove_rownames(df)   x y 1 1 3 2 2 2 3 3 1  # 把行名转换为单独的一列 > df2<-rownames_to_column(df, var = "rowname");df2   rowname x y 1       A 1 3 2       B 2 2 3       C 3 1  # 把一列设置为行名 > column_to_rownames(df2, var = "rowname")   x y A 1 3 B 2 2 C 3 1  # 把行索引转换为单独的一列 > rowid_to_column(df, var = "rowid")   rowid x y 1     1 1 3 2     2 2 2 3     3 3 1

这些data.frame的工具函数,我猜是用于data.frame到tibble的数据类型转换用的,因为tiblle是没有行名的。

4. tibble的源代码分析

对于tibble包的深入理解,我们需要分析tibble包底层的源代码,以及设计原理。我们打开github上是tibble项目,找到 tibble.R 的源代码,先来了解一下tibble类型的定义。

找到tibble函数的定义:

tibble <- function(...) {   xs <- quos(..., .named = TRUE)   as_tibble(lst_quos(xs, expand = TRUE)) }

tibble函数的构成是非常简单地,用quos()和lst_quos()函数来分割参数,再用as_tibble()函数,生成tibble类型。

我们再找到as_tibble函数的定义:

as_tibble <- function(x, ...) {   UseMethod("as_tibble") }  as_tibble.tbl_df <- function(x, ..., validate = FALSE) {   if (validate) return(NextMethod())   x }

这个函数是一个S3类型的函数,可以S3面向对象类型的方法,来查找tibble相关的重写的函数。关于S3类型的详细介绍,请参与文章 R语言基于S3的面向对象编程

> methods(generic.function=as_tibble) [1] as_tibble.data.frame* as_tibble.default*    as_tibble.list*       as_tibble.matrix*     [5] as_tibble.NULL*       as_tibble.poly*       as_tibble.table*      as_tibble.tbl_df*     [9] as_tibble.ts*

利用S3的查询函数,把整个tibble类型定义的泛型化函数都找到了。

接下来,我们继续到 tbl_df 的类型的定义

#' @importFrom methods setOldClass setOldClass(c("tbl_df", "tbl", "data.frame"))

最后,这样就明确了tbl_df是类的定义,包括了属性和方法,而tibble是实例化的对象。通过对tibble函数的源代码分析,了解tibble本身的结构是怎么样的。那么再接下来,就是如何利用tibble来进行用于数据科学的数据处理过程。请继续阅读下一篇文章:R语言数据科学数据处理包dplyr。

转载请注明出处:

http://blog.fens.me/r-tibble/

R语言数据科学新类型tibble

原文链接:R语言数据科学新类型tibble,转载请注明来源!

0