3.8. Векторизованные вычисления
Несмотря на то, что R похож на многие современные скриптовые языки программирования, например, такие, как Perl и Python, в нём есть много своеобразного. Одна из интересных и очень полезных особенностей R — это, так называемые, векторизованные вычисления. Использовать их очень просто. Допустим, мы хотим перевести вес из килограммов в граммы:
> w*1000
Коля Женя Петя Саша Катя Вася Жора
69000 68000 93000 87000 59000 82000 72000
Для такой операции часто требуется использовать циклические конструкции (loops), а здесь всё получается в одно действие. Конечно, в R циклы тоже будут работать:
> for (i in seq_along(w)) {
+ w[i] <- w[i] * 1000
+ }
> w
Коля Женя Петя Саша Катя Вася Жора
69000 68000 93000 87000 59000 82000 72000
Но это уж слишком громоздко. Векторизованы и операции между векторами и матрицам
> ma + mb
b1 b2
a1 2 5
a2 5 8
> 1:8 + 1:2
[1] 2 4 4 6 6 8 8 10
В последнем примере второй вектор гораздо короче первого, поэтому при вычислении результата он был несколько раз повторен. Так будет и в том случае, если длина меньшего вектора (матрицы) не кратна длине большего, но тогда R выдаст предупреждение. Помимо простых арифметических операций, векторизованы и более сложные преобразования. Есть целое семейство функций, которые специализируются на векторизованных вычислениях: apply(), by(), lapply(), sapply(), tapply() и другие. Вот как работает, например, функция apply():
> apply(trees, 2, mean)
Girth Height Volume
13.24839 76.00000 30.17097
Двойка во втором аргументе означает, что среднее (mean()) вычисляется для каждой колонки данных. Для строк надо поставить единицу, но в данном случае это лишено смысла, потому что разные колонки относятся к измерениям разной природы. А вот так при помощи sapply() можно преобразовать наши данные в «кодированный», цифровой вид:
> sapply(d, as.numeric)
Weight height size sex
[1,] 69 174 3 2
[2,] 68 162 1 1
[3,] 93 188 4 2
[4,] 87 192 5 2
[5,] 59 165 1 1
[6,] 82 168 2 2
[7,] 72 172 3 2
tapply() и by() позволяют сделать ещё хитрее:
> by(d[,1:2], d$sex, mean)
d$sex: female
weight height
63.5 163.5
------------------------------------------------------------
d$sex: male
weight height
80.6 178.8
Мы вычислили средний рост и вес для мужчин и женщин за одно действие! Наконец, lapply() позволяет применить некую команду к каждому элементу списка:
> lapply(d, is.factor)
$weight
[1] FALSE
$height
[1] FALSE
$size
[1] TRUE
$sex
[1] TRUE
