А. Б. Шипунов, Е. М. Балдин, П. А. Волкова, А. И. Коробейников, С. А. Назарова
Скачать 3.04 Mb.
|
(что, как вы помните, увеличивает и ее репрезентативность), а также работать с непрерывными данными. В R интервальные данные представляют в виде числовых векторов (numerical vectors). Чаще всего один вектор — это одна выборка. Допус- тим, у нас есть данные о росте семи сотрудников небольшой компании. Вот так можно создать из этих данных простейший числовой вектор: > x <- c(174, 162, 188, 192, 165, 168, 172.5) x — это имя объекта R, «<-» — функция присвоения, c() — функ- ция создания вектора (от англ. concatenate, собрать). Собственно, R и работает в основном с объектами и функциями. У объекта может быть своя структура: > str(x) num [1:7] 174 162 188 192 165 168 172.5 То есть x — это числовой (num, «numeric») вектор. В R нет так на- зываемых скаляров, «одиночные» объекты трактуются как векторы из одного элемента. Вот так можно проверить, вектор ли перед нами: > is.vector(x) [1] TRUE Вообще говоря, в R есть множество функций «is.что-то()» для подобной проверки, например: > is.numeric(x) [1] TRUE А еще есть функции конверсии «as.что-то()», с которыми мы по- работаем ниже. Называть объекты можно в принципе как угодно, но лучше придерживаться некоторых правил: «Садись, двойка»: шкальные данные 49 1. Использовать для названий только латинские буквы, цифры и точку (имена объектов не должны начинаться с точки или циф- ры). 2. Помнить, что R чувствителен к регистру, X и x — это разные имена. 3. Не давать объектам имена, уже занятые распространенными функ- циями (типа c()), а также ключевыми словами (особенно T, F, NA, NaN , Inf, NULL, а также pi — единственное встроенное в R число). Для создания «искусственных» векторов очень полезен оператор «:», обозначающий интервал, а также функции создания последова- тельностей («sequences») seq() и повторения («replications») rep(). 3.2. «Садись, двойка»: шкальные данные Если интервальные данные можно получить непосредственно (на- пример, посчитать) или при помощи приборов (измерить), то шкальные данные не так просто сопоставить числам. Предположим, нам надо со- ставить, а затем проанализировать данные опросов об удобстве мебели. Ясно, что «удобство» — вещь субъективная, но игнорировать ее нель- зя, надо что-то с ней сделать. Как правило, «что-то» — это шкала, где каждому баллу соответствует определенное описание, которое и вклю- чается в опрос. Кроме того, в такой шкале все баллы часто можно ран- жировать, в нашем случае — от наименее удобной мебели к наиболее удобной. Число, которым обозначено значение шкалы,— вещь более чем услов- ная. По сути, можно взять любое число. Зато есть отношение порядка и, более того, подобие непрерывности. Например, если удобную во всех от- ношениях мебель мы станем обозначать цифрой «5», а несколько менее удобную — цифрой «4», то в принципе можно представить, какая мебель могла бы быть обозначена цифрой «4.5». Именно поэтому к шкальным данным применимы очень многие из тех методов, которые используют- ся для обработки интервальных непрерывных данных. Однако к чис- ловым результатам обработки надо подходить с осторожностью, всегда помнить об условности значений шкалы. Больше всего трудностей возникает, когда данные измерены в раз- ных шкалах. Разные шкалы часто очень нелегко перевести друг в друга. По умолчанию R будет распознавать шкальные данные как обычный числовой вектор. Однако для некоторых задач может потребоваться преобразовать его в так называемый упорядоченный фактор («ordered factor» — см. ниже). Если же стоит задача создать шкальные дан- 50 Типы данных ные из интервальных, то можно воспользоваться функцией cut(..., ordered=TRUE) Для статистического анализа шкальных данных всегда требуются непараметрические методы. Если же хочется применить параметриче- ские методы, то нужно иначе спланировать сбор данных, чтобы в ре- зультате получить интервальные данные. Например, при исследовани- ях размеров листьев не делить их визуально на «маленькие», «средние» и «большие», а измерить их длину и ширину при помощи линейки. Од- нако иногда сбор непрерывных данных требует использования трудно- доступного оборудования и сложных методик (например, если вы ре- шите исследовать окраску цветков как непрерывную переменную, вам понадобится спектрофотометр для измерения длины волны отражен- ного света — количественного выражения видимого цвета). В этом слу- чае можно выйти из положения путем последующего перекодирования данных на стадии их обработки. Например, цвет можно закодировать в значениях красного, зеленого и синего каналов компьютерной цветовой шкалы RGB. Вот еще один пример перекодирования. Предположим, вы изучае- те высоту зданий в различных городах земного шара. Можно в графе «город» написать его название (номинальные данные). Это, конечно, проще всего, но тогда вы не сможете использовать эту переменную в статистическом анализе данных. Можно закодировать города цифрами в порядке их расположения, например с севера на юг (если вас инте- ресует географическая изменчивость высоты зданий в городе),— тогда получатся шкальные данные, которые можно обработать непараметри- ческими методами. И наконец, каждый город можно обозначить его географическими координатами или расстоянием от самого южного го- рода — тогда мы получим интервальные данные, которые можно будет попробовать обработать параметрическими методами. 3.3. Красный, желтый, зеленый: номинальные данные Номинальные данные (их часто называют «категориальными»), в отличие от шкальных, нельзя упорядочивать. Поэтому они еще даль- ше от чисел в строгом смысле слова, чем шкальные данные. Вот, на- пример, пол. Даже если мы присвоим мужскому и женскому полам какие-нибудь числовые значения (например, 1 и 2), то из этого не будет следовать, что какой-то пол «больше» другого. Да и промежуточное значение (1.5) здесь непросто представить. Красный, желтый, зеленый: номинальные данные 51 В принципе, можно обозначать различные номинальные показатели не цифрами, а буквами, целыми словами или специальными значками — суть от этого не изменится. Обычные численные методы для номинальных данных непримени- мы. Однако существуют способы их численной обработки. Самый прос- той — это счет, подсчет количеств данных разного типа в общем массиве данных. Эти количества и производные от них числа уже гораздо легче поддаются обработке. Особый случай как номинальных, так и шкальных данных — би- нарные данные , то есть такие, которые проще всего передать числами 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 52 Типы данных [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 Красный, желтый, зеленый: номинальные данные 53 female male 0 1 2 3 4 5 Рис. 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] 54 Типы данных [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, что перед нами — шкальные данные. Делается это так: Красный, желтый, зеленый: номинальные данные 55 165 170 175 180 185 190 60 65 70 75 80 85 90 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 56 Типы данных > as.numeric(a) # Неправильно! [1] 1 2 3 > as.numeric(as.character(a)) # Правильно! [1] 3 4 5 Когда файл данных загружается при помощи команды read.table(), то все столбцы, где есть хотя бы одно нечисло, будут преобразованы в факторы 1 . Если хочется этого избежать (для того, например, чтобы не столкнуться с вышеописанной проблемой), то нужно задать дополни- тельный параметр: read.table(..., as.is=TRUE). 3.4. Доли, счет и ранги: вторичные данные Из названия ясно, что такие данные возникают в результате обра- ботки первичных, исходных данных. Наибольшее применение вторичные данные находят при обработке шкальных и в особенности номинальных данных, которые нельзя обра- батывать «в лоб». Например, счет («counts») — это просто количество членов какой-либо категории. Такие подсчеты и составляют суть ста- тистики в бытовом смысле этого слова. Проценты (доли, «rates») тоже часто встречаются в быту, так что подробно описывать их, наверное, не нужно. Одно из самых полезных их свойств — они позволяют вычле- нить числовые закономерности там, где исходные данные отличаются по размеру. Для того чтобы визуализировать счет и проценты, придумано нема- ло графических способов. Самые из них распространенные — это, на- верное, графики-пироги и столбчатые диаграммы. Почти любая компью- терная программа, имеющая дело с таблицами данных, умеет строить такие графики. Однако надо заметить, что столбчатые диаграммы и в особенности «пироги» — неудачный способ представления информа- ции. Многочисленные эксперименты доказали, что читаются такие гра- фики гораздо хуже остальных. Самое печальное, что главная задача графиков — показать, где цифры различаются, а где сходны, практи- чески не выполняется. В экспериментах людям предлагали несколько минут смотреть на такие графики, а затем просили расположить груп- пы, отраженные на графике, в порядке значений подсчитанного при- знака. Оказалось, что это нелегко сделать. Вот пример. На рисунке 7 — столбчатый график результатов гадания на ромашках: > romashka.t <- read.table("data/romashka.txt", sep="\t") > romashka <- romashka.t$V2 1 Это верно только для версий R меньше 4. Доли, счет и ранги: вторичные данные 57 > names(romashka) <- romashka.t$V1 > oldpar <- par(mar = c(7, 4, 4, 2) + 0.1) > romashka.plot <- barplot(romashka, names.arg="") > text(romashka.plot, par("usr")[3]-0.25, srt=45, adj=1, + xpd=TRUE, labels=names(romashka)) > par(oldpar) (Пришлось исхитриться, чтобы поместить длинные надписи под стол- биками.) 0 5 10 15 20 лю би т не лю би т пл юн ет по це лу ет к с ер дц у п ри жм ет к ч ер ту по шл ет Рис. 7. Результаты гадания на ромашках (проценты исходов), показан- ные с помощью столбчатой диаграммы Попробуйте проделать тот же эксперимент: посмотреть на график 3–5 минут, а затем закрыть книгу и расположить возможные исходы гадания в порядке убывания, от самого большого значения — к самому маленькому. (Ответ проверьте в конце главы.) Создатели R прекрасно знали об этих проблемах, и поэтому в первых версиях вообще не было команды для рисования «пирогов». На замену им, а также на замену менее сомнительным столбчатым диаграммам 58 Типы данных в R есть так называемые точечные графики (dotplots). Ниже приведен пример такого графика для тех же самых данных по гаданию (рис. 8): > dotchart(romashka) любит не любит плюнет поцелует к сердцу прижмет к черту пошлет 14 16 18 20 22 24 Рис. 8. Результаты гадания на ромашках (проценты исходов), показан- ные с помощью точечного графика Надеемся, что большинство читателей согласятся с нами в том, что точечные диаграммы читаются легче «пирогов». Именно поэтому про- фессионалы рекомендуют точечные графики и боксплоты, а не «пиро- ги» и столбчатые диаграммы. Если счет и доли получают обычно из номинальных данных, то от- ношения и ранги «добывают» из данных количественных. Отношения особенно полезны в тех случаях, когда изучаемые явления или вещи имеют очень разные абсолютные характеристики. Например, вес людей довольно трудно использовать в медицине напрямую, а вот соотноше- ние между ростом и весом очень помогает в диагностике ожирения. Чтобы получить ранги, надо упорядочить данные по возрастанию и заменить каждое значение на номер его места в полученном ряду. Пропущенные данные 59 Например, обычная методика вычисления медианы (см. ниже) осно- вывается на рангах. Ранги особенно широко применяются при анализе шкальных и непараметрических интервальных данных. Ранговые ме- тодики анализа, как правило, устойчивы, но менее чувствительны, чем параметрические. Это и понятно, ведь в процессе присваивания рангов часть информации теряется: > a1 <- c(1,2,3,4,4,5,7,7,7,9,15,17) > a2 <- c(1,2,3,4,5,7,7,7,9,15,17) > names(a1) <- rank(a1) > a1 1 2 3 4.5 4.5 6 8 8 8 10 11 12 1 2 3 4 4 5 7 7 7 9 15 17 > names(a2) <- rank(a2) > a2 1 2 3 4 5 7 7 7 9 10 11 1 2 3 4 5 7 7 7 9 15 17 Как видно, ранги могут быть не целыми, а половинными. Это бы- вает тогда, когда одинаковых чисел четное число. Кроме того, у одина- ковых чисел ранги тоже одинаковые. Это называется «ties», буквально «ничья». Ничья эта несколько мешает при выполнении некоторых ста- тистических операций, например при вычислении непараметрических тестов, основанных на рангах: > wilcox.test(a2) [... результаты теста пропущены ...] Warning message: In wilcox.test.default(a2) : cannot compute exact p-value with ties В этих случаях R всегда сообщает о проблеме. (О самом тесте речь пойдет в следующей главе.) |