笔记 3 R语言编程

3.1 R语言概述

  • R语言是S语言的一种方言
  • 1976年S是John Chambers等在贝尔实验室作为Fortran的扩展库开发出来的
  • 1988年用C语言重写 S3方法 白皮书
  • 1993年StatSci从贝尔实验室获得S语言的独家开发售卖许可
  • 1998年S4方法 绿皮书 之后S语言稳定 获得Association for Computing Machinery’s Software System Award
  • 2004年Insightful(原StatSci)从Lucent收购了S语言
  • 2006年Alcatel收购了Lucent成立Alcatel-Lucent
  • 2008年TIBCO收购Insightful 之前Insightful开发并售卖S-PLUS
  • 1991年Ross Ihaka与Robert GentlemanNew在Zealand开发了R
  • 1993年发布R第一份许可
  • 1995年R作为自由软件发放GUN许可
  • 1996年R邮件列表创立
  • 1997年R Core成立 控制R源码
  • 2000年R version 1.0.0 放出
  • 2013年R version 3.0.2 放出
  • R由CRAN掌控的base包与其他包组成
  • 其余参考R主页

3.2 获得帮助

help()
?command
# 提问给出以下信息
version
str(.Platform)

3.3 数据类型及基本运算

  • 所有数据都是对象 所有对象都有类型
  • 基本类型包括:字符“” 数字 整数L 复数(Re实部 Im虚部) 逻辑
  • 向量储存同一类型数据
  • list存储不同类型数据 [[*]]引用相应向量 unlist 可用做紧凑输出
  • 对象可以有属性attributes
  • 对象赋值符号为 <- 赋值同时展示加括号或直接输入对象名 可累加赋值 a <- b <- c
  • #表示注释 不执行
  • : 用来产生整数序列 也可以用seq生成
  • 向量用c产生
  • 空向量用vector()函数建立
  • 向量中类型不同的对象元素会被强制转换为同一类型 字符优先级最高 其次数字 其次逻辑(0 or 1) 也可以用来串联字符
  • 可使用as.*来强制转化数据类型
  • 对象可以用names命名
  • 变量名开头不能是数字和. 大小写敏感 下划线不要出现在名字里 分割用. 变量名中不能有空格
  • 保留字符
FALSE Inf NA NaN NULL TRUE break else for function if in next repeat while
  • 清空rm(list = ls())
  • 矩阵
  • 带有dimension属性的向量为矩阵 矩阵的生成次序为upper-left
  • matrix(1:6,nrow=2,ncol=3)表示建一个2行3列矩阵 从1到6 先列后行赋值 可用 byrow = T 来更改
  • 可用cdim赋值行和列数 这样可把一个向量转为一个矩阵 m<-1:6;dim(m)<-c(2,3)
  • 矩阵可以用rbindcbind生成
  • t对矩阵转置
  • 因子变量表示分类数据 用标签名区分 用level来命名排序 默认是字母排序 有些函数对顺序敏感可用 levels = c() 来命名 ( 例如低中高的排序 ) 数字表示 drop = T 表示显示截取数据的水平 nlevels给出个数
  • NaN表未定义或缺失值 NA表示无意义转换或缺失值 NaN可以是NA反之不可以 NA有数据类型 is.NaN与is.NA 可用来检验
  • 数据框
  • 特殊list 每个元素长度相等
  • 每一列类型相同 矩阵所有数据类型相同
  • 特殊属性row.names
  • 转为矩阵data.matrix
  • 变量名自动转化 可以不同
  • 因子变量保持为字符可以用 I data.frame(x,y,I(c))
  • 数组
  • 表示更高维度的数据
  • dim() = c(x,y,z) 三维数组表示一组数
  • dimnames 给数组命名
  • 数组调用如果只有一行 需要drop = F 否则 不会按照数组分类
  • ts 产生时间序列对象
  • .Last.value 引用前一个数值
  • 取整数 用round(x,n) n表示保留几位小数
  • 截取整数 trunc
  • 开平方 sqrt
  • 绝对值 abs
  • 指数函数 exp
  • 自然对数函数 log
  • 以 10 为底的对数函数 log10
  • 三角函数 sin cos tan asin acos atan
  • 常用的逻辑运算符有: 大于 > 小于 < 等于 == 小于或等于 <= 大于或等于 >=&!|
  • 判断向量x中是否与y中元素相等 x %in% y 结果返回逻辑值
  • sum 求和 prod 求连乘
  • range 给极值范围
  • duplicated 给出有重复的值
  • unique 给出无重复的值
  • 向量操作 union 并集 intersect 交集 setdiff 除了交集的部分
  • rep 用向量循环生成向量
