@evilking
2018-03-03T08:00:08.000000Z
字数 4369
阅读 1329
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,返回的是一个向量