R语言笔记之数据类型6-列表

列表

什么是列表

列表(list)为最复杂的数据类型,是一些对象或成分的有序集合,例如可以是向量,矩阵,数据框,或其他列表的组合。用list()创建:mylist<-list(object1,object2,...), 或命名列表:mylist<-list(name1=object1,name2=object2,...)

列表(list)是一个广义的向量,它可以包含其它类型的对象,甚至可以包括其它列表。列表的灵活性非常有用,例如,当我们使用R拟合了一个线性模型时,其结果本质上就是一个列表,它里面包括了线性回归的详细结果,例如回归系数(数值向量),残差(数值向量)和QR分析(包含一个矩阵和其它对象的列表)等。

就我个人理解而言,列表更像是对数据框的拓展,它可以含有多个不同类型,不同长度的数据,而数据框只能是含有不同类型的相同数据。

创建列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
g<-"My First List"
h<-c(25,26,18,39)
j<-matrix(1:10,nrow=5)
k<-c("one","two","three")
mylist<-list(title=g,ages=h,j,k)
mylist #输出列表
## $title
## [1] "My First List"
##
## $ages
## [1] 25 26 18 39
##
## [[3]]
## [,1] [,2]
## [1,]1 6
## [2,]2 7
## [3,]3 8
## [4,]4 9
## [5,]5 10
##
## [[4]]
## [1] "one" "two" "three"

显示列表数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mylist[1]
## $title
## [1] "My First List"
mylist[2]
## $ages
## [1] 25 26 18 39
mylist[[2]]
## [1] 25 26 18 39
mylist["ages"]
## $ages
## [1] 25 26 18 39

删除列表数据

将需要删除的内容直接赋值为NULL即可,如下所示:

1
2
3
4
5
6
7
8
9
10
g<-"My First List"
h<-c(25,26,18,39)
j<-matrix(1:10,nrow=5)
k<-c("one","two","three")
mylist<-list(title=g,ages=h,j,k)
mylist #输出列表
mylist
mylist$ages
mylist$ages <- NULL
mylist

运行结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
> mylist
$title
[1] "My First List"
$ages
[1] 25 26 18 39
[[3]]
[,1] [,2]
[1,] 1 6
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
[[4]]
[1] "one" "two" "three"
> mylist$ages
[1] 25 26 18 39
> mylist$ages <- NULL
> mylist
$title
[1] "My First List"
[[2]]
[,1] [,2]
[1,] 1 6
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
[[3]]
[1] "one" "two" "three"

提取列表子集

有的时候,我们需要从一个列表中提取多个元素,由这些元素组成的列表构成了原列表的一个子集。构建一个列表的子集,我们可以使用单层方括号,就像提取向量和矩阵中的元素一样。取些这些元素后,然后放到一个新列表中。
这里的方括号用法与其在向量中的用法非常类似。我们可以用字符向量表示成分名称,用数值向量表示成分位置,用逻辑向量指定选择标准,来取出列表元素。

例如mylist[[N]][M]表示提取N列中的第M个元素,如下所示:

1
2
3
4
5
6
7
g<-"My First List"
h<-c(25,26,18,39)
j<-matrix(1:10,nrow=5)
k<-c("one","two","three")
mylist<-list(title=g,ages=h,j,k)
mylist #输出列表
mylist[[2]][1] # 第取第2列第1个元素

结果运行如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
> mylist #输出列表
$title
[1] "My First List"
$ages
[1] 25 26 18 39
[[3]]
[,1] [,2]
[1,] 1 6
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
[[4]]
[1] "one" "two" "three"
> mylist[[2]][1] # 第取第2列第1个元素
[1] 25

判断列表完整

使用complete.cases()函数可以判断一个列表是否完整,但是,此函数要求列表的所有行长度都相等,如下所示:

1
2
3
4
h<-c(25,26,NA,NA)
k<-c("one","two","three","four")
mylist<-list(ages=h,k)
complete.cases(mylist)

运行结果如下所示:

1
2
> complete.cases(mylist)
[1] TRUE TRUE FALSE FALSE

更多情况下,complete.cases()函数用于判断数据框是否有缺失值,如下所示:

1
2
3
test <- data.frame(h<-c(25,26,NA,NA),
k<-c("one","two","three","four"))
complete.cases(test)

运行结果如下所示:

