А.Б.Шипунов1

$n+1$ вопрос про \R

n+1 вопрос про R


Шипунов А.Б. n+1 вопрос про R [Электронный ресурс]. 2002. Режим доступа:
http://herba.msu.ru/shipunov/software/r/rplus1.htm


Shipunov A.B. n+1 question about R [Electronic resource]. 2002. Mode of access:
http://herba.msu.ru/shipunov/software/r/rplus1.htm



Эта статья не претендует на обучение основам статистики. Автор рассчитывает на читателя, более или менее знакомого с основными понятиями теории вероятностей и математической статистики. Такой читатель может научиться делать то, о чем он читал в руководствах, при помощи R.

1  Для чего надо обрабатывать данные?

Статистический анализ начинается с (1) постановки проблемы, продолжается (2) сбором данных, производится при помощи (3) обработки, и завершается (4) выводами. Здесь мы рассмотрим только третий этап. Нужно помнить, однако, что ``формулировка проблемы более важна, чем ее решение, которое является всего лишь математической или экспериментальной задачей'' (А. Эйнштейн).

Данные обрабатывают для того, чтобы извлечь из них информацию, недоступную ``невооруженному глазу''. Такая информация может быть очень различной, но чаще всего от обработки ожидают следующих результатов:

  1. преобразования данных (сортировки, группировки, слияния и т.п.), такое преобразование может существенно прояснить картину;
  2. выяснения общих характеристик данных (например, среднего и медианы);
  3. выяснения идентичности или неидентичности разных данных (говоря языком статистики, выяснения, с какой вероятностью данные принадлежат одной генеральной совокупности);
  4. выяснения взаимосвязей - от простых корреляций до уравнений регрессии, трендов и даже предсказания событий;
  5. выяснения структуры данных, например, классификации и ординации.

2  Каким образом можно обрабатывать данные?

Самый простой способ - обрабатывать вручную или с помощью микрокалькулятора. Так и поступали до наступления эпохи компьютеров.

Способ посложнее - воспользоваться программами общего назначения, например, Excel. Однако реализация статистических функций в таких пакетах оставляет желать лучшего.

Самый сложный способ - научиться пользоваться специализированными статистическими программами. Таковых существует два сорта: (1) программы с интерфейсом меню и кнопок (SPSS, STATISTICA, MiniTab, StatGraphics) и (2) программы, общающиеся с пользователем в режиме команд (SAS, S-PLUS и R).

3  Что такое R и зачем он нужен?

В начале 90-х годов в Bell Labs (там, где в свое время придумали Unix и C) изобрели язык, специально предназначенный для обработки данных. Этот язык назвали S. Затем фирма MathSoft, Inc. на основе этого языка разработала программу S-PLUS, которая успешно существует и по сей день (надо сказать, что статистические пакеты - долгожители компьютерного мира, например, SPSS развивается уже больше 30 лет!). В 1997 году группа энтузиастов задумала создать программу, аналогичную S-PLUS, но свободно распространяемую. Так появился R.

R - это среда для статистической обработки информации. ``Среда'' означает не просто набор программ, но и цельный, очень развитый язык программирования высокого уровня, который позволяет быстро и с удобством производить различные вычисления. Например, Вам нужно посчитать среднее для некоторой выборки (назовем ее x). R делает это в одно действие2:

> x                     # посмотрим, что это за выборка
> [1] 1 2 3 4 5 6 7 8 9 # вот она
> mean(x)               # посчитаем среднее
> [1] 5                 # а вот и ответ

