軌道
/
R
R
/
課程大綱
/
向量篩選
向量

向量篩選 在 R

3 個練習

關於 向量篩選

我們在 Vectors概念中看過,向量可以用在條件運算式裡,產生一個邏輯向量。 反過來,這種結果也能用在像 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

這個技巧的威力遠不只如此。

向量子集

想要取出向量中特定的元素,可以用索引編號,或是一組索引向量:

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

或者,用邏輯向量來篩選原本的向量,回傳其中對應到TRUE值的元素子集:

v <- 1:3
bools <- c(FALSE, TRUE, TRUE)
v[bools]
#> [1] 2 3

從這裡再跨一小步,就能用條件運算式產生布林向量:

bools <- v >= 2
bools
#> [1] FALSE  TRUE  TRUE

v[bools]
#> [1] 2 3

# simpler form
v[v >= 2]
#> [1] 2 3

這些條件運算式可以任意複雜,牽涉多個向量或函式:

v <- 1:10
w <- 10:1

# pairwise comparison
v > w
#> [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE

# shorter form
v[v > w]
#> [1]  6  7  8  9 10

命名

我們把這個概念命名為「向量篩選」,希望這樣能讓最多數的程式設計師一看就懂。

在 R 社群裡,「子集選取」這個說法可能更常見。

循環

為了簡單起見,上面的例子比較的向量長度都相同。 如果長度不一致會怎樣?

刻意使用時威力強大,但出乎意料時則令人困惑。

舉個例子:

v <- 1:6
cond <- c(TRUE, FALSE)
v[cond]
#> [1] 1 3 5

這裡發生了什麼事? 我們用長度 2 的布林向量去索引長度 6 的向量,結果卻得到長度 3 的向量。

如果某個向量對它所在的運算式來說「太短」,R 會把它重複到所需長度為止:這就叫做「循環」。 這會把我們的c(TRUE, FALSE)向量變成c(TRUE, FALSE, TRUE, FALSE, TRUE, FALSE),接著v[cond]會回傳v中值為TRUE的元素:在這個例子裡就是奇數。

那麼下一個例子又是怎麼回事?

v <- 1:3
0.5 * v
#> [1] 0.5 1.0 1.5
2 + v
#> [1] 3 4 5

乍看之下像是純量乘法,以及(有點奇怪的)純量加法,但 R 裡根本沒有純量。

實際上,這些數字會被循環,以得到與v長度相符的向量,然後算術運算會用c(0.5, 0.5, 0.5)或c(2, 2, 2)逐元素套用。

Caution

循環非常、非常有用,但要確定這真的是你想要的。

向量長度只要稍微對不上(例如 99 對上 100),就可能造成令人困惑的 bug。

有些作者建議,只有當其中一個向量的長度為 1 時,才使用循環。

找出索引

which()函式接受一個布林引數,並回傳會得到TRUE的索引向量。

v
#> [1] 2 7 9

v[v > 5]  # returns values
#> [1]  7  9

which(v > 5) # returns indices
#> [1] 2 3

檢查元素是否存在

前面幾節談的是找出符合某個條件的元素。

如果你只想知道向量裡有沒有某個特定元素,可以使用 %in%運算子。

3 %in% 1:5
#> [1] TRUE
7 %in% 1:5
#> [1] FALSE

這在功能上等同於下面這段程式碼,但方便得多:

length(v[v == 3]) > 0
#> [1] TRUE

另外還有%notin%運算子,它會回傳%in%的邏輯not。

透過 GitHub 編輯 連結會在新視窗或分頁中開啟

學習 向量篩選

練習已鎖定

再解鎖 2 個練習,就能練習 向量篩選