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```