Глава 3. Типы данных
3.3. Красный, желтый, зеленый: номинальные данные
ные из интервальных, то можно воспользоваться функцией cut(..., ordered=TRUE).
Для статистического анализа шкальных данных всегда требуются непараметрические методы. Если же хочется применить параметриче- ские методы, то нужно иначе спланировать сбор данных, чтобы в ре- зультате получить интервальные данные. Например, при исследовани- ях размеров листьев не делить их визуально на «маленькие», «средние»
и «большие», а измерить их длину и ширину при помощи линейки. Од- нако иногда сбор непрерывных данных требует использования трудно- доступного оборудования и сложных методик (например, если вы ре- шите исследовать окраску цветков как непрерывную переменную, вам понадобится спектрофотометр для измерения длины волны отражен- ного света — количественного выражения видимого цвета). В этом слу- чае можно выйти из положения путем последующего перекодирования данных на стадии их обработки. Например, цвет можно закодировать в значениях красного, зеленого и синего каналов компьютерной цветовой шкалы RGB.
Вот еще один пример перекодирования. Предположим, вы изучае- те высоту зданий в различных городах земного шара. Можно в графе
«город» написать его название (номинальные данные). Это, конечно, проще всего, но тогда вы не сможете использовать эту переменную в статистическом анализе данных. Можно закодировать города цифрами в порядке их расположения, например с севера на юг (если вас инте- ресует географическая изменчивость высоты зданий в городе),— тогда получатся шкальные данные, которые можно обработать непараметри- ческими методами. И наконец, каждый город можно обозначить его географическими координатами или расстоянием от самого южного го- рода — тогда мы получим интервальные данные, которые можно будет попробовать обработать параметрическими методами.
3.3. Красный, желтый, зеленый: номинальные
В принципе, можно обозначать различные номинальные показатели не цифрами, а буквами, целыми словами или специальными значками — суть от этого не изменится.
Обычные численные методы для номинальных данных непримени- мы. Однако существуют способы их численной обработки. Самый прос- той — это счет, подсчет количеств данных разного типа в общем массиве данных. Эти количества и производные от них числа уже гораздо легче поддаются обработке.
Особый случай как номинальных, так и шкальных данных — би- нарные данные, то есть такие, которые проще всего передать числами 0 и 1. Например, ответы «да» и «нет» на вопросы анкеты. Или на- личие/отсутствие чего-либо. Бинарные данные иногда можно упорядо- чить (скажем, наличие и отсутствие), иногда — нет (скажем, верный и неверный ответы). Можно бинарные данные представить и в виде
«логического вектора», то есть набора значений TRUE или FALSE. Са- мая главная польза от бинарных данных — в том, что в них можно перекодировать практически все остальные типы данных (хотя иногда при этом будет потеряна часть информации). После этого к ним можно применять специальные методы анализа, например логистическую ре- грессию (см. главу о двумерных данных) или бинарные коэффициенты сходства (см. главу о многомерных данных).
Для обозначения номинальных данных вRесть несколько способов, разной степени «правильности». Во-первых, можно создать текстовый (character) вектор:
> sex <- c("male", "female", "male", "male", "female", "male", + "male")
> is.character(sex) [1] TRUE
> is.vector(sex) [1] TRUE
> str(sex)
chr [1:7] "male" "female" "male" "male" "female" "male" ...
Обратите внимание на функциюstr()! Это очень важная функция, мы бы рекомендовали выучить ее одной из первых. На первых порах пользовательR не всегда понимает, с каким типом объекта (вектором, таблицей, списком и т. п.) он имеет дело. Разрешить сомнения помогает str().
Предположим теперь, что sex — это описание пола сотрудников небольшой организации. Вот как R выводит содержимое этого векто- ра:
> sex
[1] "male" "female" "male" "male" "female" "male" "male"
Кстати, пора раскрыть загадку единицы в квадратных скобках — это просто номер элемента вектора. Вот как его можно использовать (да-да, квадратные скобки — это тоже команда, можно этопроверить, набрав помощь ?"["):
> sex[1]
[1] "male"
«Умные», то есть объект-ориентированные, команды R кое-что по- нимают про объект sex, например командаtable():
> table(sex) sex
female male
2 5
А вот команда plot(), увы, не умеет ничего хорошего сделать с таким вектором. Сначала нужно сообщитьR, что этот вектор надо рас- сматривать как фактор (то есть номинальный тип данных). Делается это так:
> sex.f <- factor(sex)
> sex.f
[1] male female male male female male male Levels: female male
И теперь команда plot() уже «понимает», что ей надо делать — строить столбчатую диаграмму (рис. 5):
> plot(sex.f)
Это произошло потому, что перед нами специальный тип объекта, предназначенный для категориальных данных,— фактор с двумя уров- нями (градациями) (levels):
> is.factor(sex.f) [1] TRUE
> is.character(sex.f) [1] FALSE
> str(sex.f)
Factor w/ 2 levels "female","male": 2 1 2 2 1 2 2
female male
012345
Рис. 5. Вот так командаplot()рисует фактор
Очень многие функции R (скажем, тот же самый plot()) предпо- читают факторы текстовым векторам, при этом некоторые умеют кон- вертировать текстовые векторы в факторы, а некоторые — нет, поэтому надо быть внимательным. Еще несколько свойств факторов надо знать заранее. Во-первых, подмножество фактора — это фактор с тем же ко- личеством уровней, даже если их в подмножестве не осталось:
> sex.f[5:6]
[1] female male Levels: female male
> sex.f[6:7]
[1] male male
Levels: female male
«Избавиться» от лишнего уровня можно, применив специальный ар- гумент или выполнив преобразование данных «туда и обратно»:
> sex.f[6:7, drop=TRUE]
[1] male male Levels: male
> factor(as.character(sex.f[6:7])) [1] male male
Levels: male
Во-вторых, факторы (в отличие от текстовых векторов) можно лег- ко преобразовать в числовые значения:
> as.numeric(sex.f) [1] 2 1 2 2 1 2 2
Зачем это нужно, становится понятным, если рассмотреть вот та- кой пример. Положим, кроме роста, у нас есть еще и данные по весу сотрудников:
> w <- c(69, 68, 93, 87, 59, 82, 72)
И мы хотим построить такой график, на котором были бы видны одновременно рост, вес и пол. Вот как это можно сделать (рис. 6):
> plot(x, w, pch=as.numeric(sex.f), col=as.numeric(sex.f))
> legend("topleft", pch=1:2, col=1:2, legend=levels(sex.f)) Тут, разумеется, нужно кое-что объяснить. pch и col — эти пара- метры предназначены для определения соответственно типа значков и их цвета на графике. Таким образом, в зависимости от того, какому полу принадлежит данная точка, она будет изображена кружком или треугольником и черным или красным цветом. При условии, разумеет- ся, что все три вектора соответствуют друг другу. Еще надо отметить, что изображение пола при помощи значка и цвета избыточно, для «нор- мального» графика хватит и одного из этих способов.
В-третьих, факторы можно упорядочивать, превращая их в один из вариантов шкальных данных. Введем четвертую переменную — размер маек для тех же самых гипотетических восьмерых сотрудников:
> m <- c("L", "S", "XL", "XXL", "S", "M", "L")
> m.f <- factor(m)
> m.f
[1] L S XL XXL S M L
Levels: L M S XL XXL
Как видим, уровни расположены просто по алфавиту, а нам надо, чтобы S (small) шел первым. Кроме того, надо как-то сообщить R, что перед нами — шкальные данные. Делается это так:
●
●
165 170 175 180 185 190
60657075808590
● female male
Рис. 6. График, показывающий одновременно три переменные
> m.o <- ordered(m.f, levels=c("S", "M", "L", "XL", "XXL"))
> m.o
[1] L S XL XXL S M L
Levels: S < M < L < XL < XXL
Теперь R«знает», какой размер больше. Это может сыграть крити- ческую роль — например, при вычислениях коэффициентов корреля- ции.
Работая с факторами, нужно помнить и об одной опасности. Если возникла необходимость перевести фактор в числа, то вместо значений вектора мы получим числа, соответствующие уровням фактора! Чтобы этого не случилось, надо сначала преобразовать фактор, состоящий из значений-чисел, в текстовый вектор, а уже потом — в числовой:
> a <- factor(3:5)
> a
[1] 3 4 5 Levels: 3 4 5
> as.numeric(a) # Неправильно!
[1] 1 2 3
> as.numeric(as.character(a)) # Правильно!
[1] 3 4 5
Когда файл данных загружается при помощи командыread.table(), то все столбцы, где есть хотя бы одно нечисло, будут преобразованы в факторы. Если хочется этого избежать (для того, например, чтобы не столкнуться с вышеописанной проблемой), то нужно задать дополни- тельный параметр:read.table(..., as.is=TRUE).