http://www.math.csi.cuny.edu/Statistics/R/simpleR
Раздел 2: Данные
Статистика — это изучение данных. После того, как мы разберёмся, как запустить R, первое, что нам понадобится, — научиться, как вводить данные в R и как работать с данными, когда они уже введены.
Запуск R
R легче всего изучать интерактивным способом. Вы задаёте вопрос, а R даёт вам ответ. Вопросы задают и получают на них ответы в командной строке. Чтобы запустить командную строку R, вы можете: в Windows отыскать иконку R и дважды кликнуть по ней, в Unix набрать в командной строке терминала прописную букву R. Другие операционные системы, потребуют от вас других действий. Как только R будет запущен, вы увидите приветствие, подобное следующему:
R : Copyright 2001, The R Development Core Team
Version 1.4.0 (2001-12-19)
R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type ‘license()’ or ‘licence()’ for distribution details.
R is a collaborative project with many contributors.
Type ‘contributors()’ for more information.
Type ‘demo()’ for some demos, ‘help()’ for on-line help, or
‘help.start()’ for a HTML browser interface to help.
Type ‘q()’ to quit R.
[Previously saved workspace restored]
>
Значок > называется «приглашением» (prompt). В дальнейшем мы будем им пользоваться, чтобы показать, что нужно вводить в командной строке R, если вы хотите повторить приведённые примеры. Если команда слишком длинна и не помещается в одну строку, применяется значок + для переноса её на следующую строку.
Ввод данных с помощью функции c
Самой употребимой командой в R для быстрого ввода небольших наборов данных является функция c. Она объединяет или «сцепляет» (combines or concatenates) следующие за ней значения. Например, предположим, что у нас есть следующий набор чисел, выражающий количество опечаток на странице. Его мы назовём typos: 2 3 0 3 1 0 0 1
Чтобы ввести это в текущую сессию R, мы наберём
> typos = c(2,3,0,3,1,0,0,1)
> typos
[1] 2 3 0 3 1 0 0 1
Заметьте себе
• мы присвоили ряд значений переменной typos.
• знак равенства = является оператором присвоения в версии R 1.4.0 или выше. В более ранних версиях таким опрератором был (и по прежнему может быть) знак <-. Оба эти знака могут использоваться, хотя вы должны запомнить какой-либо один и пользоваться им. • значения переменной typos не выводятся автоматически на печать или на монитор. Это происходит только тогда, когда мы набираем имя переменной, как показано в последней строке предыдущего примера. • значения переменной typos предваряются чем-то подобным тому, что произошло в нашем примере: [1]. Это показывает, что наша переменная — вектор. Подробнее об этом мы поговорим ниже. Чтобы сэкономить силы
Во многих случаях вы можете сэкономить свои силы, если вы запомните, что клавиши стрелок могут использоваться для повторного ввода ранее введённых команд. Каждая команда сохраняется в истории сессии и с помощью клавиши «стрелка вверх» вы можете просматривать эту историю от последних команд к первым, а с помощью клавиши «стрелка вниз» — от первых к последним. Клавиши «стрелка влево» и «стрелка вправо» работают как обычно. Это в сочетании с мышкой существенно облегчает простое редактирование ваших предыдущих команд.
Применение функций
В R очень много встроенных функций, которыми можно обрабатывать такие данные, как typos. Одна из них — расчёт среднего (mean function). Воспользоваться ею просто:
> mean(typos)
[1] 1.25
Точно также мы можем вызвать расчёт медианы (median) или функцию дисперсии (var). Синтаксис этих команд такой же — имя функции с последующими круглыми скобками, в которых содержится один или несколько аргументов:
> median(typos)
[1] 1
> var(typos)
[1] 1.642857
Данные — это вектор
Данные содержатся в R как вектор. Это значит попросту то, что они находятся в том порядке, который был задан при их вводе. Т. е. тут есть некий первый элемент, второй элемент и т. д. вплоть до последнего элемента. Такая организация данных удобна по ряду причин:
• наш простенький вектор данных typos расположен в естественном порядке — число опечаток на первой странице, на второй и т. д. Мы бы не хотели всё тут попутать.
• мы бы могли изменить наши данные одно за другим вместо того, чтобы вводить весь массив снова.
• векторы суть математические объекты. Они — естественное продолжение таких математических концепций как сложение и умножение, что облегчает работу с данными в векторной форме.
Давайте посмотрим, как всё изложенное применяется к нашему примеру typos. Для начала предположим, что переменная typos из Раздела 1 есть первый черновик нашего текста. Мы хотим слегка исправить опечатки, т. е. изменить данные. Это можно было бы сделать так:
> typos.draft1 = c(2,3,0,3,1,0,0,1)
> typos.draft2 = c(0,3,0,3,1,0,0,1)
Таким образом, два набора typos различаются только первым числом. Обратите внимание на имена переменных. В отличие от других языков, точка (period) используется только в качестве разделителя. Нельзя пользоваться подчёркиванием _ , чтобы отделять имена друг от друга так, как это можно делать в других языках программирования.
Сейчас вы могли бы сказать, что слишком много времени занимает повторное переписывание данных. Могу ли я указать R просто внести изменения в первое значение? Ответ, естественно, будет «да». И вот как:
> typos.draft1 = c(2,3,0,3,1,0,0,1)
> typos.draft2 = typos.draft1 # делаем копию
> typos.draft2[1] = 0 # приписываем 0 первому значению
Обратите внимание на детали. Во-первых, знак комментария #. Вообще, всё что следует после этого знака в строке, игнорируется (естественно R, но, надеюсь, не читателем). Важнее однако то, что операция присвоения первому значению в векторе typos.draft2 сделана через ссылку на номер самого значения в векторе. Это сделано с помощью квадратных скобок []. Важно запомнить: круглые скобки () используются в функциях, тогда как квадратные [] — в векторах (и в дальнейших вызовах (arrays) и списках). В частности, мы получили следующие значения в typos.draft2
> typos.draft2 # вывести значения на экран
[1] 0 3 0 3 1 0 0 1
> typos.draft2[2] # вывести значение под номером два (опечатки на второй странице)
[1] 3
> typos.draft2[4] # значение под номером четыре (опечатки на четвёртой странице)
[1] 3
> typos.draft2[-4] # все, кроме четвёртого
[1] 0 3 0 1 0 0 1
> typos.draft2[c(1,2,3)] # и допустим ещё — первое, второе и третье.
[1] 0 3 0
Заметьте, что знак минус перед номером значения указывает R вывести всё, кроме этого номера. Последний пример особенно важен. Вы можете получить несколько значений сразу с использованием иного вектора с индексными номерами. Это так называемая «вырезка» (slicing).
Окей, нам нужно привести эти заметки в порядок, давайте найдём по настоящему плохие страницы. Мы, конечно, можем просто просмотреть наш список и заметить, что на второй и четвёртой странице больше всего опечаток. Можно ли это сделать в R более систематическим образом?
> max(typos.draft2) # каково самое большое число опечаток на странице?
[1] 3 # 3 опечатки
> typos.draft2 == 3 # Где страницы с тремя опечатками?
[1] FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE
Заметьте, мы воспользовались двойным знаком равенства (==). Это указывает программе проверить все значения в typos.draft2 на равенство их 3. Второй и четвёртые ответы «да» (TRUE), все остальные — «нет» (FALSE).
Представьте, что вы спрашиваете R: «равно ли значение 3?» R ответит для всех значений каждого, даже самого длинного вектора, правда это (TRUE) или ложь (FALSE).
Но как же нам получить номера страниц, соответствующих условию? Давайте перефразируем наш запрос:
> which(typos.draft2 == 3)
[1] 2 4
Но что, если вам не подходит команда which? Вы не остались без помощи, но вы просто дожны немного больше поработать. Основная идея в этом случае состоит в том, чтобы создать вектор 1 2 3 ... , состоящий из номеров страниц, после чего вырезать из него (slicing) только те, для которых typos.draft2==3:
> n = length(typos.draft2) # сколько у нас страниц
> pages = 1:n # сгенерировать вектор, состоящий из последовательных номеров страниц
> pages # показать этот вектор
[1] 1 2 3 4 5 6 7 8
> pages[typos.draft2 == 3] # логическое исключение — чрезвычайно полезная команда
[1] 2 4
Чтобы создать вектор 1 2 3 ... мы воспользовались очень простым оператором двоеточия (colon) : . Конечно, мы могли бы просто напечатать эти номера вручную, но полезно знать, как это сделать автоматически. Команда a:b генерирует последовательной чисел a, a+1, a+2, ..., b (при этом a, b могут быть целыми или дробными):
> x=1.5:7
> x
[1] 1.5 2.5 3.5 4.5 5.5 6.5
Более общей функцией в R является seq(). Попробуйте ?seq для того, чтобы узнать о её опциях. Для того, чтобы воспроизвести предыдущий пример наберите:
>seq(1.5,7,1)
Пользование экстрагирующими элементами вектора с использованием другого вектора такого же размера, состоящего из єлементов «истинно» (TRUE) и «ложно» (FALSE) относится к операции извлечения логическим вектором. Заметьте, что это отличается от извлечения по номерам страниц через нарезку (slicing), описанного ранее. Знание, как пользоваться нарезкой (slicing) и логическими векторами, даёт вам возможность получить лёгкий доступ к вашим данным так, как это вам нужно.
Естественно, мы бы могли сделать всё описанное с использованием только одной команды (но зачем?):
> (1:length(typos.draft2))[typos.draft2 == max(typos.draft2)]
[1] 2 4
Это выглядит устрашающе и, к тому же, при наборе такой фразы можно наделать кучу ошибок, но приведённый пример на самом деле иллюстрирует, как команды могут быть объединены в короткую мощную фразу. Это очень важный момент. Чтобы оценить все прелести использования R, вы должны понять, как соединяется выход одной функции или операции со входщом другой. В математике это называется композицией (composition).
В конце-концов мы могли бы захотеть знать, сколько всего у нас опечаток, или, например, на каких страницах по-прежнему есть опечатки, или чем отличаются черновики? На эти вопросы можно получить ответ с помощью математических функций:
> sum(typos.draft2) # Сколько всего опечаток?
[1] 8
> sum(typos.draft2>0) # Сколько страниц с опечатками?
[1] 4
> typos.draft1 - typos.draft2 # Чем отличаются два черновика?
[1] 2 0 0 0 0 0 0 0
Пример: изучение ставок на бирже — добавление данных
Предположим, что дневные ставки вашей биржи за две недели таковы:
45,43,46,48,51,46,50,47,46,45
Введём эти данные в R как вектор:
> x = c(45,43,46,48,51,46,50,47,46,45)
> mean(x) # среднее
[1] 46.7
> median(x) # медиана
[1] 46
> max(x) # максимум или самое большое значение
[1] 51
> min(x) # минимум или наименьшее значение
[1] 43
Из приведённого примера следует, что много интересных функций можно легко найти по названию. Давайте посмотрим, как можно сделать что-нибудь другое. Во-первых, давайте добавим ставки двух следующих недель к данным вектора x, а именно: 48,49,51,50,49,41,40,38,35,40
Мы можем сделать это по-разному:
> x = c(x,48,49,51,50,49) # присоединить значения к x
> length(x) # какой длины сейчас x (было 10)
[1] 15
> x[16] = 41 # добавить ещё одно значение
> x[17:20] = c(40,38,35,40) # добавить оставшиеся
Заметьте, мы добавляли значения тремя разными способами. Все они полезны, поэтому объясним их. Сначала мы воспользовались оператором c (combine) и объединили прежние значения x с новыми. После этого мы напрямую приписали одно из них к 16 номеру (при этом до этого у x было только 15 значений, следовательно 16-е создалось автоматически). И, наконец, мы приписали оставшие к отрезку. Последнее сильно упрощает ряд задач.
Основы R: Графические интерфейсы для ввода данных
Есть и другие пути редактирования данных — с использованием интерфейса таблицы. Это может быть более предпочтительно для некоторых студентов. Рассмотрим их:
> data.entry(x) # Вызов таблицы для редактирования данных
> x = de(x) # То же самое, но без возможности записи изменений (в режиме «только для чтения»)
> x = edit(x) # Использование редактора для редактирования вектора x.
Всем этим легко пользоваться. Главной неожиданностью будет то, что переменная x должна быть определена заранее. Например:
> data.entry(x) # не работает. x не определена.
Error in de(..., Modes = Modes, Names = Names) :
Object "x" not found
> data.entry(x=c(NA)) # работает. x определена.
Другие методы ввода данных будут рассмотрены в Приложении.
Прежде чем мы закончим с этим примером, давайте посмотрим, как мы можем ещё манипулировать с данными. Всего несколько примеров.
Динамичное среднее (moving average) означает по-просту нахождение среднего за некоторое предыдущее число дней. Предположим, мы хотим пятидневное динамичное среднее (обычно применяется 50-дневное или 100-дневное). Мы можем сделать это, начиная с пятого дня торгов на бирже, поскольку другие дни содержат недостаточные данные:
> day = 5;
> mean(x[day:(day+4)])
[1] 48
Суть трюка состоит в том, чтобы извлечь из массива дни 5й, 6й, 7й, 8й и 9й:
> day:(day+4)
[1] 5 6 7 8 9
после чего взять среднее только от этих значений вектора x.
Какова наивысшая ставка торгов? Это легко найти с помощью функции max(x). Однако, Вы, возможно, интересуетесь наивысшей ставкой, когда-либо достигнутой к заданной дате (прим. переводчика: я не смог подобрать эквивалента термину running maximum, смысл которого поясняется аналогией с прибором «максимальный термометр»). Это также просто — если Вы знаете, что у R есть для этого встроенная функция. Она называется cummax, показывающий кумулятивный максимум. Покажем результаты обработки наших четырёжнедельных данных:
> cummax(x) # running maximum
[1] 45 45 46 48 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51
> cummin(x) # running minimum
[1] 45 43 43 43 43 43 43 43 43 43 43 43 43 43 43 41 40 38 35 35
Пример: Работа с математикой
R позволяет легко оперировать математическими выражениями привычным нам образом (если, конечно, данные уже введены). Например, предположим, что ежегодное число китов, приплывающих к техасским пляжам за период с 1990 по 1999 таково: 74 122 235 111 292 111 211 133 156 79
Как отыскать среднее, дисперсию и стандартное отклонение? Итак:
> whale = c(74,122,235,111,292,111,211,133,156,79)
> mean(whale)
[1] 152.4
> var(whale)
[1] 5113.378
> std(whale)
Error: couldn’t find function "std"
> sqrt(var(whale))
[1] 71.50789
> sqrt(sum((whale - mean(whale))^2 /(length(whale)-1)))
[1] 71.50789
Ну, наконец-то! Во-первых, нужно помнить имена функций. Запомнить функцию mean() легко2, дисперсию — var() чуть сложнее, стандартное отклонение —std(), казалось бы, тоже очевидно, но почему R выдаёт ошибку? функции std() в нём нет! Но можно попробовать кое-что другое. Во-первых мы помним, что стандартное отклонение — это квадратный корень из дисперсии. Во-вторых, последняя строка иллюстрирует, что средствами R можно достаточно точно воспроизвести математическую формулу стандартного отклонения.
Конечно, было бы неплохо иметь всегда под рукой встроенную функцию. Сделать её очень легко:
> std = function(x) sqrt(var(x))
> std(whale)
[1] 71.50789
Лёгкость создания ваших собственных функций — это очень привлекательная особенность R; мы ещё вернёмся к ней.
Ну и наконец: если бы мы чуть больше напряглись, то мы могли бы отыскать уже встроенную команду для вычисления стандартного отклонения — sd(), которая даёт:
> sd(whale)
[1] 71.50789
Основы R: Доступ к данным
Существует несколько способов извлечь данные из вектора. Ниже приведён перечень использования как вырезок (slicing), так и извлечения данных с помощью логического вектора. Пусть x — это вектор данных, например x=1:10.
сколько элементов в векторе? length(x)
i-тый элемент x[2] (i = 2)
все элементы, кроме i-того x[-2] (i = 2)
первые k элементов x[1:5] (k = 5)
последние k элементов x[(length(x)-5):length(x)] (k = 5)
определённые элементы x[c(1,3,5)] (первый, третий и пятый)
все элементы, большие некоторого значения x[x>3] (3 — это граничное значение)
все элементы большие чем или меньшие чем некоторое значение x[ x< -2 | x > 2]
какие номера у самых больших элементов? which(x == max(x))
Упражнения
2.1 Предположим, Вы записываете каждый раз после поезки расстояние, которое Вы преодолели. В последних Ваших шести путешествиях расстояние было (в милях): 65311 65624 65908 66219 66499 66821 67145 67447.
Введите эти числа в R. Примените функцию diff() к этим данным. Что у Вас получилось?
> miles = c(65311, 65624, 65908, 66219, 66499, 66821, 67145, 67447)
> x = diff(miles)
Вы, должно быть, увидели разницу в числе миль между соседними поезками. Используйте max(), чтобы найти максимальную разницу между пройденными Вами расстояниями, mean(), чтобы вычислить среднее пройденное расстояние, и min(), чтобы узнать самое короткое из пройденных дистанций.
2.2 Предположим, Вы записывали время пути из дому на работу в течение двух недель (10 дней) и получили следующий ряд чисел (в минутах): 17 16 20 24 22 15 21 15 17 22.
Введите эти числа в R. Воспользуйтесь функцией max() для того, чтобы найти продолжительность самого долгого пути, mean() — среднего и min() — самого короткого. Сколько раз Вы шли 20 минут или дольше? (для ответа на этот вопрос попробуйте, если Вы назвали Ваш вектор commutes,
> sum(commutes>=20)
Что у Вас получилось? Каков процент Ваших походов продолжался менее 17 минут? Как бы Вы ответили на это с помощью R?
2.3 Счета за переговоры по Вашему мобильному телефону изменяются от месяца к месяцу. Предположим, за год суммы по месяцам были таковы: 46 33 39 37 46 30 48 32 49 35 30 48
Введите эти данные в R как переменную bill. Воспользуйтесь коммандой sum(), чтобы вычислить сумму, потраченную Вами на переговоры. Какова наименьшая сумма, потраченная Вами за один месяц? Наибольшая?Как часто Вы тратили больше 40 долларов? В скольки процентов случаев это было?
2.4 Вы хотите купить подержанный автомобиль и после трёх месяцев поисков по объявлениям нашли следующие цены (предположим, что автомобили одинаковые): 9000 9500 9400 9400 10000 9500 10300 10200
С помощью R вычислите среднюю цену и сравните её с оценочной ценой Эдмунта (http://www.edmunds.com) $9500. Отыщите минимальное и максимальное значения. Какая цена Вас бы устроила?
2.5 Попробуйте предположить результаты нижеприведённых команд в R. Учтите, что способом получения доступа к элементам вектора являются квадратные скобки [].
> x = c(1,3,5,7,9)
> y = c(2,3,5,7,11,13)
1. x+1
2. y*2
3. length(x) and length(y)
4. x + y
5. sum(x>5) and sum(x[x>5])
6. sum(x>5 | x< 3) # read | as ’or’, & and ’and’ 7. y[3] 8. y[-3] 9. y[x] (What is NA?) 10. y[y>=7]
2.6 Пусть данные вектора x определены так:
> x = c(1, 8, 2, 6, 3, 8, 5, 5, 5, 5)
С помощью R рассчитайте следующие функции. Заметьте, мы обозначаем как X1 первый элемент вектора x и т. д.
1. (X1 + X2 + · · · + X10 )/10 (используйте команду sum)
2. Отыщите log10 (Xi ) для каждого i. (Воспользуйтесь функцией log, основание которой по умолчанию равно e)
3. Отыщите (Xi − 4.4)/2.875 для каждого i. (Сделайте это за один раз)
4. Отыщите разность между самым большим и самым малым значением x.
Читать далее