第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]
思考 8.1 向量、矩阵、数据框、列表四者之间如何转换?

下面开始习题。练习的内容主要是复习已经学过的,并提升一点点。如果遇到问题,请善用小助理。菜鸟学 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语言解答。

Example 8.10 在下面的竖式里,A,B,C,D,E,F均为0到9的整数,那么他们分别是多少?

  ABC
x  DC
-----
 DEAC
 7ED
-----
 FDBC
Example 8.11 从前,山上有一棵魔法苹果树。树上长了125个苹果,有一天掉下来1个苹果。从第二天起,每天掉的苹果数量比前一天多1个,但如果某天树上的苹果数量少于这一天本应该掉的数量时,那么从这一天起又重新从掉1个苹果开始,按原来的规律进行新的一轮。那么,第几天树上的苹果会掉光?