读书笔记_第二十章

#高级编程

#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(),row.names(),col.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)  #返回"data.frame"
attributes(iris)
#属性names,变量名的字符串向量
#属性row.names,识别单个植物(行)的数字向量
#属性class,识别data.frame的类型

head(iris) #默认返回前6行
#等价于将attributes的names下的所有值,全部展开
#对于列,将每个列展开,输出所有值
#对于行,attr(,"row.names"),展开,输出所有行号
unclass(iris) 
unclass(iris)$Species #加$符号的支持单独访问

set.seed(1234)
fit <- kmeans(iris[1:4],3)
#返回对象所有属性
#$names
#[1] "cluster"      "centers"      "totss"        "withinss"     "tot.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"     "tot.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均值聚类分析的中心
set.seed(1234)
fit <- kmeans(iris[1:4],3)
means <- fit$centers#提取聚类中心矩阵,行是类,列是变量的均值
str(means)
#chr [1:3] "1" "2" "3"  ----对应行名
#chr [1:4] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width"-----对应列名

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("myplot.png")
    plot(x,y)
    dev.off
}

#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>
    
#内部环境
#内部环境,构造出来的环境
#可以是通过 new.env()函数显示创建的环境空间,也可以是匿名的环境空间。
e1 <- new.env()
e1
#返回environment: 0x3e28948>
    
# 父环境
#父环境,即上一层环境,环境空间的上一层。
parent.env(e1)
#返回environment: R_GlobalEnv>
    
# 空环境
#空环境,即顶层环境,没有父环境空间。
emptyenv()
#返回environment: R_EmptyEnv>
    
# 包环境
#包环境,包封装的环境空间。
baseenv()
#返回environment: base>

#范例
search() #查看加载的包,所有环境空间

#查看当前环境空间,返回<environment: R_GlobalEnv>
#三种方法等价
.GlobalEnv 
parent.frame()
environment()

#查看e1环境的父环境空间,返回<environment: R_GlobalEnv>
parent.env(e1) 

#查看当前环境的父环境空间
#排名第2位的软件包
parent.env(parent.frame()) 
#<environment: package:ggplot2>
#attr(,"name")
#[1] "package:ggplot2"
#attr(,"path")
#[1] "C:/Users/m/Documents/R/win-library/3.4/ggplot2"
class(parent.env(parent.frame())) #返回environment

# base包环境的父环境空间
parent.env(baseenv())
#返回<environment: R_EmptyEnv>

# 空环境的父环境空间,因没有父环境,所以出现错误
#返回Error in parent.env(emptyenv()) : the empty environment has no parent
parent.env(emptyenv())

# 递归打印父环境空间
parent.call<-function(e){
      print(e)
      if(is.environment(e) & !identical(emptyenv(),e)){
             parent.call(parent.env(e))
          }
     }

parent.call(e1) #顺序与search()的包名排序一致
#通过层次结构图,又可以发现R包的加载顺序。 
#最先加载的是base包,
#然后通过base::Autoloads()函数,分别加载8个基础包,
#上层的ggplot2包则是手动加载的,最后以R_GlobalEnv环境为当前运行环境空间,
#内部环境空间是R_GlobalEnv环境的下层环境空间。

#环境
#包括框架和外壳
#框架是符号-值(即对象名称及其内容)的集合
#外壳是指向封闭环境的一个指针
#封闭环境也称为父环境

#范例
x <- 5
myenv <- new.env() #创建一个新环境

#输出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>
parent.env(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
        #sort.int(x, partial = NULL, na.last = NA, decreasing = FALSE,
        #method = c("auto", "shell", "quick", "radix"), index.return = FALSE)
        #sort.int(x,partial=unique(c(lo,hi))),仅完成所取位置的数字排序
        #sort.int(x,partial=unique(c(lo,hi)))[lo:hi],仅取完成数字排序的部分
        
        #unique(x),对x进行去重
        #unique(c(lo,hi)),对两个单独的向量去重,上限!=下线,基本没变,
        #以上是根据你的数据得到的,R中默认的是fromLast=FALSE,即若样本点重复出现,则取首次出现的;
        #否则去最后一次出现的。列名不变,去掉重复样本值之后的行名位置仍为原先的行名位置。
        x  <- sort.int(x,partial=unique(c(lo,hi)))[lo:hi]
    }
    trimit #重点是将函数返回 
}

