8 R数据类型的性质
8.1 存储模式与基本类型
R的变量可以存储多种不同的数据类型,
可以用typeof()
函数来返回一个变量或表达式的类型。比如
typeof(1:3)
## [1] "integer"
typeof(c(1,2,3))
## [1] "double"
typeof(c(1, 2.1, 3))
## [1] "double"
typeof(c(TRUE, NA, FALSE))
## [1] "logical"
typeof('Abc')
## [1] "character"
typeof(factor(c('F', 'M', 'M', 'F')))
## [1] "integer"
注意因子的结果是integer
而不是因子。
R还有两个函数mode()
和storage.mode()
起到与typeof()
类似的作用,
这是为了提供与S语言兼容所遗留的,
应停止使用。
R中数据的最基本的类型包括logical,
integer, double, character, complex, raw,
其它数据类型都是由基本类型组合或转变得到的。
character类型就是字符串类型,
raw类型是直接使用其二进制内容的类型。
为了判断某个向量x
保存的基本类型,
可以用is.xxx()
类函数,
如is.integer(x)
,
is.double(x)
,
is.numeric(x)
,
is.logical(x)
,
is.character(x)
,
is.complex(x)
,
is.raw(x)
。
其中is.numeric(x)
对integer和double内容都返回真值。
在R语言中数值一般看作double, 如果需要明确表明某些数值是整数, 可以在数值后面附加字母L,如
整数型的缺失值是NA
,
而double型的特殊值除了NA
外,
还包括Inf
, -Inf
和NaN
,
其中NaN
也算是缺失值, Inf
和-Inf
不算是缺失值。
如:
对double类型,可以用is.finite()
判断是否有限值,
NA
、Inf
, -Inf
和NaN
都不是有限值;
用is.infinite()
判断是否Inf
或-Inf
;
is.na()
判断是否NA
或NaN
;
is.nan()
判断是否NaN
。
严格说来,
NA
表示逻辑型缺失值,
但是当作其它类型缺失值时一般能自动识别。
NA_integer_
是整数型缺失值,
NA_real_
是double型缺失值,
NA_character_
是字符型缺失值。
在R的向量类型中, integer类型、double类型、logical类型、character类型、还有complex类型和raw类型称为原子类型(atomic types), 原子类型的向量中元素都是同一基本类型的。 比如, double型向量的元素都是double或者缺失值。
除了原子类型的向量,
在R语言的定义中,
向量还包括后面要讲到的列表(list),
列表的元素不需要属于相同的基本类型,
而且列表的元素可以不是单一基本类型元素。
用typeof()
函数可以返回向量的类型,
列表返回结果为"list"
:
原子类型的各个元素除了基本类型相同, 还不包含任何嵌套结构,如:
R有一个特殊的NULL
类型,
这个类型只有唯一的一个NULL
值,
表示不存在。
NULL
长度为0,
不能有任何属性值。
用is.null()
函数判断某个变量是否取NULL
。
NULL
值可以用来表示类型未知的零长度向量,
如c()
没有自变量时返回值就是NULL
;
也经常用作函数缺省值,
在函数内用is.null()
判断其缺省后再用一定的计算逻辑得到真正的缺省情况下的数值。
要把NULL
与NA
区分开来,
NA
是有类型的(integer、double、logical、character等),
NA
表示存在但是未知。
数据库管理系统中的NULL值相当于R中的NA值。
8.2 类型转换与类型升档
可以用as.xxx()
类的函数在不同类型之间进行强制转换。
如
as.numeric(c(FALSE, TRUE))
## [1] 0 1
as.character(sqrt(1:4))
## [1] "1" "1.4142135623731" "1.73205080756888" "2"
类型转换也可能是隐含的,比如,
四则运算中数值会被统一转换为double类型,
逻辑运算中运算元素会被统一转换为logical类型。
逻辑值转换成数值时,TRUE
转换成1,
FALSE
转换成0。
在用c()
函数合并若干元素时,
如果元素基本类型不同,
将统一转换成最复杂的一个,复杂程度从简单到复杂依次为:
logical<integer<double<character
。
这种做法称为类型升档,如
不同类型参与要求类型相同的运算时, 也会统一转换为最复杂的类型, 也称为类型升档, 如:
8.3 属性
除了NULL
以外,
R的变量都可以看成是对象,
都可以有属性。
在R语言中,
属性是把变量看成对象后,
除了其存储内容(如元素)之外的其它附加信息,
如维数、类属等。
R对象一般都有length
和mode
两个属性。
常用属性有names
, dim
,class
等。
8.3.1 attributes
函数
对象x
的所有属性可以用attributes()
读取,
如
x <- table(c(1,2,1,3,2,1)); print(x)
##
## 1 2 3
## 3 2 1
attributes(x)
## $dim
## [1] 3
##
## $dimnames
## $dimnames[[1]]
## [1] "1" "2" "3"
##
##
## $class
## [1] "table"
table()
函数用了输出其自变量中每个不同值的出现次数,称为频数。
从上例可以看出,
table()
函数的结果有三个属性,前两个是dim和dimnames,
这是数组(array)具有的属性;
另一个是class属性,值为"table"
。
因为x
是数组,可以访问如
也可以用attributes()
函数修改属性,
如
如上修改后x
不再是数组,也不是table。
8.3.2 attr
函数
可以用attr(x, "属性名")
的格式读取或定义x
的属性。
如:
可以让向量x
额外地保存一个theta
属性,
这样的属性常常成为“元数据”(meta data),
比如,
用来保存数据的说明、模拟数据的真实模型参数,等等。
8.3.3 names
属性
有元素名的向量、列表、数据框等都有names
属性,
许多R函数的输出本质上也是列表,
所以也有names
属性。
用names(x)
的格式读取或设定。
如:
x <- 1:5
y <- x^2
lmr <- lm(y ~ x)
print(names(lmr))
## [1] "coefficients" "residuals" "effects" "rank"
## [5] "fitted.values" "assign" "qr" "df.residual"
## [9] "xlevels" "call" "terms" "model"
对于没有元素名的向量x
,names(x)
的返回值是NULL
。
8.4 类属
R具有一定的面向对象语言特征,
其数据类型有一个class
属性,
函数class()
可以返回变量类型的类属,
比如
typeof(factor(c('F', 'M', 'M', 'F')))
## [1] "integer"
mode(factor(c('F', 'M', 'M', 'F')))
## [1] "numeric"
storage.mode(factor(c('F', 'M', 'M', 'F')))
## [1] "integer"
class(factor(c('F', 'M', 'M', 'F')))
## [1] "factor"
class(as.numeric(factor(c('F', 'M', 'M', 'F'))))
## [1] "numeric"
class属性是特殊的。
如果一个对象具有class属性,
某些所谓“通用函数(generic functions)”会针对这样的对象进行专门的操作,
比如,
print()
函数在显示向量和回归结果时采用完全不同的格式。
这在其它程序设计语言中称为“重载”(overloading)。
class属性用来支持R的S3风格的类, 常用的有factor, 日期,日期时间, 数据框,tibble。 R还有S4、R6等风格的类。