Advanced R(1)——basic

ZhiYuan Wang

2018/11/08

library(magrittr)

第2章 数据结构

2.1 向量

两种向量:原子向量,列表,三个共同属性:

  • typeof()
  • length()
  • attributes() 附加任意元数据
a <- 1:3
typeof(a)
## [1] "integer"
length(a)
## [1] 3
attributes(a)
## NULL
l <- list(a)
typeof(l)
## [1] "list"
length(l)
## [1] 1
attributes(l)
## NULL

2.1.1 原子向量

四种常见类型:

  • 逻辑型
  • 整型
  • 双精度型
  • 字符型

原子向量总是被展开

c(1,c(2,c(3,4)))
## [1] 1 2 3 4

给定一个向量,使用typeof()来确定类型,或使用is.character()查看是否为指定类型。

is.numeric判断向量的数值型

强制转换

当把不同类型的数据结合成一个向量时,强制转换为最具灵活性的数据类型。

灵活性由低到高:逻辑,整型,双精度,字符型

2.1.2 列表

列表中的元素可以是任意的,使用列表来构造更复杂的数据结构。

2.2 属性

所有对象可以通过任意附加的属性来存储对象的元数据

  • 可以通过attr()单独访问对象的每一个属性;
  • 也可以通过attributes()同时访问所有的属性;
a <- 1:10
attr(a, "my_attri") <- "This is a vector"
attr(a, "my_attri")
## [1] "This is a vector"

3个最重要的属性:

  • name,使用names()访问
  • dimension,使用dim()访问
  • class,使用class()访问

元素的命名:唯一性命名是非常有用的。

names(a) <- NULL

来去掉元素的名称

2.1.1 因子

因子构建在整型向量的基础上,levels()定义因子中所有可能的取值

使用因子而不是字符向量可以知道没有观测的可能取值

特殊方式编码缺失值

x <- read.csv("···",na.strings=".")

可以通过stringsAsFactors=FALSE设置读取过程不转换为因子,但不建议修改全局设置(会引起依赖包产生不可预测行为)。

因子型本质上是整型而不是字符串

2.3 矩阵和数组

可以通过将原子向量添加dim()属性将其变为矩阵

a <- 1:20
dim(a) <- c(4,5)
a
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    5    9   13   17
## [2,]    2    6   10   14   18
## [3,]    3    7   11   15   19
## [4,]    4    8   12   16   20
rownames(a) <- LETTERS[1:4]
colnames(a) <- letters[1:5]
a
##   a b  c  d  e
## A 1 5  9 13 17
## B 2 6 10 14 18
## C 3 7 11 15 19
## D 4 8 12 16 20
attributes(a)
## $dim
## [1] 4 5
## 
## $dimnames
## $dimnames[[1]]
## [1] "A" "B" "C" "D"
## 
## $dimnames[[2]]
## [1] "a" "b" "c" "d" "e"

可以使用t()对矩阵转置

列表矩阵

l <- list(1:3,"a",T,1.0)
l
## [[1]]
## [1] 1 2 3
## 
## [[2]]
## [1] "a"
## 
## [[3]]
## [1] TRUE
## 
## [[4]]
## [1] 1
dim(l) <- c(2,2)
l
##      [,1]      [,2]
## [1,] Integer,3 TRUE
## [2,] "a"       1

列表矩阵用于按网状结构存储数据。

2.4 数据框(矩阵+列表)

2.4.1 构建

使用data.frame()构建,默认将字符串转换成因子,使用stringAsFactors=F来禁止。

2.4.2 类型判断

x <- 1:6
y <- letters[1:6]
df <- data.frame(x,y)
typeof(df)
## [1] "list"
class(df)
## [1] "data.frame"
is.data.frame(df)
## [1] TRUE

2.4.3 合并

cbind,rbind

列向合并时,两数据框行数保持一致,行名可忽略;

行向合并时,列名和列数都必须一致。

特殊列

对列表使用data.frame,会尝试将每个元素放入自己的列中。

df <- data.frame(x = 1:3)
df$y <- list(1:2,1:3,1:4)
df
##   x          y
## 1 1       1, 2
## 2 2    1, 2, 3
## 3 3 1, 2, 3, 4

第3章 子集选取

3.1 数据类型

3.1.1 原子向量

空索引返回原始向量。

a <- 1:10
a[]
##  [1]  1  2  3  4  5  6  7  8  9 10

