第8章 习题
就算现在不用R,将来迟早你会用。
— David Kane, November 2004
8.1 向量、矩阵、数据框和列表
纸上谈兵没有用,实战是练兵最有效的方法。本篇是习题集。做习题之前,我们对前面的某些内容作个小结和补充,顺便热热身。
到目前为止,我们遇到过向量、矩阵、数据框和列表,这些都叫做对象的类型。他们的区别和联系在哪里?
向量,vector,是最简单的对象。向量由一个或多个同类变量组成。可以使用c()
函数来新建一个向量。
x <- c(1, 1, 2, 2, 3) # 生成一个向量。
is.character(x) # x 是字符型吗?不是。
## [1] FALSE
is.numeric(x) # x 是数字型吗?是的。
## [1] TRUE
mode(x) # 确实是数字型。
## [1] "numeric"
y <- c(3, 4, 4, 5, 5)
z <- c(x, y) # 多个向量并在一起。
z
## [1] 1 1 2 2 3 3 4 4 5 5
z[4] # 向量的下标。
## [1] 2
矩阵,matrix,与向量差不多,不同的是分成了行和列,也就是行列式。可以使用矩阵函数matrix()
来新建一个矩阵变量:
# 生成一个矩阵,指定行数和列数:
m <- matrix(c(2, 3, 1, 5), nrow = 2, ncol = 2)
m
## [,1] [,2]
## [1,] 2 1
## [2,] 3 5
# 生成一个矩阵,指定行数:
m <- matrix(c(2, 3, 1, 5), nrow = 2)
m
## [,1] [,2]
## [1,] 2 1
## [2,] 3 5
# 生成一个矩阵,指定行数,并按行排列:
m <- matrix(seq(1, 20, 1), nrow = 5, byrow = TRUE)
m
## [,1] [,2] [,3] [,4]
## [1,] 1 2 3 4
## [2,] 5 6 7 8
## [3,] 9 10 11 12
## [4,] 13 14 15 16
## [5,] 17 18 19 20
# 生成一个矩阵,指定行数,并按列排列:
m <- matrix(seq(1, 20, 1), nrow = 5, byrow = FALSE)
m[2, 2] # 矩阵的下标。
## [1] 7
我们在第3.1节见过的image()
函数,就是专门针对矩阵作图的。矩阵的任何一行或一列,都是一个向量。
数据框,dataframe,与矩阵差不多,区别在于,不用的列可以是不同类型。相当于 Excel 的表格。我们前面处理过的mydata2就是数据框。可以使用data.frame()
函数来新建一个数据框变量。
a <- c(1, 2, 3, 4)
b <- seq(5, 8, by = 1)
d <- data.frame(a, b) # 生成一个数据框。
d
## a b
## 1 1 5
## 2 2 6
## 3 3 7
## 4 4 8
is.data.frame(d) # 是数据框吗?
## [1] TRUE
str(d) # 数据框的结构。
## 'data.frame': 4 obs. of 2 variables:
## $ a: num 1 2 3 4
## $ b: num 5 6 7 8
class(d)
## [1] "data.frame"
nrow(d) # 数据框的行数。
## [1] 4
ncol(d) # 数据框的列数。
## [1] 2
e <- c(9, 10)
f <- rbind(d, e) # 给数据框增加一行。
f
## a b
## 1 1 5
## 2 2 6
## 3 3 7
## 4 4 8
## 5 9 10
g <- c("one", "two", "three", "four", "five")
class(g)
## [1] "character"
h <- cbind(f, g) # 给数据框增加一列。
h
## a b g
## 1 1 5 one
## 2 2 6 two
## 3 3 7 three
## 4 4 8 four
## 5 9 10 five
class(h)
## [1] "data.frame"
ncol(h)
## [1] 3
colnames(h) <- c("one", "two", "three") # 更改列名称。
h
## one two three
## 1 1 5 one
## 2 2 6 two
## 3 3 7 three
## 4 4 8 four
## 5 9 10 five
数据框的任何一列都是一个向量,而任何一行仍然是个数据框,这就是思考题2.3的答案:mean()
函数的自变量可以是向量或矩阵,但不能是数据框。若想把数据框的行转化成向量,需要把该行用unlist()
函数打散。这个操作在第3.1节出现过。
is.numeric(d[, 1])
## [1] TRUE
is.data.frame(d[1, ])
## [1] TRUE
is.numeric(d[1, ])
## [1] FALSE
is.numeric(unlist(d[1, ]))
## [1] TRUE
列表,list,跟数据框差不多,区别在于,列表里的不同项目可以有不同的长度。我们在第5章见过的lapply()
函数,返回的结果就是列表。如果要新建一个列表,可以用list()
函数:
mylist <- list(x = 1:4, y = letters[3:10])
mylist
## $x
## [1] 1 2 3 4
##
## $y
## [1] "c" "d" "e" "f" "g" "h" "i" "j"
列表里元素的调用方式比较特别,需要用两层方括号,或用美元符号。体会一下:
mylist[[1]]
mylist[[1]][1]
mylist[[2]]
mylist[[2]][5]
mylist$x
mylist$y[3]
下面开始习题。练习的内容主要是复习已经学过的,并提升一点点。如果遇到问题,请善用小助理。菜鸟学 R,不必面面俱到,多练练习题,上手之后就会喜欢上 R,就有兴趣深入了解下去。
8.2 A卷:照猫画虎题
请先运行下面的代码,生成一个示例数据文件:
write.csv(WorldPhones, file = 'c:/r4r/wp.csv')
打开这个文件浏览一下。这是20世纪五六十年代世界各大洲的电话数量。下面的练习,均以此文件为出发点。
Example 8.1 读入数据
- 将wp.csv读入R中,保存到一个叫 wp 的对象中,并查看文件内容、总结报告和作图。
- 将wp的年份列的列名称改为“year”。
- 将wp的行名称改为对应年份。
Example 8.2 数据类型。
- 给wp新增年代列,取值为对应行所属的年代,即‘1950s’和’1960s’字符,列名称为’decade’。
- 查看wp各列的数据类型。
Example 8.3 矩阵。
- 生成一个5行6列的矩阵,取值为整数数列1:30。
Example 8.4 矩阵与数据框。
wp是个对话框对象。请将wp转换成矩阵对象wp_mt,并比较wp与wp_mt的区别。
从这两个对象中选取1956年欧洲的电话数量。
从这两个对象中选择亚洲和欧洲两列。
- 从这两个对象中选择第2, 4, 5行。选择除了2, 4, 5行之外的其他行。
Example 8.5 计算。
计算wp数据中全世界每年的电话总数。
- 计算wp中任意相邻年份全世界以及各洲的电话增长数量以及增长百分比。
Example 8.6 作图。
请在同一张图上以合理的布局、颜色和线型,做出亚洲1951到1961年之间:
电话数量逐年变化的散点图,以及
- 电话数量增长率的散点图。
Example 8.7 循环:
请以合理的布局,用循环函数做出所有大洲在1951年到1961年之间各自的电话数量增长曲线。Example 8.8 拟合。
将各洲电话数量对年份进行线性拟合,并在散点图上添加拟合直线和拟合方程。
Example 8.9 办公套件。
请把上述题目的解答过程、代码、注释以及结果均以R Markdown的形式写在同一个文档中。8.3 B卷:自由发挥题
还记得小学时做过的数学题吗?记得那时候做过的什么“相遇问题”、“追及问题”、“鸡兔同笼问题”,解决方法是四则运算。后来学会了方程,就把从前的解法全忘了。有一次收拾书柜,翻出一张小学试卷,有一道题目,我只用了两步的四则运算就做出来了,换现在我只会列二元一次方程组来求解。我看着当时的算式发呆,因为怎么也看不懂每一步是什么意思。
下面这两道小学数学题,请用R语言解答。
ABC
x DC
-----
DEAC
7ED
-----
FDBC