R深入 | 数据类型
学过R语言都知道,数据类型有向量、矩阵、数据框、列表。知道这些就可以使用,不过如果不更深入地了解,很可能会产生一些困惑。例如
为什么 as.vector 函数不能将列表转化为向量?
向量带有名字是怎么回事?怎么处理?
class, typeof, mode到底有什么区别?
(本文有一些代码结果没有列出来,建议在电脑上边运行R边看)
下面是本文目录
vector的划分
is.vector 的作用
区分两种vector的函数
atomic的细分
NA的类型
属性的介绍及作用
typeof class mode storage.mode 的区别
vector 的划分
R中的vector分为两类,atomic和list,二者的区别在于,前者元素类型必须相同,后者可以不同。前者的代表是向量和矩阵,后者的代表是list和数据框。
# atomic
a <- 1:5
b <- letters[1:5]
c <- 1:10
mat <- matrix(c,nrow=2)
# list
l <- list(a,b,c)
df <-data.frame(a,b)
is.vector
由于它们都是vector,所以用is.vector检验无法区分向量和列表。当然,也无法用as.vector将列表转换成向量。
is.vector(a) # TRUE
is.vector(l) # TRUE
as.vector(l) # 仍然是list,,没有改变
is.vector(mat) # FALSE
is.vector(df) # FALSE
大家可能注意到了,同样是vector,矩阵和数据框用is.vector检验就返回的是FALSE,这说明is.vector也不是检验vector的,它的真正原理在于,检查是否最多只有一个属性:name。即查看其属性,如果没有属性或者只有一个name属性,才返回TRUE。
attributes(l) # NULL
attributes(a) # NULL
attributes(df) # 多个属性names row.names class
attributes(mat) #只有一个dim
is.vector的这个功能我现在也不知道有什么用,写在这里只是让大家知道,不要乱用。
要想将list转换成向量,可以用unlist函数
unlist(l)
as.atomic(l) # 报错,没有这个函数
as.list(a) # as.list函数是有的
as.vector的作用也不是把除了names以外的属性全部删掉,它的作用是,当作用对象是atomic时,去除它的所有属性,如果是list则没改变,用is.vector检验也返回FALSE。我们有时用unlist转换后得到的向量是自带名字的,如果不去掉会造成一些麻烦,所以as.vector的一个作用是去除向量的名字属性。
# as.vector作用于list无效
vdf <- as.vector(df)
attributes(vdf) # 属性没有改变
is.vector(vdf) # FALSE
# 转化数据框后向量带有名字
(udf <- unlist(df))
attributes(udf) # 只有一个names属性
vudf <- as.vector(udf)
attributes(vudf) # NULL
# 自己创建带有名字的向量
aaa <- c(1,2,3)
attr(aaa,"names")<-letters[1:3]
aaa
as.vector(aaa)
as.numeric(aaa) # 数值型向量去掉名字还有这种方法
bbb <- c(letters[4:6])
attr(bbb,"names")<- letters[1:3]
bbb
as.vector(bbb)
区分
要想区分atomic和list,可以使用is.atomic和is.list函数。
is.atomic(a) # TRUE
is.atomic(mat) # TRUE
is.atomic(l) # FALSE
is.atomic(df) # FALSE
is.list(a) # FALSE
is.list(mat) # FALSE
is.list(l) # TRUE
is.list(df) # TRUE
除此之外,还可以用typeof函数来检验
typeof(l) # list
typeof(df) # list
typeof(mat) # integer
typeof(a) # integer
typeof(b) # character
我们可以发现typeof不仅区分了atomic和list,而且返回的是atomic更细的类别。下面我们就来说一说atomic的细分。
atomic的细分
atomic可以分成6个类别,4个常见类别logical, integer, double, character;2个不常见类别complex raw。后两个涉及到复数等,用的不多,我们着重讨论前面4个。
我们前文说到的一个atomic向量中的元素必须有相同的类型,就是指这里,比如一个向量中不能同时含有integer和character,如果创建的时候同时包含多种类型,则自动统一,顺序是logical, integer, double, character,前面的会自动变成后面的。我们看下面一个例子
c(T,F) # TRUE FALSE
(p <- c(T,F,1L,4L)) # 1 0 1 4
(q <- c(T,F,1L,4)) # 1 0 1 4
c(T,1L,2,3.4) # 1.0 1.0 2.0 3.4
c(T,1L,2,"a") # "TRUE" "1" "2" "a"
is.double(p) # FALSE
is.double(q) # TRUE
is.numeric(p) # TRUE
is.numeric(q) # TRUE
其中p和q的返回值看起来是一样的,实际上一个是integer,一个是double.而integer和double统一为numeric,所以用它检验都返回TRUE。
上面四个类型的优先级同样适用于,不同类型之间逻辑值比较的时候的自动转换
F==0 # TRUE
T==1 # TRUE
1=="1" # TRUE
TRUE=="1" # FALSE
T=="TRUE" # TRUE
3>="a" # FALSE
NA
NA的设定非常巧妙,作为缺失值,它本身是一个逻辑值,处于转换链的最底端,这样它的出现不会强制转换正常的数据,只是自己被转换掉了。同时,R中还自带这其他类型的缺失值。double类型的NA_real_,integer类型的NA_integer_和character类型的NA_character_,我们来看一下例子。
typeof(NA) # logical
k <- c(NA,1L,3L)
m <- c(NA,1,3)
n <- c(NA,1,"a")
typeof(k[1]) # integer
typeof(m[1]) # double
typeof(n[1]) # character
typeof(NA_real_) # double
k1 <- c(NA_real_,1L,2L)
m1 <- c(NA_character_,1,3)
typeof(k1) # double
typeof(m1) # character
属性
我们上文中提到了属性,我们可以暂时这样理解:属性是一个变量附带的标签,它一般不影响变量的正常使用,但是在需要的时候,我们可以提取关于这个变量的其他信息。
属性名称可以任意指定,通过attr函数对应属性内容。输出变量名,有的属性自动显示,不显示的可以用attributes函数查看属性。
a <- 1:5
attr(a,"any") <- "all"
a
attributes(a)
有三个属性名比较特殊,”names”,”dim”,”class”,这三个属性名不可以随意赋值。同时,对于这三个属性,都有专门的函数来查看.
attr(a,"class") <- "data.frame" # 报错
attr(a,"dim") <- 2 # 报错
attr(a,"names") <- "a"
a
attr(a,"names") <- letters[1:5]
a
# df
attributes(df)
names(df)
dim(df)
class(df)
# 修改属性
dim(mat)<-c(5,2)
mat
# 将数据框转换为列表
class(df)<-NULL
df
上面最后一个例子说明,data.frame是一个特殊的list,这里称为vector的扩展。
数据框和 tibble 是从列表中扩展而来
因子型向量是从整数向量中扩展而来
data data-time 向量是从数值向量中扩展而来
扩展的手段是改变属性,正如上面,list增加了一个属性”class”为”data.frame”就变成了数据框,去掉又变回了list.
f <- factor(1:5)
f
is.atomic(f) # TRUE
is.numeric(f) # FALSE
is.factor(f) # TRUE
attributes(f) # levels和class
class(f)<-NULL
is.factor(f) # FALSE
is.numeric(f) # TRUE
attributes(f) # levels
typeof class mode storage.mode 的区别
大家在检查函数类型的时候应该经常见到这几个函数,它们得出的结果有时相同,有时不同,让人捉摸不清,在这里做一下总结。
其中mode storage.mode typeof 是一类,检查变量类型,如list integer character等
关系是,从前往后,检查精度越来越细。所以当想看粗类别时,就用mode,看细类别用typeof.
# 此时后两者都能查到最细的程度
mode(1:5) # numeric
storage.mode(1:5) # integer
typeof(1:5) # integer
# 此时只有typeof能查到最细的程度
mode(`+`) # function
storage.mode(`+`) # function
typeof(`+`) # builtin
# 这里稍微解释一下,`+`是一个函数
# R中一切皆为函数的性质,以后会专门讲解
# 下面两个例子等价
1+2 # 3
`+`(1,2) # 3
class和另外三个不是一个体系
对于有”class”属性的变量,返回的就是这个属性对应的值
对于没有”class”属性的变量,则根据它的类型、维度来确定
# 有"class"属性,只认属性
a <- 1:6
df <-data.frame(a,a+1)
class(df) # data.frame
class(df)<- "abc" # 随便定义一个值
class(df) # abc
#没有属性,根据类型和dim属性
ar <- array(1:4)
attributes(ar) # 数组dim为4
mat <- matrix(1:4)
attributes(mat) # 矩阵dim为4 1 两个值
a <- 1:4 # 没有dim
class(a) # integer
aar <- structure(a,dim=4) # 赋予类似array的dim
class(aar) # array
amat <- structure(a,dim=c(4,1)) # 赋予类似matrix的dim
class(amat) # matrix
class(list(1:4)) # list 不一样类型
参考文献
Advanced R (http://adv-r.had.co.nz/)
typeof mode class的区别 (
专栏信息
专栏主页:Data Analysis
专栏目录:目录
文末彩蛋
NA,NaN,Inf,NULL的区别
NA表示缺失值,读取数据时没有值的位置会显示NA
Inf和-Inf就是指正负无穷,或者除以0时会出现
NaN表示无意义,即“not a number” 0/0
NULL对象,一般被用在函数参数中,表示该参数没有被赋予任何值,或者某些函数返回值为NULL
四个特殊值都有自己专门的函数来检验。
b <- 1:3
b==3 # FALSE FALSE TRUE
a <- c(1,3,NA,Inf,-Inf,NaN,NULL)
length(a) # 6,没有把NULL算进去
a==3 # FALSE TRUE NA FALSE FALSE NA
# 说明其中两个Inf可以用==来检验,其余的都要用自己专门的函数
is.nan(a[6]) # TRUE
is.na(a[3]) # TRUE
is.null(a[7]) # FALSE
a[7] # NA
is.null(NULL) # TRUE
# 不过Inf也有自己专门的函数
is.finite(a[4]) # FALSE
is.finite(a[1]) # TRUE
is.infinite(a[5]) # TRUE
is.infinite(a[4]) # TRUE
Dwzb , R语言中文社区专栏作者,厦门大学统计专业学生。
知乎专栏:Data Analysis
https://zhuanlan.zhihu.com/Data-AnalysisR
微信回复关键字即可学习
回复 R R语言快速入门免费视频
回复 统计 统计方法及其在R中的实现
回复 用户画像 民生银行客户画像搭建与应用
回复 大数据 大数据系列免费视频教程
回复 可视化 利用R语言做数据可视化
回复 数据挖掘 数据挖掘算法原理解释与应用
回复 机器学习 R&Python机器学习入门