@evilking
2018-03-03T16:00:08.000000Z
字数 4369
阅读 1104
R基础篇
向量的元素要求都是同类型的,而列表却可以组合多个不同类型的对象,而且列表中还可以包含列表,即递归列表,有点像C语言中的结构体
列表在R中扮演至关重要的角色,是数据框和面向对象编程的基础
本篇会讲列表的创建,值操作,列表上常用的一些函数
> x <- list(name = "Tom",salary = 5000, union=T) #创建字段带有标签的列表
> x
$name
[1] "Tom"
$salary
[1] 5000
$union
[1] TRUE
> (y <- list("Ketty", 5500, F)) #使用默认标签的方式创建列表
[[1]]
[1] "Ketty"
[[2]]
[1] 5500
[[3]]
[1] FALSE
> (z <- vector(mode = "list")) #使用"list"属性的方式创建列表
list()
> z[["name"]] <- "Hello"
> z[["salary"]] <- 6000
> z[["union"]] <- T
> z
$name
[1] "Hello"
$salary
[1] 6000
$union
[1] TRUE
> (w <- list(x,y,z,count = 3)) #列表中包含列表
[[1]]
[[1]]$name
[1] "Tom"
[[1]]$salary
[1] 5000
[[1]]$union
[1] TRUE
[[2]]
[[2]][[1]]
[1] "Ketty"
[[2]][[2]]
[1] 5500
[[2]][[3]]
[1] FALSE
[[3]]
[[3]]$name
[1] "Hello"
[[3]]$salary
[1] 6000
[[3]]$union
[1] TRUE
$count
[1] 3
> c(list(y,z),recursive=T) #将递归属性去掉,得到的是一个向量
name salary union
"Ketty" "5500" "FALSE" "Hello" "6000" "TRUE"
>
这里举出了四种创建列表的方式,从技术上讲,列表就是向量,之前我们接触过的普通向量都称为"原子型"(atomic)向量,即向量的元素已经是最小的、不可再分的。而列表则属于"递归型"(recursive)向量
第一个例子是创建列表的各个组件带有名称的列表,其中这些名称就叫做标签(tags),如name="Tom"
中的name
就是一个标签;标签的运用可以方便查看该组件代表的含义,同时也可以使用标签去访问某个组件,可以使代码更清晰
当然标签也是可选的,如第二个例子就是创建不带标签的列表,则标签名默认就是按数字排列下去,如[[1]] [[2]] [[3]]
;我们一般推荐使用带标签的方式来创建列表
列表本质上也是向量,可以用vector()函数来创建,只是该向量具有"list"
模式,然后给列表的组件赋值,如果该组件不存在列表中,则会自动创建该标签的组件;如第三个例子就是先创建了一个空的列表,然后给列表的组件赋值,此时这些组件原先是不存在的,赋值的同时也是创建了对应标签的组件
在第四个例子中,我们用列表对象去创建一个新列表,那么列表w的前三个元素,每个元素都是一个子列表,第四个元素是一个向量;由于并没有给前三个元素设置标签名,那么就是用默认的[[1]]
来索引;从这个例子还可以看出列表的每个元素的类型确实可以不同
在最后的例子中,用c()函数去拼接,而c()函数有个可选参数recursive,决定在拼接列表的时候,是否把原列表"压平",就是把所有组件的元素都提取出来,组合成一个向量
赋值
> x #使用上一步创建的列表x
$name
[1] "Tom"
$salary
[1] 5000
$union
[1] TRUE
> x[[1]] <- "Hello Tom" #使用"[[1]]"的方式索引组件
> x
$name
[1] "Hello Tom"
$salary
[1] 5000
$union
[1] TRUE
> x[["salary"]] <- 3400 #使用[["salary"]]的方式索引组件
> x
$name
[1] "Hello Tom"
$salary
[1] 3400
$union
[1] TRUE
> x$union <- FALSE #使用$符合的方式索引组件
> x
$name
[1] "Hello Tom"
$salary
[1] 3400
$union
[1] FALSE
上面列举了三种访问列表中的组件的方式,返回值就是对应的组件,返回值的类型就是对应组件元素的数据类型,这一点很重要,因为还有一种访问组件的方式,如下:
> x[1] #使用单括号索引取值
$name
[1] "Hello Tom"
> x["salary"] #使用单括号+标签的方式取值
$salary
[1] 3400
> class(x[1]) #查看单括号取值结果的数据类型
[1] "list"
> class(x["salary"])
[1] "list"
> class(x[[1]]) #查看双括号索引取值的数据类型
[1] "character"
> class(x[["salary"]])
[1] "numeric"
> x[1:2] #使用单括号+索引序列的方式取值
$name
[1] "Hello Tom"
$salary
[1] 3400
> x[[1:2]] #体会与上面单括号的区别
Error in x[[1:2]] : 下标出界
>
上述例子展示了使用单括号索引取值及它的返回值类型;可以看出当使用单括号索引时,取的是原列表的子列表,这个子列表包含了取值时对应的标签索引和数值索引;而双重中括号[[]]
一次只能提取列表的一个组件,返回值是组件本身的类型,而不是列表
增加或删除列表元素
> x #依然使用上面创建的列表对象
$name
[1] "Hello Tom"
$salary
[1] 3400
$union
[1] FALSE
> x[["aa"]] <- "aabb" #添加一个标签为"aa"的组件,并赋值为"aabb"
> x
$name
[1] "Hello Tom"
$salary
[1] 3400
$union
[1] FALSE
$aa
[1] "aabb"
> x$bb <- "bbcc" #添加一个标签为"bb"的组件,赋值为"bbcc"
> x
$name
[1] "Hello Tom"
$salary
[1] 3400
$union
[1] FALSE
$aa
[1] "aabb"
$bb
[1] "bbcc"
> x[[6]] <- "ccdd" #赋值一个不存在的索引组件时,会添加该组件
> x
$name
[1] "Hello Tom"
$salary
[1] 3400
$union
[1] FALSE
$aa
[1] "aabb"
$bb
[1] "bbcc"
[[6]]
[1] "ccdd"
> x[[4]] <- "ddee" #给一个存在的组件赋值时,就是简单的为组件赋值了
> x
$name
[1] "Hello Tom"
$salary
[1] 3400
$union
[1] FALSE
$aa
[1] "ddee"
$bb
[1] "bbcc"
[[6]]
[1] "ccdd"
> x[[6]] <- NULL #删除指定索引元素
> x
$name
[1] "Hello Tom"
$salary
[1] 3400
$union
[1] FALSE
$aa
[1] "ddee"
$bb
[1] "bbcc"
>
上述例子展示了如何去添加新组件,就是只需要给指定索引的组件赋值就可以了,如果该索引的组件不存在,就会创建新组件;如果要删除指定索引的组件,只需要将它赋值为NULL就可以了
上面介绍了单括号表示取列表的子列表,当然可以利用单括号和索引序列去批量添加或删除组件了,如下:
> x[6:8] <- c(FALSE,TRUE,TRUE) #添加新组件
> x
$name
[1] "Hello Tom"
$salary
[1] 3400
$union
[1] FALSE
$aa
[1] "ddee"
$bb
[1] "bbcc"
[[6]]
[1] FALSE
[[7]]
[1] TRUE
[[8]]
[1] TRUE
> x[5:8] <- NULL #删除子列表
> x
$name
[1] "Hello Tom"
$salary
[1] 3400
$union
[1] FALSE
$aa
[1] "ddee"
>
列表的数据展开
> x
$name
[1] "Hello Tom"
$salary
[1] 3400
$union
[1] FALSE
$aa
[1] "ddee"
> unlist(x) #展开列表x,则不在具有list属性
name salary union aa
"Hello Tom" "3400" "FALSE" "ddee"
> mode(unlist(x)) #去掉了list属性
[1] "character"
> names(w) #查看列表w的标签
[1] "" "" "" "count"
> names(x)
[1] "name" "salary" "union" "aa"
> names(y)
NULL
> names(z)
[1] "name" "salary" "union"
> unlist(w) #循环列表的每个元素也是依次展开
name salary union name salary union
"Tom" "5000" "TRUE" "Ketty" "5500" "FALSE" "Hello" "6000" "TRUE"
count
"3"
> (x <- unname(unlist(x))) #使用unname()函数可以去掉元素名
[1] "Hello Tom" "3400" "FALSE" "ddee"
>
如果一个列表的各个元素含有标签,就可以使用names()获取它的标签
unlist()函数返回的值是一个向量,向量的元素的元素名就来自原列表的标签
> w
[[1]]
[[1]]$name
[1] "Tom"
[[1]]$salary
[1] 5000
[[1]]$union
[1] TRUE
[[2]]
[[2]][[1]]
[1] "Ketty"
[[2]][[2]]
[1] 5500
[[2]][[3]]
[1] FALSE
[[3]]
[[3]]$name
[1] "Hello"
[[3]]$salary
[1] 6000
[[3]]$union
[1] TRUE
$count
[1] 3
> length(x) #查看列表x的长度
[1] 4
> length(w) #查看循环列表w的长度
[1] 4
>
由于列表是向量,可以使用length()得到列表的组件个数
> lapply(list("a" = 1:5,"b" = 10:20),sum)
$a
[1] 15
$b
[1] 165
>
lapply()函数与矩阵的apply()函数的用法类似,对列表中的每个组件应用给定的函数,并返回另一个列表,lapply即代表list apply
上例中按照lapply()函数的规则,分别对"a"组件和"b"组件应用sum()函数求和,则序列1:5求和就是15,序列10:20求和就是165,则结果就如上展示的这个新列表
> sapply(list(1:5,10:20),median)
[1] 3 15
>
在某些情况下,lapply()返回的列表可以转化为矩阵或向量的形式,于是可以用sapply()函数,代表simplified [l]apply,返回的是一个向量