x <- 1:4 # puts c(1,2,3,4) into x
i <- rep(2, 4) # puts c(2,2,2,2) into i
y <- rep(x, 2) # puts c(1,2,3,4,1,2,3,4) into y
z <- rep(x, i) # puts c(1,1,2,2,3,3,4,4) into z
w <- rep(x, x) # puts c(1,2,2,3,3,3,4,4,4,4) into w
  • 整型变量后面加上L x<-10L
  • Inf代表1/0 同样1/Inf运算结果为0

3.4 环境/文件操作

  • getwd() setwd() 设置工作目录
  • ls() 列举环境中bianliang
  • list.files()dir() 列举当前目录下文件
  • args() 列举函数默认变量
  • dir.create() 创建文件目录 加上recursive=T可创建多级目录
  • file.create() 创建文件
  • file.exists() 检查文件是否存在
  • file.info() 检查文件信息
  • file.rename() 文件重命名
  • file.copy() 文件复制
  • file.path() 文件路径 多个文件组成多级路径
  • unlink() 删除文件

3.5 截取数据

  • []截取数据
  • 可以用[x,y]提取特定数值
  • [-1,-2]可剔除第一行第二列
  • [[]]用来从list或者frame里提取元素 类型固定 可提取序列x[[1]][[3]] 可部分匹配 exact=FALSE
  • $用名字提取元素 可部分匹配
  • 提取矩阵时默认只能提取向量 但可以提取1*1矩阵x[1,2,drop=FALSE]
  • 先用is.NA()提取 用!排除 缺失值可用is.element(x,y)来处理很多表示NA值的数字 返回x %in% y的逻辑值
  • complete.cases()提取有效数据用[]提取可用数据
  • head(x,n) n表示从头截取多少行
  • tail(x,n) n表示从尾截取多少行
  • subset(x,f) x表示数据 f表示表达式
  • 条件筛选中获得一个变量多个数值的数据使用 [is.element(x,c(' ',' ',' ')),] 或者[x%in%c(' ',' ',' '),] 使用x == c( ' ' , ' ' , ' ' ) 会报错 循环查找三个变量
  • x!='t' 可能会把空白值输入 应该使用is.element(x,'t')
  • ifelse(con,yes,no) 利用条件筛选 返回yes 或者no 的值
  • 支持正则表达式

3.6 读取数据

  • read.table read.csv 读取表格 反之write.table
  • readLines 读取文本行 反之writeLines
  • source 读取R代码 反之dump
  • dget 读取多个R代码 反之dput
  • load 读取保存的工作区 反之save
  • unserialize 读取二进制R对象 反之serialize
  • ?read.table
  • 大数据读取提速
  • 计算内存
  • comment.char = "" 不扫描注释
  • 设定nrows
  • 设定colClasses
initial <- read.table("datatable.txt", nrows = 100)
classes <- sapply(initial, class)
tabAll <- read.table("datatable.txt",
                     colClasses = classes)
  • 使用connectionsfile等保存外部文件指向

3.7 控制结构

  • if else 条件