В общем-то, среднее для этой выборки можно посчитать и в уме. Но R позволяет подсчитывать гораздо более сложные вещи, такие как, например, вейвлет-преобразования, главные компоненты, дискриминантные функции и т.п. Это значит, что его можно использовать вместо широко употребляемых биологами программ для статистической обработки данных типа STATISTICA. Более того, по нашему мнению, это нужно делать. Вот несколько причин:

  1. R, как и его родоначальник, язык S, является единственным языком, созданным специально для работы с данными. За годы существования ими накоплен гигантский запас методов и приемов обработки данных практически на все случаи жизни. Если в STATISTICA или SPSS не реализована какая-то функция, ее почти наверняка можно найти в R.
  2. R поддерживается коллективом специалистов-статистиков, а это значит, что любая новая статистическая методика гораздо быстрее появится в качестве функции для R, нежели для всех остальных программ. Это значит также, что он тщательно оттестирован и практически не содержит столь характерных для многих статистических программ (прежде всего для STATISTICA) упрощений и ошибок, а вновь найденные устраняются практически мгновенно.
  3. R относится к свободному программному обеспечению. Любой пользователь может использовать R бесплатно, скачав версию для своего компьютера непосредственно с Web-сайта программы
    http://www.r-project.org.
  4. На любой вопрос по R, заданный в одном из листов рассылки, в кратчайшие сроки можно получить квалифицированный ответ одного из ведущих в данной области специалистов.

С другой стороны, хотя R и превосходно документирован, работа в нем происходит через так называемый ``интерфейс командной строки'', а привычные большинству пользователей кнопки и выпадающие меню практически отсутствуют.

Но сила R там же, где его ``слабость''. Интерфейс командной строки позволяет делать такие вещи, которых рядовой пользователь других статистических программ может достичь только часами ручного труда. Вот, например, простая задача: требуется превратить выборку x (см. выше) в матрицу из трех колонок (допустим, это были данные за 3 дня, а каждый день делалось 3 измерения). Чтобы сделать это в STATISTICA, требуется: (1) учредить две новые переменные, (2-3) скопировать дважды кусок выборки в буфер, (4-5) скопировать его в одну и другую переменную и (6) уничтожить лишние строки. В R это делается так:

> b <- matrix(x, ncol=3)        # применим команду matrix()
> b                             # посмотрим, что вышло
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

4  Как работать в R?

Вся работа в R происходит посредством команд. Команды вводятся вручную, но если какая-нибудь уже была введена раньше, то к ней всегда можно вернуться, нажав на клавиши со стрелками вверх (или вниз). Все команды имеют аргумент(ы), которые помещаются в круглые скобки. Даже команда выхода q() пишется с такими скобками.

Команды работают с объектами. Объекты могут относиться к самым различным типам, хотя б\'ольшая их часть по своей структуре бывает: (1) вектором (vector, factor), (2) матрицей (matrix, array), (3) перечнем (list), (4) таблицей данных (data.frame). С каждым объектом R обращается по-своему. Например, команда summary(), работает с любым типом объекта, но для каждого имеет особенный вывод.

Самый простой способ использования R - это арифметические вычисления. Например, выражение log(((sqrt(sum(c(2,2))))^2)*2.5) вычисляется так:

  1. Из двух двоек создается вектор - c(2,2)
  2. Подсчитывается сумма его членов - 2+2=4
  3. Извлекается квадратный корень - sqrt(4)=2
  4. Он возводится в квадрат - 2^2=4
  5. Результат умножается на 2,5 - 4*2.5=10
  6. Вычисляется десятичный логарифм - log(10)=1

Как видите, круглые скобки можно вкладывать друг в друга. R раскрывает их, вычисляя значение ``изнутри наружу''.

Ясно также, для чего нужны сами круглые скобки. В них, как правило, пишутся аргументы команды. Этих аргументов может быть очень много, и один из самых простых способов узнать, какие той или иной команде требуются аргументы, это ввести команду args(команда). Например, команда round (``округлить'') имеет два аргумента: число, которое нужно округлить, и значение digits, сообщающее, до какого знака округлять. Система аргументов работает разумно, так что все равно, чт\'о написать:

> round(1.5, digits=0)
[1] 2
> round(1.5, d=0)
[1] 2
> round(d=0, 1.5)
[1] 2
> round(1.5, 0)
[1] 2
> round(1.5,)
[1] 2
> round(1.5)
[1] 2

Это происходит благодаря тому, что есть так называемые ``умалчиваемые'' значения аргументов. Нарпимер, в данном случае умалчиваемое значение аргумента digits - ``0''. Об этом говорит и результат вывода команды args():

> args(round)
> function (x, digits = 0)

Можно заметить также, что некоторые аргументы имеют имена. В результате аргументы можно вызывать не по порядку, а по именам. Имена же можно сокращать вплоть до одной буквы, но только если нет разных аргументов, которые от такого сокращения станут неразличимы. Можно вызывать аргументы по порядку, через запятую3, и тогда разрешается не использовать имен.