1
2
3
4
> test <- data.frame(h<-c(25,26,NA,NA),
+ k<-c("one","two","three","four"))
> complete.cases(test)
[1] TRUE TRUE FALSE FALSE

do.call()函数

do.call()函数可以根据名称或函数以及要传递给它的一个列表参数构建并执行一个函数的调用,它的用法如下所示:

1
do.call(what, args, quote = FALSE, envir = parent.frame())

参数说明如下所示:

  1. what:函数或者是一个要调用函数的名称的字符串;
  2. args:列表(list)参数,是函数执行的对象;
  3. quote:逻辑值,用于指定是否引用参数,默认情况下是FALSE,如果是FALSE,那么do.call()就会检测调用环境中的参数,而非envir中的参数。如果参数为TRUE,那么前面每个参数都会引用,
  4. envir:调用的函数。如果what参数是一个字符串,参数是一个符号或引号的表达式,envir这个参数比较有用。

看下面的案例:

第一个案例:

1
2
> do.call("complex", list(imag = 1:3))
[1] 0+1i 0+2i 0+3i

"complex"表示复数,这也是一个函数,list(imag=1:3)则是生成一个列表,并且将列表中的元素转换为复数。

第二个案例:如果我们已经有了一个数据框,可以通过c()函数添加另外的参数,如下所示:

1
2
3
4
tmp <- expand.grid(letters[1:2], 1:3, c("+", "-"))
tmp
do.call("paste", c(tmp, sep = ""))
do.call(paste, list(as.name("A"), as.name("B")), quote = TRUE)

运行结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
> tmp <- expand.grid(letters[1:2], 1:3, c("+", "-"))
> tmp
Var1 Var2 Var3
1 a 1 +
2 b 1 +
3 a 2 +
4 b 2 +
5 a 3 +
6 b 3 +
7 a 1 -
8 b 1 -
9 a 2 -
10 b 2 -
11 a 3 -
12 b 3 -
> do.call("paste", c(tmp, sep = ""))
[1] "a1+" "b1+" "a2+" "b2+" "a3+" "b3+" "a1-" "b1-" "a2-" "b2-" "a3-" "b3-"
> do.call(paste, list(as.name("A"), as.name("B")), quote = TRUE)
[1] "A B"

在这个案例中,先创建了一个tmp数据框,然后调用了paste()函数,并且添加了""

第三个案例:这里需要注意就是参数what加引号与不加引号的作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
A <- 2
f <- function(x) print(x^2)
env <- new.env()
assign("A", 10, envir = env)
assign("f", f, envir = env)
f <- function(x) print(x)
f(A) # 2
do.call("f", list(A)) # 2
# 在env里,加引号和不加引号是有区别的
# 加引号,代表引用的是env里的
do.call("f", list(A), envir = env) # 4
do.call(f, list(A), envir = env) # 2
# 不加引号,代表是parent.frame()里的f
do.call("f", list(quote(A)), envir = env) # 100
do.call(f, list(quote(A)), envir = env) # 10
do.call("f", list(as.name("A")), envir = env) # 100
eval(call("f", A)) # 2
eval(call("f", quote(A))) # 2
eval(call("f", A), envir = env) # 4
eval(call("f", quote(A)), envir = env) # 100

结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
> A <- 2
> f <- function(x) print(x^2)
> env <- new.env()
> assign("A", 10, envir = env)
> assign("f", f, envir = env)
> f <- function(x) print(x)
> f(A) # 2
[1] 2
> do.call("f", list(A)) # 2
[1] 2
> # 在env里,加引号和不加引号是有区别的
> # 加引号,代表引用的是env里的
>
> do.call("f", list(A), envir = env) # 4
[1] 4
> do.call(f, list(A), envir = env) # 2
[1] 2
> # 不加引号,代表是parent.frame()里的f
>
> do.call("f", list(quote(A)), envir = env) # 100
[1] 100
> do.call(f, list(quote(A)), envir = env) # 10
[1] 10
> do.call("f", list(as.name("A")), envir = env) # 100
[1] 100
>
> eval(call("f", A)) # 2
[1] 2
> eval(call("f", quote(A))) # 2
[1] 2
> eval(call("f", A), envir = env) # 4
[1] 4
> eval(call("f", quote(A)), envir = env) # 100
[1] 100

参考资料

  1. do.call 函数使用问题