#高级编程
#R是一种面向对象的,实用的数组编程语言
#对象的名称由大小写字母,数字0~9,句号和下划线组成
#名称是区分大小写的,而且不能以数字开头,句号被视为没有特殊含义的简单字符
#所有的对象在程序执行时都存储在RAM中,这对大规模数据分析有显著的影响
#数据类型
#原子向量 atomic vector
#原子向量是包含单个数据类型(逻辑类型,实数,复数,字符串或原始类型)的数组
#每一个向量均为一维原子向量
#R中没有标量型数据,标量是具有单一元素的原子向量,所以k<-2等价于k <- c(2)
#范例 原子向量
x <- c(1,2,3,4,5,6,7,8)
print(x) #输出x
#每一个对象都有属性:元信息描述对象的特性
#attributes(),罗列出对象的所有属性
#attr(),支持对象属性的修改
#允许你创建任意属性并将其与对象相关联
#仍有很多函数支持设置属性,包括dim(),dimnames(),names(),(),(),class(),tsp()
#class(),支持对象类的读取和设置
class(x) #返回"numeric",原始为一维原子向量
attr(x,"dim") <- c(2,4) #对象x增加dim属性
class(x) #返回"matrix",修改为二维原子向量,矩阵
print(x) #输出对象x
attributes(x) #输出对象x的所有属性,以及对应的属性值
attr(x,"dimnames") <- list(c("A1","A2"),
c("B1","B2","B3","B4")) #对象x增加行名,列名
print(x) #输出对象x
attr(x,"dim") <- NULL #对象x去除dim属性的原子向量
print(x) #输出对象x,还原成最开始的一维原子向量
#泛型向量或列表
#列表是原子向量和/或其他列表的集合,列表是递归的,因为它们还可以包含其他列表
#原子向量的集合
#数据框是一种特殊的列表,每个向量代表数据框中的一列(对应一个变量),每个原子变量都有相同的长度
#范例 泛型向量或列表
class(iris) #返回""
attributes(iris)
#属性names,变量名的字符串向量
#属性,识别单个植物(行)的数字向量
#属性class,识别的类型
head(iris) #默认返回前6行
#等价于将attributes的names下的所有值,全部展开
#对于列,将每个列展开,输出所有值
#对于行,attr(,""),展开,输出所有行号
unclass(iris)
unclass(iris)$Species #加$符号的支持单独访问
(1234)
fit <- kmeans(iris[1:4],3)
#返回对象所有属性
#$names
#[1] "cluster" "centers" "totss" "withinss" "" "betweenss"
#[7] "size" "iter" "ifault"
#$class
#[1] "kmeans"
attributes(fit)
#names(),提供这些成分的名字
names(fit)
#unclass(),用来检查对象的内容,并没有实际修改源对象的类
#等价于将$names中每一个对象,按照全值,展开
unclass(fit)
#返回对象attribute对应name下每个列对象的类别,即每个列的类类型
sapply(fit,class)
str(fit)
#索引
#提取元素可以使用object[index],其中object是向量,index是一个整数向量
#如果原子向量中的元素已经被命名,index也考科一是这些名字中的字符串向量
#注意,R中的索引从1开始,而不是像其他语言一样从0开始
#范例 没有名字命名的原子变量元素
x <- c(20,30,40)
x[3] #返回单值,40,第三个变量
x[c(2,3)] #返回多值,30,40,第二个以及第三个变量
#范例 有名字命名的原子变量元素
x <- c(A=20,B=30,C=40)
x[c(2,3)] #位置索引,返回多值,第二个及第三个变量名及值
x[c("B","C")] #命名索引,返回多值,第二及第三个变量名及值
#范例 fit对象中索引访问
#$names
#[1] "cluster" "centers" "totss" "withinss" "" "betweenss"
#[7] "size" "iter" "ifault"
#centers,对应位置索引2
#size,对应位置索引7
fit[c(2,7)]
fit[2]
class(fit[2]) #返回list
#等价于unclass将所有names中指定对象centers,size展开所有值,显示
#注意,返回的是以列表形式出现的成分
fit[[2]] #将位置索引为2的列表中的值全部取出
fit$centers #等价,取值
class(fit[[2]]) #返回matirx
class(fit$centers) #返回matrix
fit[[2]][1,] #返回矩阵,第一行
#范例 画出k均值聚类分析的中心
(1234)
fit <- kmeans(iris[1:4],3)
means <- fit$centers#提取聚类中心矩阵,行是类,列是变量的均值
str(means)
#chr [1:3] "1" "2" "3" ----对应行名
#chr [1:4] "" "" "" ""-----对应列名
library(reshape2)
#将宽表拉伸成长表,基于类别,将每一行基于变量列个数拆分成对应的行数
#原始行名保留,作为新的变量
#原始列名保留,做为新变量的值
dfm <- melt(means)
#第一列,对应类别名,第二列,对应变量名,第三列,对应变量值
names(dfm) <- c("Cluster","Measurement","Centimeters")
#将原始类别从数值列转换成因子列
dfm$Cluster <- factor(dfm$Cluster)
str(dfm) #查看对象整体结构
head(dfm) #查看前六行
library(ggplot2)
ggplot(data=dfm,
aes(x=Measurement,y=Centimeters,group=Cluster))+
geom_point(size=3,aes(shape=Cluster,color=Cluster))+ #散点图,基于Cluster,区分形状和颜色
geom_line(size=1,aes(color=Cluster))+ #折现图,基于Cluster,画不同颜色的线
ggtitle("Profiles for Iris Clusters") #等价于labs增加标题
#控制结构
#for循环
#var 一个变量名
#seq 计算向量的表达式
#var直到函数退出才退出
#for(var in seq){
#statements
#}
for(i in 1:5){
print(i)
}
#单语句时,可以省略大括号,两种表达式等价
#序列递增
#退出时i=5
for(i in 1:5) print(1:i)
for(i in 5:1) print(1:i) #序列递减,退出时i=1
#if和else
#if函数允许你有条件的执行语句
#运行的条件是一元逻辑向量(TRUE,或FALSE),并且不能有缺失值
#else部分是可选的
#如果仅有一个语句,花括号也是可以省略的
#if(condition){
# statements
#}else{
# statements
#}
if(interactive()) {
x <- c(1,2,3,4,5,6,7,8) #已知x值
y=sqrt(x) #通过x,y之间的函数关系,得到y值
plot(x,y,type="l") #默认为点p,画出函数关系图
} else {
png("")
plot(x,y)
}
#ifelse()函数是if()的简化版本
#ifelse(test,yes,no)
#test 是已强制为逻辑模式的对象
#yes 返回test元素为真时的值
#no 返回test元素为假时的值
#范例
#标记p<0.05水平下的显著性检验
#Significant,重要的
pvalues <- c(0.0867,0.0018,0.0054,0.1572,0.0183,0.5386)
results <- ifelse(pvalues < 0.05,"Significant","Not Significant") #输入向量,返回顺次比较结果的向量
results #向量版,更快更有效
#循环
pvalues <- c(0.0867,0.0018,0.0054,0.1572,0.0183,0.5386)
results <- vector(mode="character",length=length(pvalues)) #定义指定字符型,长度的结果向量
for (i in 1:length(pvalues)){
if(pvalues[i] <0.05) results[i] <- "Significant"
else results[i] <- "Not Significant"
}
results #显示循环版
#仍然包括其他的控制结构
#while(),repeat(),switch()等等
#创建函数
#如果函数中存在多个参数,则参数之间用逗号隔开
#functionname <- function(parameters){
# statements
# return(value)
#}
#范例
#参数是可选的,假如没有任何参数值被传递也必须使用圆括号
#return也是可选的,返回函数产生的对象,如果缺失,函数中最后一条语句的结果也会被返回
#args(),用来观测参数的名字和默认值,用于交互式观测
f <- function(x,y,z=1){
result <- x+(2*y)+(3*z)
return(result)
}#自定义函数
args(f)
#结果解读
#function (x, y, z = 1) #三个变量,x,y,z,并且仅有z=1存在默认值
#NULL #在非函数的情况下为NULL
f(2,3,4) #通过位置传递,x=2,y=3,z=4
f(2,3) #通过位置传递,x=2,y=3,z=1(默认值)
f(x=2,y=3) #通过关键字传递,x=2,y=3,z=1(默认值)
f(z=4,y=2,3) #通过关键字传递,y=2,z=4,仅剩下x未指定且剩余一个值,所以x=3
#对象范围
#全局对象VS局部对象
#在函数之外创建的对象是全局的,也适用于函数内部,
#在函数之内创建的对象都是局部的,仅仅适用于函数内部
#局部对象在函数执行后被丢弃,只有那些通过return函数,
#或者使用算子<<-分配传回的对象在函数执行之后可以继续使用
#全局对象在函数之内可被访问(即可读)但是不会改变,除非使用<<-算子
#对象可以通过参数传递到函数中,但是不会被函数改变
#传递的是对象的副本而不是变量本身
x <- 2
y <- 3
z <- 4
r <- 5
f <- function(w){
z <- 2
#x的一个副本被传递到函数f()中,初始的x并未改变
#y通过访问全局变量得到
x <- w*y*z
r <<- x #必须使用<<-才可以修改全局变量
return(x)
}
args(f)
#function (w)
# NULL
f(x)
print(c("x=",x,"y=",y,"z=",z,"r=",r)) #除了r,其余全局变量均未被修改
#环境空间的层次结构
#环境空间是R语言中关于计算机方面的底层设计,主要用于R语言是环境加载器。
#通过环境空间,封装了加载器的运行过程,让使用者在不知道底层细节的情况下,
#可以任意加载使用到的第三方的R语言程序包。
#R语言的环境是一种有层次关系的结构,每个环境都有上一层环境,直到最顶层的空环境。
#R语言中有5种环境的定义 全局环境,内部环境,父环境,空环境 和 包环境。
#全局环境,当前环境,即用户环境,是用户程序运行的环境空间。
#当前环境,等价于全局环境
environment()
#返回environment: R_GlobalEnv>
#内部环境
#内部环境,构造出来的环境
#可以是通过 ()函数显示创建的环境空间,也可以是匿名的环境空间。
e1 <- ()
e1
#返回environment: 0x3e28948>
# 父环境
#父环境,即上一层环境,环境空间的上一层。
(e1)
#返回environment: R_GlobalEnv>
# 空环境
#空环境,即顶层环境,没有父环境空间。
emptyenv()
#返回environment: R_EmptyEnv>
# 包环境
#包环境,包封装的环境空间。
baseenv()
#返回environment: base>
#范例
search() #查看加载的包,所有环境空间
#查看当前环境空间,返回<environment: R_GlobalEnv>
#三种方法等价
.GlobalEnv
()
environment()
#查看e1环境的父环境空间,返回<environment: R_GlobalEnv>
(e1)
#查看当前环境的父环境空间
#排名第2位的软件包
(())
#<environment: package:ggplot2>
#attr(,"name")
#[1] "package:ggplot2"
#attr(,"path")
#[1] "C:/Users/m/Documents/R/win-library/3.4/ggplot2"
class((())) #返回environment
# base包环境的父环境空间
(baseenv())
#返回<environment: R_EmptyEnv>
# 空环境的父环境空间,因没有父环境,所以出现错误
#返回Error in (emptyenv()) : the empty environment has no parent
(emptyenv())
# 递归打印父环境空间
<-function(e){
print(e)
if((e) & !identical(emptyenv(),e)){
((e))
}
}
(e1) #顺序与search()的包名排序一致
#通过层次结构图,又可以发现R包的加载顺序。
#最先加载的是base包,
#然后通过base::Autoloads()函数,分别加载8个基础包,
#上层的ggplot2包则是手动加载的,最后以R_GlobalEnv环境为当前运行环境空间,
#内部环境空间是R_GlobalEnv环境的下层环境空间。
#环境
#包括框架和外壳
#框架是符号-值(即对象名称及其内容)的集合
#外壳是指向封闭环境的一个指针
#封闭环境也称为父环境
#范例
x <- 5
myenv <- () #创建一个新环境
#输出myenv
#<environment: 0x000000001ffa8a30>
myenv
class(myenv) #返回environment
otype(myenv)
assign("x","Homer",env=myenv)#在新环境中创建对象,键名x,键值Homer
#显示当前环境下所有全局变量
# [1] "dfm" "f" "fit" "i" "means"
#[6] "myenv" "pvalues" "r" "results" "x"
#[11] "y" "z"
#包括定义的新环境myenv
ls()
x #返回5,与赋值相同
#显示自定义环境myenv中所有的全局变量
#[1] "x"
ls(myenv)
get("x",env=myenv) #新环境中通过键名,访问键值,返回"Homer"
myenv$x #键名,等价于对象,支持用$符号访问,返回"Homer"
myenv$y <- "New" #给键名赋值,等价于assign()
myenv$y #返回New
#展示了myenv的父环境
#返回<environment: R_GlobalEnv>
(myenv)
#注意:全局环境的父环境为空环境
#补充排序
#如果partial不为空,则表示它包含结果元素的索引,
#这些元素将通过分部排序放置在排序数组的正确位置。
#对于位于指定位置的每个结果值,任何小于该值的值都保证在排序数组中具有较小的索引,任何大于该值的值都保证在排序数组中具有较大的索引。
#这是为了提高效率而提供的,其中许多选项不能用于部分排序。
#只有当partial包含少量元素,并且完成了完整排序(如果可能的话,使用快速排序)(如果有超过10个元素)时,才会显著提高效率。名称被丢弃以进行部分排序。
require(stats)
a1 <- swiss$Education[1:28]
a1
sort(a1)[15:19] #返回8 8 9 9 10,满足排序,数值正确
#排在第15位左边的值都比排第15位的值小
#排在第19位右边的值都比排第19位的值大
#但是两端的值未必满足大小的序列排序
#从第15位到第19位,不满足被排序的要求
sort(a1, partial = c(15, 19))[15:19] #返回 8 9 8 9 10,不满足被排序,数值正确
#范例
#针对全局变量x,去除两端高低值的p%
trim <- function(p){
trimit <- function(x){
n <- length(x) #访问的x为全局变量
p=0.1
#p 表示放弃的百分比
#n 表示当前样本总量
#floor(3.45),返回3,不大于x的最大整数
#floor(n*p)+1,大于x的最小整数,下限
lo <- floor(n*p)+1
#当前样本最大整数,上限
hi <- n+1-lo
#(x, partial = NULL, = NA, decreasing = FALSE,
#method = c("auto", "shell", "quick", "radix"), = FALSE)
#(x,partial=unique(c(lo,hi))),仅完成所取位置的数字排序
#(x,partial=unique(c(lo,hi)))[lo:hi],仅取完成数字排序的部分
#unique(x),对x进行去重
#unique(c(lo,hi)),对两个单独的向量去重,上限!=下线,基本没变,
#以上是根据你的数据得到的,R中默认的是fromLast=FALSE,即若样本点重复出现,则取首次出现的;
#否则去最后一次出现的。列名不变,去掉重复样本值之后的行名位置仍为原先的行名位置。
x <- (x,partial=unique(c(lo,hi)))[lo:hi]
}
trimit #重点是将函数返回
}
x <- 1:10 #x本身有序,所以返回值有序
trim10pct <- trim(0.1) #去除1%的最高值,1%的最低值,返回一个函数
class(trim10pct) #返回function,对应trimit函数
y <- trim10pct(x) #对应trimit函数的返回值,即最后一句
y #返回值 2 3 4 5 6 7 8 9
trim20pct <- trim(0.2)
class(trim20pct) #返回 function,对应trimit函数
y <- trim20pct(x)#对应trimit函数的返回值,即最后一句
y #返回值,2 3 4 5 6 7 8 9
#查看函数环境trim10pct中存储的变量对象
ls(environment(trim10pct))
#返回 "p" "trimit"
#查看函数环境trim10pct中存储的变量对象p
get("p",env=environment(trim10pct))
#返回 0.1
#范例二
makeFunction <- function(k){
f <- function(x){
print(x+k)
}
f #不写此行,仍然表示f函数作为makeFunction函数的返回值
}
g <- makeFunction(10) #赋值k=10,并返回f函数
class(g) #返回f函数,function
g(4) #调用f函数,k=10,x=4,4+10=14
k <- 2 #无法修改存储于g函数环境中的k值
g(5) #调用f函数,k=10,不被修改,x=5,5+10=15
ls(environment(g))
get("k",environment(g)) #返回10
environment(g)$k #返回10
#一般情况下,对象的值是从本地环境中获得的
#如果未在局部环境中找到对象,会在父环境中搜索
#然后是父环境的父环境,直到对象被发现
#如果搜索到空环境仍未找到对象,它会抛出一个错误,称为词法域lexical scoping
#面向对象的编程
#泛型函数
#泛型函数不一定是print(),plot(),summary()
#任意函数都可以是泛型的
#获得s3泛型
methods(summary)
#结果解释
#,其中lm代表对象类别
#如果(fit)存在
#summary(fit)函数,实际执行(fit)函数
#查看指定函数的代码实现
getAnywhere()
#范例 一个任意的泛型函数的例子
#定义泛型函数
mymethod <- function(x,...) UseMethod("mymethod")
<- function(x) print("Using A")
<- function(x) print("Using B")
<- function(x) print("Using default")
#数据源准备
x <- 1:5
x #返回1 2 3 4 5
y <- 6:10
y #返回6 7 8 9 10
z <- 10:15
z #返回10 11 12 13 14 15
class(x) <- "a" #给x对象,分配为自定义类a
class(y) <- "b" #给y对象,分配为自定义类b
#调用泛型函数
#有特定对应对象,相当于间接使用mymethod.类别(x)
#没有特定对应对象,相当于间接使用(x)
mymethod(x) #返回"Using A"
mymethod(y) #返回"Using B"
mymethod(z) #返回"Using default"
#当对象z被分配到两类时
#第一个出现的类"a",决定使用该类型对应的泛型函数
class(z) <- c("a","b")
class(z) #返回 "a" "b"
mymethod(z) #返回 "Using A"
#当第一个出现的类"c",没有定义时
#R从左到右搜索类的列表,寻找第一个可用的泛型函数,a
class(z) <- c("c","a","b")
mymethod(z) #返回 "Using A"
#S3模型的限制
#任意的类能被分配到任意的对象上
#没有完整性检验
#S4面向对象编程的模式更加正式,严格,旨在克服由S3方法的机构化
#程度较低引起的困难
#在S4中,类被定义为具有包含特定类型信息(也就是输入的变量)的槽的抽象对象
#对象和方法构造在强制执行的规则内被正式定义
#不过使用s4模型编程更加复杂且互动较少
#范例
?women #查询women数据集位于哪个包
data(women,package="datasets")
class(women) #返回 ""
class(women) <- "lm" #修改类属性为lm,修改成功,未报错
summary(women)
#结果解读
#Error in if (p == 0) { : argument is of length zero
#women从数据框改成lm,无意义,并且导致错误
#编写有效的代码
#程序只读取需要的数据
#colClasses参数指定需要获取的列,以及列对应的类型
#每行共计10个变量,取位于1,2,5位置的数值型变量,位于3,7位置的字符变量
#与NULL值对应位置的列会被跳过
#对于行和列在文本文件中增加,速度会变得更加显著
#范例一 有效的数据输入
#高效的形式
<- (mytextfile,header=TRUE,sep=',',
colClasses=c("numeric","numeric","character",NULL,
"numeric",NULL,"character",NULL,NULL,NULL))
#低效的形式
<- (mytextfile,header=TRUE,sep=",")
#范例二 矢量化
#尽可能的使用矢量化代替循环
#矢量化,意味着更多的使用R中统计类的专有函数,这些函数旨在以高度优化的方法处理向量
#形如plyr,dplyr,reshape2包
#形如ifelse(),colsums(),rowSums()函数
#低效的形式
(1234)
#总样本rnorm(10000000),从-1-1之间生成10000000个随机数,分为10列
#设定mymatrix数据源
mymatrix <- matrix(rnorm(10000000),ncol=10)
#自定义列求和函数accum
accum <- function(x){
sums <- numeric(ncol(x)) #基于数据源的列宽,生成结果集数值型空向量
for (i in 1:ncol(x)){
for (j in 1:nrow(x)){
sums[i] <- sums[i] + x[j,i] #计算每一列值时,基于行元素顺次叠加
}
}
}
#效率比较
#accum()函数,消耗1.63s
#系统函数colSums,消耗0.01s
#矢量化函数运行速度是循环函数的165倍,不同的机器可能运行速度不一样
#求幂,加法,乘法等操作也是向量化函数
(accum(mymatrix))
#用户 系统 流逝
#1.50 0.00 1.63
(colSums(mymatrix))
#用户 系统 流逝
#0.02 0.00 0.01
#范例三 大小(即容量)正确的对象
#定义结果集为0长度,最小长度
#不如直接初始化对象到最终的大小,然后再逐个赋值
#这样可以避免R不断调整对象而耗费相当长的时间
(1234)
k <- 100000
x <- rnorm(k) #随机生成100000个值,组成一个数值型向量
class(x) #返回"numeric"
#假设向量含有1000000个数值,y=x^2,求结果集y
#低效方法
#结果集y,对应0长度
y <- 0
(for(i in 1:length(x)) y[i] <- x[i]^2)
#用户 系统 流逝
#0.05 0.00 0.05
#高效方法
#结果集y,对应最终长度,k
#使用循环
y <- numeric(length=k)
(for (i in 1:length(x)) y[i] <- x[i]^2)
#用户 系统 流逝
#0.02 0.00 0.01
#更高效的方法
#不适用循环,而是直接使用系统函数
y <- numeric(length=k)
(y <- x^2)
#用户 系统 流逝
#0 0 0
#范例四 并行化
#并行化包括分配一个任务,在两个或多个核同时运行组块,并把结果合在一起
#eig()函数,每一次迭代都是数字密集型的,不需要访问其他迭代,而且没有涉及磁盘I/O
#这种情况从并行化程序中受益最大
#并行化的缺点是它可以降低代码的可移植性,也不能保证其他人都和你有一样的硬件配置
library(foreach)
("doParallel")
library(iterators)
library(parallel)
library(doParallel)
registerDoParallel(cores=4) #登记cpu对应的核数,通过本机的任务管理器\逻辑处理器=4
eig <- function(n,p){
x <- matrix(rnorm(100000),ncol=100)
r <- cor(x)
eigen(r)$values
}
n <- 1000000
p <- 100
k <- 500
#低效,普通运行
#%do% 操作符,表示按顺序运行函数
#.combine=rbind,追加对象x作为行
#k=500,表示循环500次
(
x <- foreach(i=1:k,.combine=rbind) %do% eig(n,p)
)
#用户 系统 流逝
#12.06 0.48 12.75
#高效,并行运行
#%dopar% 操作符,表示按并行运行函数
#.combine=rbind,追加对象x作为行
#k=500,表示循环500次
(
x <- foreach(i=1:k,.combine=rbind) %dopar% eig(n,p)
)
#用户 系统 流逝
#0.31 0.09 7.31
#对比结果显示,并行是普通运行的1.7倍=12.75/7.31
#高效,并行运行
#查看耗时函数
Rprof() #起始点
x <- foreach(i=1:k,.combine=rbind) %do% eig(n,p)
Rprof(NULL) #结束点
summaryRprof() #返回位于起始点,结束点之间的函数运行时间的汇总信息
#调试
#常见的错误来源
#1 对象名称拼写错误,或是对象不存在
#2 函数调用参数时设定错误
#3 对象的内容不是用户期望的结果
#尤其是当把NULL或者含有NaN或NA值的对象传递给不能处理它们的函数,错误经常发生
#范例 因子转换的level偏离实际值
mtcars$Transmission <- factor(mtcars$a,
levels=c(1,2),#1,2与实际a列的值0,1不匹配
labels=c("Automatic","Manual"))
aov(mpg~Transmission ,data=mtcars)
#抛错
#Error in `contrasts<-`(`*tmp*`, value = [1 + isOF[nn]]) :
#对比只适用于有两个或多于两个层次的因子
head(mtcars[c("mpg","Transmission")])
#Transmission列中出现<NA>
table(mtcars$Transmission)
#Automatic Manual
#13 0
#调试工具
#范例 一个简单的调试对话
#查看mad函数定义,默认值,形式参数等
args(mad)
#function (x, center = median(x), constant = 1.4826, = FALSE,
# low = FALSE, high = FALSE)
# NULL
#标记mad函数进入调试
#当执行标记的mad函数时,browser()函数被调用
#browser()允许你单步每次调试一行函数
#输入n或者回车键时,执行当前语句并移动到下一行,不能在函数结构块继续单步执行
#输入c,继续执行剩下的函数体,并返回函数结果
#输入Q,停止执行,并立即调到顶层
debug(mad)
mad(1:10) #调用函数
#脚本旁先开窗口,显示函数定义,并且包含箭头,n输入时,会单步执行语句
#当mad函数被调用,会话进入browser()模式,
#函数的代码被列出但是不执行
#------------console控制台内容显示------
#debugging in: mad(1:10)
#debug: {
# if ()
# x <- x[!(x)]
# n <- length(x)
# constant * if ((low || high) && n%%2 == 0) {
# if (low && high)
# stop("'low' and 'high' cannot be both TRUE")
# n2 <- n%/%2 + (high)
# sort(abs(x - center), partial = n2)[n2]
# }
# else median(abs(x - center))
#}
#-----------------
#控制台中Browse[2]>,提示符下
#可以手动输入命令,查看判断条件的执行结果,对象内容x
#当对象名为特殊字符:n,Q,c时,必须使用print(n)才可以
#否则browser解读为执行指令
#where,表明你正在执行的函数调用在堆栈的何处
#取消标记函数进行调试,
#下次调用mad()执行返回结果,不会进入debug模式
undebug(mad)
#支持调试的会话选项
#范例
#定义三个函数,相互嵌套
f <- function(x,y){
z <- x+y
g(z)
}
g<- function(x){
z <- round(x)
h(z)
}
h <- function(x){
(1234)
z <- rnorm(x)
print(z)
}
#会在出现错误时打印调用的栈
#还会提示你选择列表中的一个函数
#然后在相应的环境中调用browser函数
#输入c会返回列表,输入0则退出到R提示
options(error=recover)
#正常调用
#返回 [1] -1.2070657 0.2774292 1.0844412 -2.3456977 0.4291247
f(2,3)
#非正常调用
f(2,-3)
#--------------console控制台信息显示----------
#Error in rnorm(x) : 参数不对
#
#Enter a frame number, or 0 to exit
#1: f(2, -3)
#2: #3: g(z)
# 3: #3: h(z)
# 4: #3: rnorm(x)
# Selection:
#此处需要输入对应的列表数字,
#或者输入数字0,退出,
#输入c,退回到列表选择界面
#输入n,无法单步执行,但是可以手动输入命令,查看对象内容
#建议按照倒序的方式,顺次查看4,3,2,1
#print(f),可以在console控制台输出f函数定义,f是保留字,必须加print()
#g函数,直接输入g,而并必须用print(g)
#------------------------------------------------------------------
options(error=NULL) #返回至R默认的错误提示状态