R/R對象屬性的函數小結
R對象屬性的函數小結
編輯任何編程語言都會包含有兩個最基本的概念:數據類型和數據結構 數據類型指的是數值、字符串、邏輯值及他們衍生出的各種複合類型 數據結構描述各種數據類型所組成的對象是如何組織的
數據類型和數據結構包含兩個層次:物理層次和邏輯層次
- 類似於硬盤分區中的物理分區和邏輯分區的區別,對於一塊硬盤,可以用磁盤管理工具可以分成多個分區來儲存數據,這些分區被稱為邏輯分區;但無論我們分成多少分區,他們都同屬於一個物理分區
- 物理層次:計算機物理內存上是如何存儲的數據類型和結構
- 邏輯層次:不同編程語言本身定義的基本數據類型和結構,以及用戶自定義的各種數據類型,這是高級編程語言對底層計算機物理儲存的一種高級封裝,使得編程語言更加接近於自然語言。
- 在面向對象的編程中,被封裝成各種類和對象。
查看數據類型class、mode和typeof
編輯R的許多語法都是繼承自S語言,R語言的開發時間也比較早,許多現在的程序概念在當時並沒有被提出。 mode和storage.mode函數描述早期程序的數據類型,繼承自S語言,更接近與內存儲存的數據類型,storage.mode的描述更準確一些。mode和storage.mode的返回值基於typeof函數的結果。 typeof函數描述最新的、更準確的數據類型,其返回值的結果和storage.mode一樣,在進行程序編譯時比較重要。 class函數描述的是R語言定義的類屬性,如向量、列表、數據框等,可以由用戶自定義。類是面向對象編程中的概念,如Biostrings包中定義的一個DNAstring類。 總結:mode、storage.mode和typeof描述的數據類型存儲的物理屬性,對象所儲存的數據類型改變時發生改變;class描述的是數據的存儲的邏輯層次屬性,默認與物理屬性相同,可以由用戶自定義修改,但不影響對象所儲存的實際數據類型。
> x<- 1
> mode(x)
[1] "numeric"
> class(x)
[1] "numeric"
> typeof(x)
[1] "double"
> class(x)<- "subclass"
> class(x)
[1] "subclass"
> mode(x)
[1] "numeric"
> typeof(x)
[1] "double"
# 如果用户修改的名称是R的内置数据类型名称,则数据类型发生改变
> class(x) <- "character"
> x
[1] "1"
> class(x)
[1] "character"
> mode(x)
[1] "character"
> typeof(x)
[1] "character"
比較不同R對象的屬性函數返回值的比較
library(methods)
library(dplyr)
library(xml2)
library(Biostrings)
setClass("dummy", representation(x="numeric", y="numeric"))
types <- list(
"logical vector" = logical(),
"integer vector" = integer(),
"numeric vector" = numeric(),
"complex vector" = complex(),
"character vector" = character(),
"raw vector" = raw(),
factor = factor(),
"logical matrix" = matrix(logical()),
"numeric matrix" = matrix(numeric()),
"logical array" = array(logical(8), c(2, 2, 2)),
"numeric array" = array(numeric(8), c(2, 2, 2)),
list = list(),
pairlist = .Options,
"data frame" = data.frame(),
"closure function" = identity,
"builtin function" = `+`,
"special function" = `if`,
environment = new.env(),
null = NULL,
formula = y ~ x,
expression = expression(),
call = call("identity"),
name = as.name("x"),
"paren in expression" = expression((1))[[1]],
"brace in expression" = expression({1})[[1]],
"S3 lm object" = lm(dist ~ speed, cars),
"S4 dummy object" = new("dummy", x = 1:10, y = rnorm(10)),
"external pointer" = read_xml("<foo><bar /></foo>")$node,
"DNAString" = DNAString(),
"RNAString" = RNAString(),
"AAString" = AAString()
)
type_info <- Map(
function(x, nm)
{
tibble(
"spoken type" = nm,
class = class(x),
mode = mode(x),
typeof = typeof(x),
storage.mode = storage.mode(x)
)
},
types,
names(types)
) %>% bind_rows
knitr::kable(type_info)
輸出:
|spoken type |class |mode |typeof |storage.mode |
|:-------------------|:-----------|:-----------|:-----------|:------------|
|logical vector |logical |logical |logical |logical |
|integer vector |integer |numeric |integer |integer |
|numeric vector |numeric |numeric |double |double |
|complex vector |complex |complex |complex |complex |
|character vector |character |character |character |character |
|raw vector |raw |raw |raw |raw |
|factor |factor |numeric |integer |integer |
|logical matrix |matrix |logical |logical |logical |
|numeric matrix |matrix |numeric |double |double |
|logical array |array |logical |logical |logical |
|numeric array |array |numeric |double |double |
|list |list |list |list |list |
|pairlist |pairlist |pairlist |pairlist |pairlist |
|data frame |data.frame |list |list |list |
|closure function |function |function |closure |function |
|builtin function |function |function |builtin |function |
|special function |function |function |special |function |
|environment |environment |environment |environment |environment |
|null |NULL |NULL |NULL |NULL |
|formula |formula |call |language |language |
|expression |expression |expression |expression |expression |
|call |call |call |language |language |
|name |name |name |symbol |symbol |
|paren in expression |( |( |language |language |
|brace in expression |{ |call |language |language |
|S3 lm object |lm |list |list |list |
|S4 dummy object |dummy |S4 |S4 |S4 |
|external pointer |externalptr |externalptr |externalptr |externalptr |
|DNAString |DNAString |S4 |S4 |S4 |
|RNAString |RNAString |S4 |S4 |S4 |
|AAString |AAString |S4 |S4 |S4 |
查看數據結構的函數--str和attributes函數
編輯str和summary函數類似,str是structure的縮寫,主要是查看當前對象的數據結構的描述,無法修改對象的數據結構,當對象儲存的數據結構被修改時,str函數的返回值發生變化。 attributes描述的是R對象邏輯層次的數據結構,可以修改,可以由用戶自定義,修改之後立即生效,但不影響R對象儲存在內存的內容,但會影響對象的數據結構,str的函數返回值會發生改變,mostattributes可以設置更複雜的數據結構。
## 查看R语言内置的数据结构
> x <- cbind(a = 1:3, pi = pi)
> x
a pi
[1,] 1 3.141593
[2,] 2 3.141593
[3,] 3 3.141593
# 使用attributes查看对象x的逻辑数据结构
> attributes(x)
$dim
[1] 3 2
$dimnames
$dimnames[[1]]
NULL
$dimnames[[2]]
[1] "a" "pi"
# 使用str查看对象x的物理数据结构
> str(x)
num [1:3, 1:2] 1 2 3 3.14 3.14 ...
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:2] "a" "pi"
# 使用attributes修改对象x的数据结构
> attributes(x) <- NULL
> x
[1] 1.000000 2.000000 3.000000 3.141593 3.141593 3.141593
# 修改后,逻辑的数据结构变成NULL
> attributes(x)
NULL
# str函数返回逻辑层级的数据结构消失时,数据在物理储存的数据结构
> str(x)
num [1:6] 1 2 3 3.14 3.14 ...
# 使用mostattributes函数还原对象x原来的数据结构
> mostattributes(x) <- list(dim = 3:2, dimnames = list(NULL,c("a","pi")), names = paste(1:6))
> x
a pi
[1,] 1 3.141593
[2,] 2 3.141593
[3,] 3 3.141593
> attributes(x)
$dim
[1] 3 2
$dimnames
$dimnames[[1]]
NULL
$dimnames[[2]]
[1] "a" "pi"
> str(x)
num [1:3, 1:2] 1 2 3 3.14 3.14 ...
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:2] "a" "pi"
# 查看一个函数的数据结构
> str(numeric)
function (length = 0L)
is()及is類函數的簡單講解
編輯is.*()的一類函數可以判斷對象是否是某一種特定的數據類型或數據結構 is()可以查看該對象所屬的所有數據類型或數據結構
> x <- cbind(a = 1:3, pi = pi)
# 使用is.*()类函数判断对象是否属于该数据类型或数据结构,并返回逻辑值
> is.numeric(x)
[1] TRUE
> is.character(x)
[1] FALSE
> is.vector(x)
[1] FALSE
> is.matrix(x)
[1] TRUE
> is.array(x)
[1] TRUE
> is.data.frame(x)
[1] FALSE
# 查看对象x所属的全部类型
> is(x)
[1] "matrix" "array" "structure" "vector"
[5] "vector_OR_factor"
可以通過編寫一個函數來查看一個對象的數據類型或數據結構
what.is <- function(x, show.all=FALSE) {
# set the warn option to -1 to temporarily ignore warnings
op <- options("warn")
options(warn = -1)
on.exit(options(op))
list.fun <- grep(methods(is), pattern = "<-", invert = TRUE, value = TRUE)
result <- data.frame(test=character(), value=character(),
warning=character(), stringsAsFactors = FALSE)
# loop over all "is.(...)" functions and store the results
for(fun in list.fun) {
res <- try(eval(call(fun,x)),silent=TRUE)
if(class(res)=="try-error") {
next() # ignore tests that yield an error
} else if (length(res)>1) {
warn <- "*Applies only to the first element of the provided object"
value <- paste(res,"*",sep="")
} else {
warn <- ""
value <- res
}
result[nrow(result)+1,] <- list(fun, value, warn)
}
# sort the results
result <- result[order(result$value,decreasing = TRUE),]
rownames(result) <- NULL
if(show.all)
return(result)
else
return(result[which(result$value=="TRUE"),])
}
查看函數的輸出
> what.is(1)
test value warning
1 is.atomic TRUE
2 is.double TRUE
3 is.finite TRUE
4 is.numeric TRUE
5 is.vector TRUE
> what.is(x)
test value warning
2 is.array TRUE
3 is.atomic TRUE
4 is.double TRUE
5 is.matrix TRUE
6 is.numeric TRUE
> what.is(numeric)
test value warning
1 is.function TRUE
2 is.recursive TRUE