向量

向量 属于 R

1 个练习

关于 向量

R 中的vector(严格来说是 atomic vector)是一组type相同的值:常见的有integer、numeric、character、logical;很少见的是complex或raw。 它们在内存中连续存放,类似 C 数组。

如果传入混合类型的值,R 会悄悄把它们全部强制转换成同一种类型,通常是 character,结果可能出乎你的意料。

v <- c(2, 5.4, "txt")
v
#> [1] "2"   "5.4" "txt"
typeof(v)
#> [1] "character"

创建向量

如果你已经知道了所有的值,可以使用c()(“concatenate”的缩写):

x <- 10
v <- c(4, 7, x)

c()函数非常灵活,输入可以包含其他向量和范围。 c()能接受任意数量和种类的输入,并把它们展平成一个向量。

如果向量一开始很小,但在运行时增长很多(例如在循环中不断添加值),那么预先分配一个长向量会快得多,之后再往里面填入真实数据:

v <- vector(length = 100) 

这样可以尽量减少对对象的复制,而对于长向量来说,复制既慢又耗内存。

范围、序列与重复

要表示一段连续的值(递增或递减),可以使用:记法

v <- 1:5 # equivalent to c(1, 2, 3, 4, 5)
w <- 10:7 # c(10, 9, 8, 7)

在 R 中,范围并不是一种单独的类型,只是构造向量的一种简写方式。

seq()函数提供了更精细的控制:

# specify step size
seq(2, 11, by = 3) # c(2, 5, 8, 11)

# specify number of values, evenly-spaced
seq(2.5, 4, length.out = 5) # c(2.500, 2.875, 3.250, 3.625, 4.000) 

rep()函数可以轻松创建重复的模式:

count <- 3
rep(7, count)
#> [1] 7 7 7

rep(1:3, count)
#> [1] 1 2 3 1 2 3 1 2 3

rep(1:3, each = 2) # the "each" keyword is required in this case
#> [1] 1 1 2 2 3 3

有几个范围被预定义成了内置常量:

letters  # LETTERS is the UPPERCASE equivalent
#> [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"

month.name
#> [1] "January"   "February"  "March"     "April"     "May"       "June"      "July"      "August"   
#> [9] "September" "October"   "November"  "December" 

month.abb
#> [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"

算术运算

运算会自动沿着向量逐个元素地进行。 其他语言中常见的循环、列表推导和递归在这里并不需要,而且(出于性能考虑)应尽量避免。

2 + 1:3     # c(3, 4, 5)
2 * 1:3     # c(2, 4, 6)
12 / 1:3    # c(12  6  4)
2 ^ (1:3)   # c(2, 4, 8) : exponentiation, operator precedence order here needs ()

两个向量之间也可以运算,元素按对逐一处理:

v <- 1:3
w <- 5:7

v + w
#> [1]  6  8 10

v * w
#> [1]  5 12 21

v ^ w
#> [1]    1   64 2187

这比乍看起来要强大得多,后面的概念中还有更多内容可以探索。

访问向量中的元素

和许多语言一样,我们可以用方括号里的下标来访问:

v <- 4:7
v[2]
#> [1] 5
v[2:4]
#> [1] 5 6 7

但要小心:R 默认使用从 1 开始的下标。 这在科学计算语言(Fortran、Matlab、Julia)中很常见,但与 C 及其众多后继语言从 0 开始的下标不同。

范围既可以像上面的例子那样使用,也可以用在极其灵活的c()函数中:

v <- c(4, 7, 10)
w <- c(2, v[2:3], 11) # c(2, 7, 10, 11)

vectors(和 R 中的大多数东西一样)可以被当作可变的,用同样灵活的语法就能写入单个或多个元素:

v <- 1:10
v[2] <- 42
v[4:6] <- c(11, 12, 13)
v
#> [1]  1 42  3 11 12 13  7  8  9 10

负下标

熟悉其他语言的程序员可能会以为v[-1]是访问向量最后一个元素的方式。 错了! 要取最后一个元素,请使用tail()。

v <- c(2, 4, 6) # defaults to last 6 entries
tail(v)
#> [1] 2 4 6
tail(v, n=1) # just the last entry
#> [1] 6

负下标实际上是一种删除元素的方式:

v <- c(2, 4, 6)
v[-2]
#> [1] 2 6  # second element gone

返回的是向量的一份更短的副本,v本身并没有改变。

向量的条件判断

对向量进行比较,会返回一个长度相同的布尔值向量。 这在all()和any()这类函数中非常方便:

v <- c(4, 7, 10)
v >= 6
#> [1] FALSE  TRUE  TRUE
all(v > 6)
#> [1] FALSE    # not all elements match this condition
any(v > 6)
#> [1] TRUE     # at least one element matches

对于更复杂的逻辑表达式,重要的是使用&和|运算符,它们可以作用于向量。 双字符的&&和||只用于比较单个值,这一点在[布尔值概念][concept-boolean]中已经讨论过。

v <- c(4, 7, 10)
v %% 2 == 0 & v > 5
#> [1] FALSE FALSE  TRUE

向量在 R 中无处不在

这个话题以后还会再讲到。 现在只需要留意控制台里输出的格式:

1:20
#> [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17
#> [18] 18 19 20

每行开头的[ ]里的数字表示该行第一个元素的下标(对需要换行显示的长向量很有用)。 但为什么单个值前面也会有个[1]呢?

Note

R 中根本没有真正的标量值!

看起来像单个数字或单个字母的东西,实际上都是长度为 1 的向量。

在基础和布尔值这两个概念中,我们已经从数字类型和逻辑类型身上看到了这一点的端倪。

关于记法的说明

上面介绍的向量,更正式的叫法是atomic vectors。因为它们只能包含简单的、不可再分(因此称为“原子”)的值,例如numeric、character、boolean。更复杂的结构可以构成recursive vectors,这会在讨论lists时介绍。

通过 GitHub 编辑 该链接会在新窗口或标签页中打开

学习 向量