x <- 1:10 #x本身有序,所以sort.int返回值有序
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)
#结果解释
#summary.lm,其中lm代表对象类别
#如果summary.lm(fit)存在
#summary(fit)函数,实际执行summary.lm(fit)函数

#查看指定函数的代码实现
getAnywhere(summary.lm)

#范例 一个任意的泛型函数的例子

#定义泛型函数
mymethod <- function(x,...) UseMethod("mymethod")
mymethod.a <- function(x) print("Using A")
mymethod.b <- function(x) print("Using B")
mymethod.default <- 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)
#没有特定对应对象,相当于间接使用mymethod.default(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) #返回 "data.frame"

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值对应位置的列会被跳过
#对于行和列在文本文件中增加,速度会变得更加显著

#范例一  有效的数据输入

#高效的形式
my.data.frame <- read.table(mytextfile,header=TRUE,sep=',',
colClasses=c("numeric","numeric","character",NULL,
"numeric",NULL,"character",NULL,NULL,NULL))

#低效的形式
my.data.frame <- read.table(mytextfile,header=TRUE,sep=",")


#范例二  矢量化
#尽可能的使用矢量化代替循环
#矢量化,意味着更多的使用R中统计类的专有函数,这些函数旨在以高度优化的方法处理向量
#形如plyr,dplyr,reshape2包
#形如ifelse(),colsums(),rowSums()函数

#低效的形式
set.seed(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倍,不同的机器可能运行速度不一样
#求幂,加法,乘法等操作也是向量化函数

system.time(accum(mymatrix))
#用户 系统 流逝 
#1.50 0.00 1.63

system.time(colSums(mymatrix))
#用户 系统 流逝 
#0.02 0.00 0.01 

#范例三  大小(即容量)正确的对象
#定义结果集为0长度,最小长度
#不如直接初始化对象到最终的大小,然后再逐个赋值
#这样可以避免R不断调整对象而耗费相当长的时间

set.seed(1234)
k <- 100000
x <- rnorm(k) #随机生成100000个值,组成一个数值型向量
class(x) #返回"numeric"

#假设向量含有1000000个数值,y=x^2,求结果集y
#低效方法
#结果集y,对应0长度
y <- 0
system.time(for(i in 1:length(x)) y[i] <- x[i]^2)
#用户 系统 流逝 
#0.05 0.00 0.05 

#高效方法
#结果集y,对应最终长度,k
#使用循环
y <- numeric(length=k)
system.time(for (i in 1:length(x)) y[i] <- x[i]^2)
#用户 系统 流逝 
#0.02 0.00 0.01

#更高效的方法
#不适用循环,而是直接使用系统函数
y <- numeric(length=k)
system.time(y <- x^2)
#用户 系统 流逝 
#0    0    0 


#范例四  并行化
#并行化包括分配一个任务,在两个或多个核同时运行组块,并把结果合在一起
#eig()函数,每一次迭代都是数字密集型的,不需要访问其他迭代,而且没有涉及磁盘I/O
#这种情况从并行化程序中受益最大
#并行化的缺点是它可以降低代码的可移植性,也不能保证其他人都和你有一样的硬件配置

library(foreach)

install.packages("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次
system.time(
    x <- foreach(i=1:k,.combine=rbind) %do% eig(n,p)
)
#用户  系统  流逝 
#12.06  0.48 12.75 

#高效,并行运行
#%dopar% 操作符,表示按并行运行函数
#.combine=rbind,追加对象x作为行
#k=500,表示循环500次
system.time(
    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 = contr.funs[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, na.rm = 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 (na.rm) 
#        x <- x[!is.na(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 + as.integer(high)
#        sort(abs(x - center), partial = n2)[n2]
#    }
#    else median(abs(x - center))
#}
#-----------------

#控制台中Browse[2]>,提示符下
#可以手动输入命令,查看判断条件的执行结果na.rm,对象内容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){
    set.seed(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默认的错误提示状态

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值