0索引返回长度为0的向量,在创建测试数据时有用

a[0]
## integer(0)

3.1.2 列表

  • []总是返回列表
  • [[]]和$将列表中的元素取出

3.1.3 矩阵和数组

dim(a) <- c(2,5)
a
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    3    5    7    9
## [2,]    2    4    6    8   10
a[2,3]
## [1] 6

3.1.4 数据框

如果仅仅使用一个单一的向量,数据框的行为像列表;如果使用两个向量,数据框的行为像矩阵。列表不回退化,矩阵在一维时退化成原子向量。

df <- data.frame(x=1:3,y=3:1,z=letters[1:3])
str(df["x"])
## 'data.frame':    3 obs. of  1 variable:
##  $ x: int  1 2 3
str(df[,"x"])
##  int [1:3] 1 2 3

3.2 子集选取运算符

3.2.1 简化与保留

最后的子集是不是保持着原来的数据结构。

  • 简化:有利于交互式分析;
  • 保持:有利于编程;drop=F保持。输入与输出相同

简化的类型:

  • 原子向量:去除名字;
  • 列表:返回列表元素,而不是列表;
  • 因子:扔掉所有不用的水平;
  • 矩阵或数组:抛弃所有长度为1的维度;
  • 数据框:如果输出只有一列,返回一个向量而不是数据框
df <- data.frame(a=1:2,b=1:2)
str(df[1])
## 'data.frame':    2 obs. of  1 variable:
##  $ a: int  1 2
str(df[[1]])
##  int [1:2] 1 2
str(df[,"a",drop=F])
## 'data.frame':    2 obs. of  1 variable:
##  $ a: int  1 2
str(df[,"a"])
##  int [1:2] 1 2

3.2.2 $运算符

$与[[]]的两个区别:

  • $后不能跟存储列名的变量;
  • $部分匹配,[[]]全部匹配;

3.3 子集选取与赋值

子集选取时使用空索引会保持原有对象类和数据结构

mtcars[] <- lapply(mtcars, as.integer)
str(mtcars)
## 'data.frame':    32 obs. of  11 variables:
##  $ mpg : int  21 21 22 21 18 18 14 24 22 19 ...
##  $ cyl : int  6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: int  160 160 108 258 360 225 360 146 140 167 ...
##  $ hp  : int  110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: int  3 3 3 3 3 2 3 3 3 3 ...
##  $ wt  : int  2 2 2 3 3 3 3 3 3 3 ...
##  $ qsec: int  16 17 18 19 17 20 15 20 22 18 ...
##  $ vs  : int  0 0 1 1 0 1 0 1 1 1 ...
##  $ am  : int  1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: int  4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: int  4 4 1 1 2 1 4 2 2 4 ...
mtcars <- lapply(mtcars, as.integer)
str(mtcars)
## List of 11
##  $ mpg : int [1:32] 21 21 22 21 18 18 14 24 22 19 ...
##  $ cyl : int [1:32] 6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: int [1:32] 160 160 108 258 360 225 360 146 140 167 ...
##  $ hp  : int [1:32] 110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: int [1:32] 3 3 3 3 3 2 3 3 3 3 ...
##  $ wt  : int [1:32] 2 2 2 3 3 3 3 3 3 3 ...
##  $ qsec: int [1:32] 16 17 18 19 17 20 15 20 22 18 ...
##  $ vs  : int [1:32] 0 0 1 1 0 1 0 1 1 1 ...
##  $ am  : int [1:32] 1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: int [1:32] 4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: int [1:32] 4 4 1 1 2 1 4 2 2 4 ...

3.4 应用

3.4.1 查询表

x <- c("m","f","u","f","f","m","m")
lookup <- c(m="Male",f="Female",u=NA)
lookup[x]
##        m        f        u        f        f        m        m 
##   "Male" "Female"       NA "Female" "Female"   "Male"   "Male"
unname(lookup[x])
## [1] "Male"   "Female" NA       "Female" "Female" "Male"   "Male"

3.4.2 人工比对与合并