Если Вы не знаете, как работает та или иная команда, надо вызвать помощь:

> help(rep)

или

> ?rep

Справочные файлы написаны очень хорошо (конечно, на английском языке) и почти всегда содержат примеры, которые можно ``запустить'' командой example().

Как получить объекты, описано в следующем разделе. Очень полезны команды ls() и rm(), которые нужны для того, чтобы просматривать и удалять существующие в памяти компьютера объекты4.

5  Как набрать данные?

Сначала о том, как это сделать прямо в R. Можно, например, использовать команду c():

> a <- c(1,2,3,4,5)
> a
[1] 1 2 3 4 5

Здесь мы получаем объект a, состоящий из чисел от одного до пяти.

Можно использовать команды rep(), seq(), scan(), а также оператор двоеточия:

> b <- 1:5
> b
[1] 1 2 3 4 5

Можно воспользоваться встроенной в R подпрограммой - электронной таблицей наподобие сильно упрощенного Excel:

> data.entry(b)

В этой таблице можно редактировать данные ``на месте'', то есть вс\"е, что Вы ввели, непосредственно скажется на содержании объекта. Это несколько противоречит общем концепциям, заложенным в R, и поэтому есть функция de(), которая не меняет объект, а выдает результат ``наружу''(как list). Если же у Вас уже есть таблица данных, можно использовать команды fix() или edit(), которые в данном случае вызовут тот же Excel-подобный редактор.

Функция edit(), вызванная для другого типа объекта, запустит его редактирование в текстовом редакторе (под Windows это обычно Notepad или Блокнот), и Вы можете отредактировать объект там. Если Вы хотите поменять редактор, напишите, например:

> options(editor="c:\\Program Files\\quickpad\\quickpad")

Однако лучше всего научиться загружать в R файлы, созданные при помощи других программ, скажем, при помощи Excel. Предположим, Вы работаете с файлом электронной таблицы, который содержит в первой строке названия переменных. Тогда надо:

После этого можно прочитать файл из R следующей командой:

> myfile <- read.table(file="myfile.dat", header=TRUE, sep=";")

Вы получаете объект myfile, который является таблицей данных. Имена переменных (их можно получить командой names(myfile)) берутся при этом из первой строки файла. Объект myfile похож на содержимое электронной таблицы (это можно увидеть, набрав в командной строке его название), но не хранит дополнительных данных7, например, о том, что означают те или иные переменные. Поэтому рекомендуется завести еще один файл, который будет содержать необходимые пояснения. Другой вариант - помещать необходимые комментарии в первых строчках файла после знака #, команда read.table() пропустит такие строки.

Если исходный файл будет устроен по-другому (например, без имен переменных), нужно лишь немного поменять значения аргументов. Главное, чтобы Ваш файл был текстовым и чтобы в нем присутствовали разделители везде, кроме концов строк. Обратите внимание, что такой файл можно получить в любом текстовом редакторе, а не только в программах для создания электронных таблиц.

Суммируя, можно сказать, что один из возможных способов работы с данными в R такой:

  1. данные набирают в какой-нибудь ``внешней'' программе,
  2. записывают их в текстовый файл с разделителями (см. выше),
  3. загружают как объект в R и работают с ним, возможно, внося изменения,
  4. если были изменения, командой write.table() записывают обратно в файл,
  5. импортируют как текстовый файл в исходную программу и работают дальше, и т.д.

Такой способ несколько сложен, но позволяет использовать все преимущества программ по набору электронных таблиц и текстовых редакторов. Можно, конечно, поступить проще и вообще не использовать ничего, кроме R. Тогда есть два пути сохранения объекта между сессиями: либо (1) записывать его в виде текстового файла (см. выше), либо (2) сохранять как бинарный файл R. Второе требует использования либо команды save(), либо команды save.image(), причем последняя сохранит все объекты, накопленные Вами к текущему моменту8. Учтите, что бинарный файл проще сохранить и быстрее загрузить (командой load()), но его нельзя прочитать из других программ, а размер его значительно больше, чем у текстового файла.