if(<condition>) {
        ## do something
} else {
        ## do something else
}
if(<condition1>) {
        ## do something
} else if(<condition2>)  {
        ## do something different
} else {
        ## do something different
}
  • `for‵ 执行固定次数的循环 嵌套不超过2层
for(i in 1:10) {
        print(i)
}
  • while 条件为真执行循环 条件从左到右执行
count <- 0
while(count < 10) {
        print(count)
        count <- count + 1
}
  • repeat 执行无限循环 配合break 中断并跳出循环
  • next 跳出当前循环继续执行
for(i in 1:100) {
        if(i <= 20) {
                ## Skip the first 20 iterations
                next 
        }
        ## Do something here
}
  • return 退出函数
  • 避免使用无限循环 可用apply替代

3.8 函数

f <- function(<arguments>) {
        ## Do something interesting
}
  • 函数中参数默认值可用formals()显示
  • 参数匹配
  • 先检查命名参数
  • 然后检查部分匹配
  • 最后检查位置匹配
  • 定义函数时可以定义默认值或者设为NULL
  • 懒惰执行:只执行需要执行的语句
  • ... 向其他函数传参 之后参数不可部分匹配

3.9 编程标准

  • 使用文本文档与文本编辑器
  • 使用缩进
  • 限制代码行宽 80为宜
  • 限制单个函数长度

3.10 范围规则

  • 自由变量采用静态搜索
  • 环境是由数值符号对组成 每个环境都有母环境
  • 函数与环境组成环境闭包
  • 首先从函数环境中寻找变量
  • 之后搜索母环境
  • 最高层为工作区
  • 之后按搜寻列表从扩展包中寻找变量
  • 最后为空环境 之后报错
  • 可以函数内定义函数
  • S都存在工作区 函数定义一致 R存在内存 可根据需要调用函数环境

3.11 向量化操作

  • 向量操作针对元素
  • 矩阵操作也针对元素 %*% 表示矩阵操作

3.12 日期与时间

  • 日期以data类型存储
  • 时间以POSIXctPOSIXlt 类型存储
  • 数字上是从1970-01-01以来的天数或秒数
  • POSIXct以整数存储时间
  • POSIXlt以年月日时分秒等信息存储时间
  • strptime as.Date as.POSIXlt as.POSIXct用来更改字符为时间

3.13 循环

3.13.1 lapply

  • 对列表对象元素应用函数
  • 可配合匿名函数使用
x <- list(a = 1:5, b = rnorm(10))
lapply(x, mean)
## $a
## [1] 3
## 
## $b
## [1] 0.0412
x <- 1:4
lapply(x, runif, min = 0, max = 10)
## [[1]]
## [1] 3.38
## 
## [[2]]
## [1] 0.99 2.56
## 
## [[3]]
## [1] 6.70 3.73 2.75
## 
## [[4]]
## [1] 7.24 3.12 5.71 4.85
x <- list(a = matrix(1:4, 2, 2), b = matrix(1:6, 3, 2))
lapply(x, function(elt) elt[,1])
## $a
## [1] 1 2
## 
## $b
## [1] 1 2 3

3.13.2 sapply

  • lapply的精简版
  • 如果结果是单元素列表 转化为向量
  • 如果结果是等长向量 转化为矩阵
  • 否则输出依旧为列表
x <- list(a = 1:4, b = rnorm(10), c = rnorm(20, 1), d = rnorm(100, 5))
sapply(x, mean)
##      a      b      c      d 
##  2.500 -0.154  0.664  5.171

3.13.3 vapply

  • 类似lapply可用更复杂函数 返回矩阵

3.13.4 replicate

  • 用于将函数循环使用 如返回随机矩阵

3.13.5 rapply

  • how来调整输出方法 如选取某列表中类型数据进行迭代

3.13.6 apply

  • 数组边际函数 常用于矩阵的行列处理
  • 行为1,列为2
  • 可用rowSums rowMeans colSums colMeans 来替代 大数据量更快
x <- matrix(rnorm(50), 10, 5)
apply(x, 1, quantile, probs = c(0.25, 0.75))
##       [,1]   [,2]   [,3]  [,4]    [,5]  [,6]    [,7]   [,8] [,9]  [,10]
## 25% -0.151 -1.026 -0.592 0.572 -0.0448 0.212 -0.7386 -1.142 1.02 -1.196
## 75%  0.334 -0.294  0.739 1.109  0.4642 1.269  0.0311  0.369 1.12 -0.662
a <- array(rnorm(2 * 2 * 10), c(2, 2, 10))
apply(a, c(1, 2), mean)
##         [,1]   [,2]
## [1,]  0.2879 -0.722
## [2,] -0.0313  0.307

3.13.7 tapply

  • 对数据子集(因子变量区分)向量应用函数
x <- c(rnorm(10), runif(10), rnorm(10, 1))
f <- gl(3, 10)
tapply(x, f, mean)
##     1     2     3 
## 0.237 0.541 1.392

3.13.8 by

  • 对数据按照因子变量应用函数 类似tapply
  • 按照某个分类变量a分类求均值 by(x[,-a],a,mean)

3.13.9 split

  • 将数据按因子分割为列表 常配合lapply使用
  • 类似tapply
  • 可用来生成分组 用drop来删除空分组
x <- c(rnorm(10), runif(10), rnorm(10, 1))
f <- gl(3, 10)
lapply(split(x, f), mean)
## $`1`
## [1] -0.27
## 
## $`2`
## [1] 0.4
## 
## $`3`
## [1] 1.27
x <- rnorm(10)
f1 <- gl(2, 5)
f2 <- gl(5, 2)
str(split(x, list(f1, f2), drop = TRUE))
## List of 6
##  $ 1.1: num [1:2] 1.4 -1.78
##  $ 1.2: num [1:2] -0.466 -1.052
##  $ 1.3: num -0.879
##  $ 2.3: num 0.347
##  $ 2.4: num [1:2] 0.347 0.562
##  $ 2.5: num [1:2] 1.352 -0.385

3.13.10 mapply

  • 多变量版apply 从多个参数范围取值 并用函数得到结果
noise <- function(n, mean, sd) {
  rnorm(n, mean, sd)
}
mapply(noise, 1:5, 1:5, 2)
## [[1]]
## [1] 0.583
## 
## [[2]]
## [1]  4.830 -0.594
## 
## [[3]]
## [1] 5.04 1.91 6.05
## 
## [[4]]
## [1] 6.70 8.37 1.54 2.93
## 
## [[5]]
## [1] 6.94 7.13 8.67 7.12 4.71
#等同于如下循环

#list(noise(1, 1, 2), noise(2, 2, 2),
#    noise(3, 3, 2), noise(4, 4, 2),
#    noise(5, 5, 2))

3.13.11 eapply

  • 对环境变量应用函数 用于包

3.14 模拟

  • 在某分布下产生随机数
  • d 分布概率密度
  • r 分布随机数
  • p 分布累计概率
  • q 分布分位数
dnorm(x, mean = 0, sd = 1, log = FALSE)
pnorm(q, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)
qnorm(p, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)
rnorm(n, mean = 0, sd = 1)
  • set.seed保证重现性
  • sample对数据采样

3.15 调试

  • 三种提示 message warning error 只有error致命
  • 关注重现性
  • 调试工具 traceback debug browser trace recover
  • 三思而行

3.16 分析代码

  • 先设计 后优化
  • system.time 计算代码运行时间 返回对象类型proc_time
  • ‵user time` 执行代码用时
  • system time CPU时间
  • elapsed time 实际用时
  • 在多核或并行条件下实际用时可以短于执行代码用时
  • 明确知道耗时较长的函数时使用
  • Rprof R代码要支持分析函数
  • summaryRprof可使结果易读
  • 不要与system.time混用
  • 0.02s记录一次执行函数
  • by.total 记录单个函数用时
  • by.self 记录函数执行时被调用函数用时