grades <- c(1,2,2,3,1)
info <- data.frame(
  grade = 3:1,
  desc = c("Excellent","Good","Poor"),
  fail = c(F,F,T)
)
info
##   grade      desc  fail
## 1     3 Excellent FALSE
## 2     2      Good FALSE
## 3     1      Poor  TRUE
grades
## [1] 1 2 2 3 1
id <- match(grades,info$grade)
id
## [1] 3 2 2 1 3
info[id,]
##     grade      desc  fail
## 3       1      Poor  TRUE
## 2       2      Good FALSE
## 2.1     2      Good FALSE
## 1       3 Excellent FALSE
## 3.1     1      Poor  TRUE
rownames(info) <- info$grade
info[as.character(grades),]
##     grade      desc  fail
## 1       1      Poor  TRUE
## 2       2      Good FALSE
## 2.1     2      Good FALSE
## 3       3 Excellent FALSE
## 1.1     1      Poor  TRUE

3.4.3 随机样本(自助法)

df <- data.frame(x=rep(1:3,each=2),y=6:1,z=letters[1:6])
df
##   x y z
## 1 1 6 a
## 2 1 5 b
## 3 2 4 c
## 4 2 3 d
## 5 3 2 e
## 6 3 1 f
df[sample(nrow(df)),]
##   x y z
## 2 1 5 b
## 5 3 2 e
## 1 1 6 a
## 4 2 3 d
## 3 2 4 c
## 6 3 1 f
df[sample(nrow(df),3),]
##   x y z
## 3 2 4 c
## 6 3 1 f
## 5 3 2 e
df[sample(nrow(df),6,rep=T),]
##     x y z
## 1   1 6 a
## 3   2 4 c
## 4   2 3 d
## 5   3 2 e
## 3.1 2 4 c
## 2   1 5 b

3.4.4 排序

df2 <- df[sample(nrow(df)),3:1]
df2
##   z y x
## 3 c 4 2
## 5 e 2 3
## 4 d 3 2
## 2 b 5 1
## 1 a 6 1
## 6 f 1 3
df2[order(df2$x),]
##   z y x
## 2 b 5 1
## 1 a 6 1
## 3 c 4 2
## 4 d 3 2
## 5 e 2 3
## 6 f 1 3
df2[,order(names(df2))]
##   x y z
## 3 2 4 c
## 5 3 2 e
## 4 2 3 d
## 2 1 5 b
## 1 1 6 a
## 6 3 1 f

3.4.5 展开重复记录

df <- data.frame(x=c(2,4,1),y=c(9,11,6),n=c(3,5,1))
df
##   x  y n
## 1 2  9 3
## 2 4 11 5
## 3 1  6 1
rep(1:nrow(df),df$n)
## [1] 1 1 1 2 2 2 2 2 3
df[rep(1:nrow(df),df$n),]
##     x  y n
## 1   2  9 3
## 1.1 2  9 3
## 1.2 2  9 3
## 2   4 11 5
## 2.1 4 11 5
## 2.2 4 11 5
## 2.3 4 11 5
## 2.4 4 11 5
## 3   1  6 1

3.4.6 剔除数据框中的某些列

把列设为NULL

3.4.7 根据条件选取行

mtcars <- data.frame(mtcars)
mtcars[mtcars$gear==5,]
##    mpg cyl disp  hp drat wt qsec vs am gear carb
## 27  26   4  120  91    4  2   16  0  1    5    2
## 28  30   4   95 113    3  1   16  1  1    5    2
## 29  15   8  351 264    4  3   14  0  1    5    4
## 30  19   6  145 175    3  2   15  0  1    5    6
## 31  15   8  301 335    3  3   14  0  1    5    8
mtcars[mtcars$gear==5 & mtcars$cyl==4,]
##    mpg cyl disp  hp drat wt qsec vs am gear carb
## 27  26   4  120  91    4  2   16  0  1    5    2
## 28  30   4   95 113    3  1   16  1  1    5    2

3.4.8 布尔代数与集合

which将布尔转化为整数

x <- sample(10)<4
which(x)
## [1]  3  4 10

除非选取第一个TRUE值,否则不要用which将逻辑转为整数再选取

第6章 函数

函数本身就是对象

6.1 函数的组成部分

所有的R函数包含3个部分:

  1. body() 函数的内部代码;
  2. formals() 控制如何调用函数的参数列表;
  3. environment() 函数变量位置的“地图”;

6.1.1 原函数

.Primitive()直接调用C代码,不包含R代码

class(sum)
## [1] "function"
is.primitive(sum)
## [1] TRUE
objs <- mget(ls("package:base"),inherits=T)
funs <- Filter(is.function,objs)