Удобно принять соглашение, по которому все текстовые файлы данных, годные для загрузки в R, должны оканчиваться на *.dat, а бинарные файлы R должны оканчиваться на *.rd. Сразу скажем, что программы на языке R записываются в текстовые файлы, оканчивающиеся просто на *.r (а загружаются они командой source()).

6  Как преобразовывать исходные данные?

Очень важная часть работы со статистическими данными заключается в преобразовании данных с целью обработки только какой-нибудь их части. Например, у нас есть файл carex.dat, устроенный следующим образом (пример создан искусственно):

SPECIES LENGTH WIDTH
aqu     3.1    1.3
aqu     3.2    1.5
sal     2.5    NA
rec     2.4    0.3
aqu     2.3    0.1
sal     2.1    0.8
sal     2.9    1.4

Допустим, мы хотим получить для обработки данные только по тем осокам, которые относятся к виду ``aqu'' (Carex aquatilis). Как это сделать?

> setwd("e:\\temp")                     # (1)
NULL
> carex <- read.table("carex.dat",h=T)  # (2)
> car.aqu <- carex[carex[,1]=="aqu",]   # (3)
> car.aqu                               # (4)
  SPECIES LENGTH WIDTH
1     aqu    3.1   1.3
2     aqu    3.2   1.5
5     aqu    2.3   0.1

Сначала (1) мы установили рабочую директорию, то есть директорию, в которой находится наш файл, затем (2) загрузили сам файл. Обратите внимание, что названия команд сокращены, а разделитель не указан, потому что по умолчанию он является пробелом. Получился объект (таблица данных) carex. Затем мы написали команду (3), которая означает:

