查看原文
其他

R深入 | 数据类型

2017-04-07 dwzb 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机器学习入门 

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存