哪个函数有最多的参数

funcformalslen <- lapply(funs, formals) %>% sapply(length)
which(funcformalslen==max(funcformalslen))
## scan 
##  941

多少个基础函数没有参数

sum(funcformalslen==0)
## [1] 226

找到所有的原函数

lapply(funs, is.primitive) %>% as.logical() %>% sum()
## [1] 183

6.2 词法作用域

  • 名字屏蔽:先在最内层寻找,逐层向外寻找;
  • 函数与变量:避免函数与变量名字相同;
  • 重新开始:函数在每次调用时创建新环境,运行结束后,内部变量释放;
  • 动态查找:当函数运行时,R才开始查找,创建时不查找。

注意:全局环境的变量对函数运行结果产生影响。

6.3 每个运算都是一次函数调用

  • Everything that exists is an object.
  • Everything that happens is a function all.

重音符可以引用预留的函数,将中辍运算符变为标准的函数调用格式。

`+`(1,2)
## [1] 3
`for`(i,1:2,print(i))
## [1] 1
## [1] 2
x <- 5:10
`[`(x,3)
## [1] 7
`{`(print(1),print(2),print(3))
## [1] 1
## [1] 2
## [1] 3

match.fun()查找给定名字(字符串)的函数对象

match.fun("sum")
## function (..., na.rm = FALSE)  .Primitive("sum")
sapply(1:5, `+`,3)
## [1] 4 5 6 7 8
sapply(1:5, "+",3)
## [1] 4 5 6 7 8
x <- list(1:3,4:9,10:12)
sapply(x,"[",2)
## [1]  2  5 11

R中发生的一切都是函数调用

6.4 函数参数

6.4.1 函数调用

实参映射到形参

通常只对第一个或前两个参数使用位置匹配

6.4.2 使用参数列表调用函数

args <- list(1:10,na.rm=T)
args
## [[1]]
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## $na.rm
## [1] TRUE
do.call(mean,list(1:10,na.rm=T))
## [1] 5.5
mean(1:10,na.rm=T)
## [1] 5.5

6.4.3 默认参数和缺失参数

所有参数的默认值可以通过其他参数来定义,甚至可以用函数内部创建的变量来定义。

可以使用missing()函数来确定一个参数是否被设置了

将默认值设置为NULL,然后使用函数is.null()来检查这个参数是否被设置了。

6.4.4 惰性求值

参数只在实际被用到时求值

6.4.5 …参数

这个参数将与所有没有匹配的参数进行匹配,并很容易地传递给其他函数。

如果想手机参数来调用其他函数,又不想提前设定参数名时,这个参数很有用。

经常与S3泛型函数联合使用以便使单个方法更加灵活。

可使用list(,,,)来捕获

f <- function(...){
  names(list(...))
}
f(a=1,b=2)
## [1] "a" "b"

使用…的代价是任何拼写错误不会产生错误警告

6.5 特殊调用

6.5.1 中辍运算符

所有用户创建的中辍函数必须以%开头,以%结尾;

R里面预定义的中辍函数: - %% - %*% - %/% - %in% - %o% - %x%

`%+%` <- function(a,b) paste(a,b,sep="")
"new" %+% "string"
## [1] "newstring"
`%+%`("new","string")
## [1] "newstring"

6.5.2 替换函数

替换函数看上就就像对参数进行原地修改,通常只有两个参数x和value,必须返回被修改对象。

`second<-` <- function(x,value){
  x[2] <- value
  x
}
x <- 1:10
second(x) <- 5
x
##  [1]  1  5  3  4  5  6  7  8  9 10

如果想提供附加参数,可以放在x和value之间

`modify<-` <- function(x,position,value){
  x[position] <- value
  x
}
modify(x,1) <- 10
x
##  [1] 10  5  3  4  5  6  7  8  9 10

经常把替换与子集选取一起使用

x <- c(a=1,b=2,c=3)
names(x)
## [1] "a" "b" "c"
names(x)[2] <- "two"
names(x)
## [1] "a"   "two" "c"

6.6 返回值

一个函数中最后一个被计算的表达式成为函数的返回值

可以返回一个包含任意数量对象的列表

实参传递给形参后,实参失效。复制后修改,对函数的参数进行修改不会改变参数的原始值。

当函数退出时可以使用on.exit()来触发其他事件。