создать объект car.aqu и поместить в него (<-) те строки из carex (carex[...,]), у которых в первой колонке (carex[,1]) есть строка ``aqu'' (==äqu")

Команда (4) вывела содержание объекта car.aqu. Мы познакомились сразу с двумя типами выборок: числовыми и логическими. Числовая выборка - это, например, команда carex[,1], которая означает ``первая колонка таблицы carex''. Логическая - это команда carex[,1]==äqu". Если выполнить ее саму по себе, то получится:

> carex[,1]=="aqu"
[1] TRUE TRUE FALSE FALSE TRUE FALSE FALSE

Мы получили ответ на вопрос: для каких строк верно, что в первой колонке написано ``aqu''? Ответ такой: ``для первой, второй и пятой''. Можно было бы написать:

> car.aqu <- carex[c(TRUE,TRUE,FALSE,FALSE,TRUE,FALSE,FALSE),]
> car.aqu
  SPECIES LENGTH WIDTH
1     aqu    3.1   1.3
2     aqu    3.2   1.5
5     aqu    2.3   0.1

и получить тот же результат. Теперь попробуйте представить, что мы получим, если введем команду:

> carex[carex[,2]>2.7,]

Это будут те строки, значение второй переменной для которых больше 2,7. Ту же команду можно было записать по-другому:

> carex[carex$LENGTH>2.7,]
  SPECIES LENGTH WIDTH
1     aqu    3.1   1.3
2     aqu    3.2   1.5
7     sal    2.9   1.4

Еще одно применение таких преобразований состоит в том, что можно с легкостью заменить любые данные, опираясь на их логический или числовой ``адрес'':

> car.m <- car.aqu[,-1] # убираем колонку 1
> car.m <- as.matrix(car.m) # преобразуем таблицу в матрицу
> car.m
  LENGTH WIDTH
1    3.1   1.3
2    3.2   1.5
5    2.3   0.1
> car.m[car.m>2] <- 1000 # заменяем числа, большие 2, на 1000
> car.m
  LENGTH WIDTH
1   1000   1.3
2   1000   1.5
5   1000   0.1

Заметим, что преобразовывать таблицу данных в матрицу следует, когда возникает нужда в подобных операциях замены. При этом нужно помнить, что матрица отличается от таблицы данных, в частности, тем, что ее столбцы должны иметь одинаковую природу - не могут сочетаться колонки, состоящие из цифр (numeric) и колонки, состоящие из букв (character). Обойти такой запрет можно, обрабатывая переменные по одной:

> car.aqu -> car.aqu.save
> car.aqu$LENGTH[car.aqu$LENGTH>2] <- 1000 # (1)
> car.aqu
  SPECIES LENGTH WIDTH
1     aqu   1000   1.3
2     aqu   1000   1.5
3     sal   1000   1.4
> car.aqu <- car.aqu.save # восстанавливаем сохраненное
> car.aqu[[2]][car.aqu[[2]]>2] <- 1000 # то же, что (1)
> car.aqu
  SPECIES LENGTH WIDTH
1     aqu   1000   1.3
2     aqu   1000   1.5
3     sal   1000   1.4
> car.aqu <- car.aqu.save
> len <- car.aqu$LENGTH # еще один вариант
> len[len>2] <- 1000
> car.aqu$LENGTH <- len
> car.aqu
  SPECIES LENGTH WIDTH
1     aqu   1000   1.3
2     aqu   1000   1.5
3     sal   1000   1.4
> rm(len)

7  Как начать работу с данными?

В начале надо выяснить несколько вопросов:

Первый вопрос наиболее важен - от его решения зависит весь стиль работы. В общем случае, статистические данные могут быть трех различных типов:

Непрерывные данные,
например, длина, вес, и даже цвет, если он измерен в длине отражаемой волны. Такие данные соотвествуют действительным числам и могут обрабатываться всем арсеналом статистических методик, первоначально разрабатывавшихся именно для непрерывных данных.
Дискретные данные,
которые кодированы целыми (как правило, натуральными) числами. Это может быть, например, возраст в годах, наличие или отсутствие некоего признака, цвет, кодированный целыми числами в порядке ``радуги'' и т.п. Главный признак таких данных - возможность расположить их числовой прямой. К этим данным также применимы основные статистические методики, рассчитанные на работу с ненормально (не-гауссово) распределенными выборками.
Категориальные данные,
или, как их называют в R, факторы также могут быть кодированы числами, но обычно представляют собой строки текста. Их нельзя положить на числовую прямую. Категориальными могут быть, например, географический регион сбора, расположение тычинок в один или в два круга, номер популяции и т.п. Для обработки категориальных данных нелья применять те методы статистики, которые рассчитаны на простую арифметику! Иначе может получиться бессмыслица наподобие ``среднего значения почтового индекса''.

Второй вопрос особенно важен для многомерных методик. Нельзя (за редким исключением некоторых методов вычисления сходства) одновременно работать с данными, измеренными в разных единицах! Если в таблице присутствуют и метры, и килограммы, обычные многомерные статистические методы (типа анализа главных компонент) не годятся9.

Третий вопрос особенно важен в тех случаях, когда предполагается использовать так называемые параметрические методы. Эти методы рассчитаны на то, что данные имеют нормальное (гауссово) распределение10, а иногда (как базовый t-тест или дискриминантный анализ) еще и на то, что разброс (варианса) сравниваемых выборок одинаковы. Понятно, что ни дискретные, ни тем более категориальные данные не попадают в сферу параметрической статистики. С другой стороны, существуют и активно развиваются непараметрические методы, например, ранговые статистики, многомерное шкалирование, бутстреп и т.д. Поэтому данные надо обязательно проверить ``на нормальность''!

Четвертый вопрос также очень важен. Выбросы (данные, сильно отклоняющиеся от общей массы), пропущенные значения (``пустые клетки'') и просто опечатки могут коренным образом исказить результаты анализа. Чтобы этого не произошло, нужно обязательно выяснить структуру анализируемого в R объекта и посчитать базовые статистики.

Структура выясняется командой str(). Ее вывод обычно позволяет понять, в каком режиме будут обрабатываться переменные. Нарпимер, если переменная LENGTH выдается как factor - что-то не в порядке, и нужно обязательно выяснить, нет ли опечаток в тексте файла (скажем, один случайно набранный дефис может привести к тому, что вся колонка будет трактоваться как фактор).

Базовыми, или описательными, статистиками называют обычно общие характеристики данных, например, среднюю величину. Разумеется, в R существуют для этого специальные функции:

> mean(carex[,2]) # среднее
[1] 2.642857
> median(carex[,2]) # медиана
[1] 2.5
> mean(carex[,3]) # не получается!
[1] NA
> mean(carex[,3], na.rm=TRUE) # надо не учитывать NA
[1] 0.9
> sd(carex[,3], na.rm=T) # стандартное отклонение
[1] 0.5966574

В этом примере используется тот же объект carex, что и в предыдущем разделе. Как видно, нам сильно помешал NA в третьей строке третьей колонки. Дело в том, что таким образом в R обозначаются пропущенные данные. ``Пустое место'' может возникнуть по тысяче причин - от неаккуратного наблюдения и потери данных до невозможности измерить данный признак (например, экземпляр поврежден).

Очень просто получить описательные статистики одной командой:

> summary(carex)
 SPECIES     LENGTH          WIDTH
 aqu:3   Min.   :2.100   Min.   :0.100
 rec:1   1st Qu.:2.350   1st Qu.:0.425
 sal:3   Median :2.500   Median :1.050
         Mean   :2.643   Mean   :0.900
         3rd Qu.:3.000   3rd Qu.:1.375
         Max.   :3.200   Max.   :1.500
                         NA's   :1.00

Как видно, вместо стандартного отклонения здесь приведены медиана (значение, которое делит наблюдения пополам) и квартили (между ними должно попадать 50% значений), что гораздо удобнее для таких данных, которые не имеют нормального распредениеия и/или имеют длинные ``хвосты''.

Заметьте, что статистики по первой переменной сильно отличаются. Это потому, что она ведет себя как фактор, то есть буквенный вектор, имеющий несколько уровней (в данном случае уровней три). Проверим это (кодами уровней называют числовые значения, связанные с уровнями фактора.):

> is.factor(carex$SPECIES) # фактор ли это?
[1] TRUE                   # да!
> levels(carex$SPECIES)    # показать уровни
[1] "aqu" "rec" "sal"
> codes(carex$SPECIES)     # показать коды уровней
[1] 1 1 3 2 1 3 3

И все-таки, NA в третьей колонке будет все время мешать в дальнейших вычислениях. Хорошо бы его заменить на что-нибудь более ``операбельное''! Вот как заменить его на медиану:

> is.na(carex$WIDTH) # какие данные пропущены?
[1] FALSE FALSE  TRUE FALSE FALSE FALSE FALSE
> carex$WIDTH[is.na(carex$WIDTH)] <- median(carex$WIDTH)
> carex$WIDTH
[1] 1.3 1.5  NA 0.3 0.1 0.8 1.4 # не получилось!
> carex$WIDTH[is.na(carex$WIDTH)] <- median(carex$WIDTH, na.rm=T)
> carex$WIDTH
[1] 1.30 1.50 1.05 0.30 0.10 0.80 1.40 # получилось!

Иногда возникает потребность посчитать что-либо для каждой колонки. Вот как посчитать, например, сумму чисел во всех строках нашего объекта:

> apply(carex[,-1],1,sum)
   1    2    3    4    5    6    7
4.40 4.70 3.55 2.70 2.40 2.90 4.30

Если бы мы вторым аргументом указали ``2'', то R посчитал бы сумму по колонкам. А теперь посчитаем основные статистики для LENGTH, но по каждому виду - отдельно:

> tapply(carex[,2],carex$SPECIES,summary)
$aqu
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
  2.300   2.700   3.100   2.867   3.150   3.200

$rec
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
    2.4     2.4     2.4     2.4     2.4     2.4

$sal
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
    2.1     2.3     2.5     2.5     2.7     2.9

Такая операция экономит массу времени, затрачиваемое в обычных пакетах на вырезание, копирование, построение подмножеств и пр.

8  Как строить графики?

В R встроен обширный набор графических функций и значительный набор функций для сохранения графиков в различных форматах. Поэтому вставить график из R в статью, набирающуюся в LATEX или MS Word, достаточно легко11.

Приведем несколько важных соображений по поводу графиков. Первое касается оформления. Все элементы оформления определяются в аргументах соответствующей графической команды. Вот, например, команда для построения гистограммы:

> hist(carex[,2], main="Sample histogram", xlab="LENGTH", col="gray")

Второе соображение касается способа работы с уже построенным графиком. Графические команды делятся на две группы: команды первой группы (например, plot(), hist(), boxplot(), pairs()) заменяют построенный график новым, а команды второй (например, lines(), points(), text()) добавляют к имеющемуся графику новые элементы (к сожалению, стирать нельзя). Вот как добавить текст в произвольное место уже построенного графика:

> text(locator(), "Sample\n text", cex=.8)

Функция locator() работает по щелчку левой кнопкой мыши и выдает две координаты точки щелчка. Затем надо щелкнуть правой кнопкой и в появившемся меню выбрать ``Stop''. Тотчас же на месте щелчка появится текст, разделенный командой \n на две строки. Аргумент cex изменяет относительный размер шрифта.

Третье соображение касается того, как сохранять графику в файлах. Проще всего это делать через изменение графического устройства (graphic device). Вот как ту же гистограмму сохранить в файл с расширением *.png:

> png(file="rplus1.png", width=480, height=480)
> hist(carex[,2], main="Sample histogram", xlab="LENGTH", col="gray")
> dev.off()

Первая команда ``открывает'' графическое устройство (в данном случае файл rplus1.png), а третья - закрывает его, записывая график в файл. Вторая команда ничего не выдает на экран, поскольку графическим устройством в этот момент является файл.

Другой способ сделать это  - при помощи команды dev.print(). Преимущество последнего способа в том, что Вы можете сохранить в файл все содержимое текущего графического окна, в том числе и элементы, нанесенные при помощи интерактивных команд locator() и identify().

Еще одно соображение касается настройки. Почти все параметры выводимых графиков настраиваются, но это иожет потребовать больших усилий. К счастью, R, как правило, предоставляет очень разумные подборки параметров. В любом случае общая настройка происходит через команду par():

> oldpar <- par(mfrow=c(2,2), bg="white")
...
> par(oldpar)

Здесь мы поменяли цвет фона (это полезно для сохранения графики командой dev.print()) и количество графиков в окне, а затем вернулись к сохраненному старому значению параметров (bg="transparent", mfrow=c(1,1)).

9  Что делать дальше?

9.1  Как сравнить две выборки?

R предоставляет большой выбор статистических тестов. Из параметрических в общем случае наиболее полезны t.test(), а из непараметрических - wilcox.test() и chisq.test(). Второй тест можно вызвать также командой summary(table(f1,f2)), где f1 и f2 - некоторые факторы. Выдаваемое ими значение p-value относится к вероятности нулевой гипотезы.

Результат работы теста - это обычно каким-то образом оформленный перечень (list). Поэтому легко вызвать отдельные компоненты теста, просто указав на них при помощи операторов $ либо [[]].

9.2  Как выявить взаимосвязи?

Для выявления взаимосвязей обычно используются коэффициенты корреляции, а также регрессионный анализ. Все это (а также многое другое) реализовано в R. При вычислении корреляций (функция cor()) нужно не забывать убирать строки с пропущенными значениями (например, при помощи na.omit()), а также заменять факторы на их коды.

9.3  Как классифицировать данные?

Класификация подразумевает работу с многомерными данными, то есть сразу с несколькими векторами (столбцами). Основная коллекция многомерных методов находится в дополнительно загружаемом пакете mva:

> library(mva)

В этом пакете реализованы, в частности, создание матриц сходства (dist()), метрическое многомерное шкалирование (cmdscale()), анализ главных компонент (princomp()) и иерархический кластерный анализ (hclust()). Неметрическое многомерное шкалирование реализовано в пакете MASS (называется isoMDS()), очень много методов кластеризации собрано в пакете cluster (функции daisy(), diana() agnes()). Очень интересны также пакеты tree и rpart, которые вводят одноименные функции, предназначенные для построения деревьев классификации (метод, гораздо более мощный, чем распространенный дискриминантный анализ). Кроме того, имеется специализированный пакет vegan, в котором собрано много популярных в экологии индексов сходства (например, индекс Жаккара, функция vegdist(..., method="kulczynski")) и многомерных методов (например, decorana()). Добавим теперь несколько замечаний относительно распространенных многомерных методов.

Анализ главных компонент
 - параметрический метод, не допускающий использования в нем переменных, не имеющих нормального распределения. Кроме того, выдаваемая им классификация рассчитана в предположении лишь о простых типах взаимосвязей переменных.
Многомерное шкалирование
 - непараметрический метод, неметрическую разновидность которого можно импользовать как для непрерывных, так и для дискретных данных. Метод требует исключения из анализируемой матрицы одинаковых объектов (команда unique()). Перед началом обработки объекты полезно нормировать, например, разделить значения в каждой строке на стандартное отклонение. В начале рассчитываются индексы сходтсва (командой dist()), а затем уже происходит собственно шкалирование. Индексов сходства очень много, поэтому от их выбора в значительной степени зависит структура результата. Кроме того, многомерное шкалирование чувствительно к порядку введения в него объектов.
Кластерный анализ
 - непараметрический метод, иерархическая разновидность которого оперирует с матрицами сходства, которые нужно предварительно получить командой dist(). Методов кластеризации очень много, поэтому сочетание разных методов с разными индексами порождает значительное разнообразие результатов. Математическая база многих методов кластеризации до сих пор не разработана, поэтому результаты кластерного анализа могут оказаться не интерпретируемыми. Наконец, многие методы вычисления сходства, хотя и разрешают использование дискретных данных, чувствительны к данным, измеренным в разных шкалах (это не относится к daisy(), функции из пакета cluster). Из методов кластеризации в биологических исследованиях удобны ``complete'' и ``ward'', последний приводит обычно к построению резко отграниченных кластеров. Команда cutree() позволяет строить переменные, в которых будет сохранена кластерная принадлежность каждого объекта.
Деревья классификации
очень полезны в качестве замены дискриминантного анализа. Они позволяют выяснить, какие именно показатели могут быть использованы для разделения объектов на заранее заданные группы. Такие группы могут быть, например, получены в результате кластерного анализа. В результате строится определительный ключ, в котором на каждой ступени объекты делятся на две группы в соответствии с заранее заданными признаками. При этом не всегда удается выделить все заранее заданные группы, таким образом, классификационные деревья проверяют исходную классификацию.

9.4  Как автоматизировать работу?

Для этого важно время от времени сохранять файл истории команд командой savehistory(). После этого получившийся файл можно редактировать в любом текстовом редакторе, убирая ненужные и ошибочные команды. Теперь, если Вы хотите повторить анализ, нужно сделать так:

> sink("my.out")
> source("myhistory.r", echo=T)
> sink()

Если Ваши команды записаны в файл myhistory.r, то все они будут выполнены (учтите, что любая ошибка прервет исполнение), а все результаты записаны в файл my.out. Естественно, если Вы создавали какие-либо графические файлы, то они будут созданы заново. И отчет готов!


Footnotes:

1© А. Шипунов, 2002. Каждый имеет право воспроизводить, распространять и/или вносить изменения в настоящий документ в соответствии с условиями GNU Free Documentation License, версией 1.1 или любой более поздней версией, опубликованной Free Software Foundation. Данный документ не содержит неизменяемых разделов, а также текста, помещаемого на первой и последней страницах обложки. Копия настоящей лицензии находится по Internet-адресу http://www.gnu.org/copyleft/fdl.html.

2# - это символ комментария, и все, что за ним, R не читает. Подразумевается, что в конце каждой строки, начинающейся с >, была нажата клавиша <ENTER>.

3Кстати, учтите, что для десятичных дробей используется точка!

4R не использует никаких вр\'еменных файлов, вся информация об объектах хранится в памяти. Чтобы записать объекты на диск, воспользуйтесь командами типа save() (см. ниже).

5Это потому, что в русифицированных программах принято в качестве десятичного разделителя использовать запятую, и программа потом может перепутать, где какой разделитель.

6Excel выполняет этот пункт, если вы сохраняете данные в формате CSV.

7Пока Вы этого специально не захотите, см. команду attributes().

8Их список, если Вы не забыли, можно получить командой ls().

9Фраза ``не годятся'' звучит, может быть, чересчур жестко. В общем случае она означает, что таких методов надо избегать, поскольку их результаты могут оказаться содержательно не интерпретируемыми. Возможно, однако, применять их на свой страх и риск.

10Такое распределение возникает, например, если стрелять в цель, а затем измерять расстояние от центра мишени до каждого попадания.

11Хотя по соображениям переносимости мы не будем демонстрировать в этом тексте графики.


File translated from TEX by TTH, version 3.00.
On 18 Oct 2002, 19:34.