OOP
#封装,将相关的数据项目打包为一个类的实例
#多态,相同的函数使用不同的类的对象的时候可以调用不同的操作
#继承,允许把一个给定的类的性质自动赋予为其下属的更特殊化的类
#S3类包含一个列表,附加一个类名属性和调度的功能
#具有多态性的函数如plot()和print()称为泛型函数
#调用泛型函数的时候,R会将该调用调度到适当的类方法
#也就是将对泛型函数的调用重新定向到针对该对象的类所定义的函数上
x <- c(1,2,3)
y <- c(1,3,8)
lmout <- lm(y~x)
#lm()函数将返回一个lm类的对象
class(lmout)
lmout
#直接输入lmout会调用print.lm()```
#泛型函数的实现方法
methods()找到给定泛型函数的所有实现方法
methods(print)
星号是不可见函数,不在默认命名空间中的函数
通过getAnywhere()函数来找到函数,并且使用命名空间限定符访问他们
getAnywhere(print.lm)
可以看出这个函数在stats命名空间下,使用下面限定符执行它
stats:::print.lm(y~x)
操作符 :: :::访问命名空间变量
pkg::name returns the value of the exported variable name in namespace pkg
and pkg:::name returns the value of the internal variable name
查看所有的泛型函数
methods(class="default")
S3类的实例是通过构建一个列表的方式创建的,列表的组件是该类的成员变量
类属性是通过attr()或者class()函数手动设置,再定义各种泛型函数的实现方法
j <- list(name="joe",salary=55000,union=T)
创建一个类
class(j) <- "employee"
attributes(j)
j#打印的时候被当成一个列表
定义自己这个类的打印方法,打印的时候就会默认调度到这个方法上
print.employee <- function(wrkr){
cat(wrkr$name,"\n")
cat("salary",wrkr$salary,"\n")
cat("union member",wrkr$union,"\n")
}```
使用继承
k <- list(name="kate",salary=68000,union=F,hrsthismonth=2)
#建立hrlyemployee类继承至employee
class(k) <- c("hrlyemployee","employee")
#新类继承了原有类的方法,因从可以使用其print```
#用于存储上三角矩阵的类
function returns 1+..+i
sum1toi <- function(i) return(i*(i+1)/2)
create an object of class ut from the full matrix inmat
ut <- function(inmat){
nrow and ncol return the number of rows or columns present in x
n <- nrow(inmat)
start to build the object
创建一个列表作为类对象的主体,rtrn表示将会创建并返回这个类实例
rtrn <- list()
将ut设为一个类
class(rtrn) <- "ut"
rtrn$mat <- vector(length = sum1toi(n))
ix也是个向量,存储了开始的位置索引
rtrn$ix <- sum1toi(0:(n-1))+1
for (i in 1:n){
#store column i
ixi <- rtrn$ix[i]
rtrn$mat[ixi:(ixi+i-1)]<-inmat[1:i,i]
}
return(rtrn)
}
uncompress utmat to a full matrix
expandut <- function(utmat){
numbers of rows and cols of matrix
n <- length(utmat$ix)
initialize a matrix
fullmat <- matrix(nrow = n,ncol = n)
for(j in 1:n){
start <- utmat$ix[j]
#这一行有多少个元素,然后计算出finish
fin <- start + j - 1
#above-diag part of col j
abovediagj <- utmat$mat[start:fin]
#将向量填充至矩阵的每一列中,然后剩下元素补0
fullmat[,j] <- c(abovediagj,rep(0,n-j))
}
return(fullmat)
}
print matrix
print.ut<-function(utmat){
print(expandut(utmat))
}
multiply one ut matrix by another,returning another ut instance
"%mut%" <- function(utmat1,utmat2){
一个二元操作符
ix向量的长度就是矩阵的维数
n <- length(utmat1$ix)
初始化一个输出的上三角矩阵
utprod <- ut(matrix(0,nrow=n,ncol=n))
开始迭代计算乘法,i表示矩阵2计算第几列,j表示进行计算的具体元素
for(i in 1:n){
#提取出来utmat2的第i列元素的初始索引位置
startbi <- utmat2$ix[i]
#第i列就有i个元素,初始化乘积矩阵的每一列
prodcoli <- rep(0,i)
for(j in 1:i){
#通过j来选取应该和第i列计算的矩阵1的元素
startaj <- utmat1$ix[j]
#选取矩阵2的要计算的元素,单个值
bielement <- utmat2$mat[startbi+j-1]
#对于j的变化,从1到i,计算矩阵1相应的元素和矩阵2每列的元素乘积
#如果i=2,那么prodcoli[1]=prodcoli[1]+b3=2a+3b,prodcoli[2]=3c
#用两个输入矩阵的列项来解决乘法问题
prodcoli[1:j] <- prodcoli[1:j]+bielementutmat1$mat[startaj:(startaj+j-1)]
}
#矩阵每次开始计算的位置
startprodcoli <- sum1toi(i-1)+i
#乘积矩阵的第1或者第2,3个或者第4,5,6个元素,由计算出来的prodcoli来赋值
utprod$mat[startbi:(startbi+i-1)] <- prodcoli
}
return(utprod)
}
做一个测试
test <- function(){
utm1 <- ut(rbind(1:2,c(0,2)))
utm2 <- ut(rbind(3:2,c(0,1)))
utp <- utm1 %mut% utm2
print(utm1)
print(utm2)
print(utp)
utm1 <- ut(rbind(1:3,0:2,c(0,0,5)))
utm2 <- ut(rbind(4:2,0:2,c(0,0,1)))
utp <- utm1 %mut% utm2
print(utm1)
print(utm2)
print(utp)
}```
S4类
#S3类仅仅是列表,所以可以随时添加任何组件,因此满足不了面向对象编程的安全性
#S4类就可以避免这些问题
#setClass()来定义一个S4类,每个成员变量都有明确的类型
setClass("employee",representation(name="character",salary="numeric",
union="logical"))
#创建对象,使用new()来为此类创建一个实例
joe <- new("employee",name="joe",salary=56000,union=T)
#成员变量称为slot,@用来访问成员变量,可以写入可以读取
joe@salary <- 64000
#或者使用slot()函数
slot(joe,"salary") <- 78000
#直接输入joe相当于执行了show(joe)
#改写这个show()函数,定义泛型函数
#第一个参数是将要定义给类方法的泛型函数名
#第二个参数是类的名称,第三个是一个匿名函数,定义这个新函数
setMethod("show","employee",function(object){
#iselse语句
inorout <- ifelse(object@union,"is","is not")
cat(object@name,"has a salary of",object@salary,
"and",inorout,"in the union","\n")
})```
#对象的管理
ls()函数列出所有的对象
ls()
pattern这个具名参数,可以列出名称具有特定模式的对象
ls(pattern = 'dd')#双引号和单引号都可以
rm()函数删除特定对象
删除a,b对象
rm(a,b)
删除ls()列出的所有对象,rm的具名参数list=
rm(list=ls())
使用ls()的pattern具名参数
pattern参数后面要加双引号
rm(list=ls(pattern = "dd"))```
save()函数保存对象集合
#若干个对象调用save()可以将对象写入硬盘,以待之后用load()恢复
#生成符合正态分布的随机数10000个
z <- rnorm(10000)
hz <- hist(z)
save(hz,"hzfile")
rm(hz)
load("hzfile")
ls()
plot(hz)
#保存和加载R的数据(与R.data的交互:save()函数和load()函数)
a <- 1:10
save(a, file = "data/dumData.Rdata") #
#data文件为当前工作目录下的文件,必须存在
rm(a)
load("data/dumData.Rdata")
print(a)```
#一些有用的函数
unclass()顾名思义,对一个对象使用得到的结果仍然属于其基础类
page()查看一个对象,比如函数,page(table),主要解决问题是函数太长,
不容易显示的问题
edit()同样可以解决这种问题,可以在文本编辑器中进行查阅
names()函数可以显示出对象有哪些组件
attributes()函数显示对象组件并且给出更多信息,比如类名称```
exists()函数
#来检测对象是否存在
exists("abc")
#返回TRUE 或者 FALSE```