4.2 向量
现在,你已经试过用冒号运算符:
来创建从某个数到另一个数的数字序列,以及用c
函数来拼接数值和向量,以创建更长的向量。总结如下:
8.5:4.5 #从8.5到4.5的数字序列
## [1] 8.5 7.5 6.5 5.5 4.5
c(1, 1:3, c(5, 8), 13) #不同值被拼接成单一向量
## [1] 1 1 2 3 5 8 13
vector
函数能创建一个指定类型和长度的矢量。其结果中的值可为零、FALSE
、空字符串,或任何相当于“什么都没有”(nothing)的类型:
vector("numeric", 5)
## [1] 0 0 0 0 0
vector("complex", 5)
## [1] 0+0i 0+0i 0+0i 0+0i 0+0i
vector("logical", 5)
## [1] FALSE FALSE FALSE FALSE FALSE
vector("character", 5)
## [1] "" "" "" "" ""
vector("list", 5)
## [[1]]
## NULL
##
## [[2]]
## NULL
##
## [[3]]
## NULL
##
## [[4]]
## NULL
##
## [[5]]
## NULL
在上例中,NULL
是一个特殊的“空”值(不要与代表缺失值的NA
混淆)。第5章会详细讨论NULL
。为方便起见,用每个类型的包装(wrapper)函数来创建矢量以节省打字时间。下列命令与上面代码中的命令是等价的:
numeric(5)
## [1] 0 0 0 0 0
complex(5)
## [1] 0+0i 0+0i 0+0i 0+0i 0+0i
logical(5)
## [1] FALSE FALSE FALSE FALSE FALSE
character(5)
## [1] "" "" "" "" ""
注意
在下一章中我们将看到,
list
函数的工作方式与它们不一样。list(5)
创建的内容有所不同。
4.2.1 序列
除了冒号运算符之外,还有几个其他函数能创建更为通用的序列。其中,seq
函数最常见,能以许多不同的方式指定序列。然而在实际中,你不需要调用它,因为有三个专门的序列函数,运行更快且更易用,满足了特定场合的使用。
seq.int
可创建一个序列,序列的范围由两个数字指定。只需两个参数,原理与冒号运算符完全相同:
seq.int(3, 12) #与3:12相同
## [1] 3 4 5 6 7 8 9 10 11 12
seq.int
稍微比:
更通用些,因为它可以指定步长:
seq.int(3, 12, 2)
## [1] 3 5 7 9 11
seq.int(0.1, 0.01, -0.01)
## [1] 0.10 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01
因为seq_len
函数将创建一个从1到它的输入值的序列,所以用seq_len(5)
来表达1:5
有些笨拙。不过,当输入值为零时,该函数非常有用:
n <- 0
1:n #和你预期的可能不一样!
## [1] 1 0
seq_len(n)
## integer(0)
seq_along
创建一个从1开始、长度为其输入值的序列:
pp <- c("Peter", "Piper", "picked", "a", "peck", "of", "pickled", "peppers")
for(i in seq_along(pp)) print(pp[i])
## [1] "Peter"
## [1] "Piper"
## [1] "picked"
## [1] "a"
## [1] "peck"
## [1] "of"
## [1] "pickled"
## [1] "peppers"
在以上的每一个例子中,你都可以简单地用seq
替换seq.int
、seq_len
或seq_along
,得到的结果相同,虽然这样做并无必要。
4.2.2 长度
我们刚才已经悄悄地引入了一个关于向量的新概念:所有的向量都有一个长度,它告诉我们向量包含多少个元素。这是一个非负整数1(是的,向量的长度可以为零),你可以通过length
函数查到这个值。缺失值也会被计入长度:
1 在32位的系统以及3.0.0之前版本的R中,长度被限制为2^31-1
个元素。
length(1:5)
## [1] 5
length(c(TRUE, FALSE, NA))
## [1] 3
容易造成混淆的地方是字符向量。它们的长度为字符串的数目,而非每个字符串中字符数的长度。对此,我们使用nchar
:
sn <- c("Sheena", "leads", "Sheila", "needs")
length(sn)
## [1] 4
nchar(sn)
## [1] 6 5 6 5
我们也可以为向量重新分配一个长度,不过很少这么做,且几近意味着糟糕的代码。例如,如果向量的长度缩短,那么后面的值将会被删除;而如果长度增加,则缺失值会添加到最后:
poincare <- c(1, 0, 0, 0, 2, 0, 2, 0) #请参见:http://oeis.org/A051629
length(poincare) <- 3
poincare
## [1] 1 0 0
length(poincare) <- 8
poincare
## [1] 1 0 0 NA NA NA NA NA
4.2.3 命名
R向量的一大特性是能给每个元素命名。通常,标记元素可使代码可读性更强。你可以使用name = value
的形式在创建向量时为其指定名称。如果元素的名称是有效的,则无需被引号括起来。你也可以只命名向量中的某些元素而忽略其他元素:
c(apple = 1, banana = 2, "kiwi fruit" = 3, 4)
## apple banana kiwi fruit
## 1 2 3 4
你也可以在向量创建后用names
函数为元素添加名字:
x <- 1:4
names(x) <- c("apple", "bananas", "kiwi fruit", "")
x
## apple bananas kiwi fruit
## 1 2 3 4
此name
函数也可用于取得向量的名称:
names(x)
## [1] "apple" "bananas" "kiwi fruit" ""
如果向量中没有一个元素有名字,则names
函数返回NULL
:
names(1:4)
## NULL
4.2.4 索引向量
通常,我们只要访问向量中的部分或个别元素。这就是所谓的索引,它用方括号[]
来实现。(有人也称之为子集、下标或切片,这些术语所指相同。)R系统非常灵活,提供如下多种索引方法。
- 给向量传入正数,它会返回此位置上的向量元素切片。它的第一个位置是1 (而不像其他某些语言一样是0) 。
- 给向量传入负数,它会返回一个向量切片,它将包含除了这些位置以外的所有元素。
- 给向量传入一个逻辑向量,它会返回一个向量切片,里面只包含索引为
TRUE
的元素。 - 对于已命名的向量,给向量传入命名的字符向量,将会返回向量中包含这些名字的元素切片。
请看以下向量:
x <- (1:5) ^ 2
## [1] 1 4 9 16 25
以下三个索引方法都将返回相同的值:
x[c(1, 3, 5)]
x[c(-2, -4)]
x[c(TRUE, FALSE, TRUE, FALSE, TRUE)]
## [1] 1 9 25
如果给每个元素命名,以下方法也将返回相同的值:
names(x) <- c("one", "four", "nine", "sixteen", "twenty five")
x[c("one", "nine", "twenty five")]
## one nine twenty five
## 1 9 25
混合使用正负值是不允许的,会抛出一个错误:
x[c(1, -1)] #这说不通!
## Error: only 0's may be mixed with negative subscripts
如果你使用正数或逻辑值作为下标,那么缺失索引所对应的值同样也是缺失值:
x[c(1, NA, 5)]
## one <NA> twenty five
## 1 NA 25
x[c(TRUE, FALSE, NA, FALSE, TRUE)]
## one <NA> twenty five
## 1 NA 25
对于负的下标值来说,不允许存在缺失值,会产生错误:
x[c(-2, NA)] #这也讲不通!
## Error: only 0's may be mixed with negative subscripts
超出范围的下标值(即超出了矢量的长度)不会导致错误,而是返回缺失值NA
。在实际中,最好确保你的下标值都在使用范围内:
x[6]
## <NA>
## NA
非整数下标会默认向零舍入。这是另一个R被认为过于宽松的证例。如果你传入的下标是分数,那么很可能你正在写一些糟糕的代码:
x[1.9] #1.9 舍入为 1
## one
## 1
x[-1.9] #-1.9 舍入为-1
## four nine sixteen twenty five
## 4 9 16 25
不传递任何下标值将返回整个向量。不过再次提醒,如果你没有传递任何索引值,那么很可能你正在做一些不靠谱的事情:
x[]
## one four nine sixteen twenty five
## 1 4 9 16 25
which
函数将返回逻辑向量中为TRUE
的位置。如果要将逻辑索引切换到整数索引中,这个函数很有用:
which(x > 10)
## sixteen twenty five
## 4 5
which.min
和which.max
分别是which(min(x))
和which(max(x))
的简写:
which.min(x)
## one
## 1
which.max(x)
## twenty five
## 5
4.2.5 向量循环和重复
到目前为止,所有相加在一起的向量都具有相同的长度。你可能会问:“当我对不同长度的向量做运算,结果会如何?”
如果我们把一个单独的数字与向量相加,则向量的每个元素都会与该数字相加:
1:5 + 1
## [1] 2 3 4 5 6
1 + 1:5
## [1] 2 3 4 5 6
将两个向量相加时,R将会循环较短向量中的元素以配合较长的那个:
1:5 + 1:15
## [1] 2 4 6 8 10 7 9 11 13 15 12 14 16 18 20
如果长向量的长度不是短向量长度的倍数,将出现一个警告:
1:5 + 1:7
## Warning: longer object length is not a multiple of shorter object length
## [1] 2 4 6 8 10 7 9
必须强调的是,虽然我们可以在不同长度的向量之间做运算,但这并不意味着应该这样做。为向量添加一个标量值没有问题,但我们会在其他方面把自己搞晕。更好的做法是明确地创建同等长度的向量,然后再对它们进行操作。
rep
函数非常适合此类任务,它允许我们重复使用元素来创建矢量:
rep(1:5, 3)
## [1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
rep(1:5, each = 3)
## [1] 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5
rep(1:5, times = 1:5)
## [1] 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5
rep(1:5, length.out = 7)
## [1] 1 2 3 4 5 1 2
正如seq
函数一样,rep
有一个更为简单和快速的变体rep.int
:
rep.int(1:5, 3) #与rep(1:5, 3)一样
## [1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
类似seq_len
,在最近的R版本(从v3.0.0开始)中也有rep_len
函数,可指定输出向量的长度:
rep_len(1:5, 13)
## [1] 1 2 3 4 5 1 2 3 4 5 1 2 3