Чтобы работать с данными нужно их сперва окуда-то загрузить. Можно загружать данные из локального файла, находящегося в каком-то каталоге на жёстком диске компьютера, а можно сразу из Интернета. Делается это примерно одинаково. Самый простой формат, в котором можно хранить данные для статистической обработки, называется comma separated values (csv) – это табличка, записанная по строчкам, в которых отдельные ячейки разделены запятыми. Для примера я выложил файл с искусственными данными, похожими на настоящие, на страничку курса. Можно его скачать и поместить в каталог, в котором находится сейчас R. Узнать, что это за каталог, можно так:
getwd()
## [1] "/Users/user/prj/oldhse-2010-11/repo/2014-15/ling-r"
Перейти в другой каталог можно так:
setwd("/Users/user/prj/hse/ling-r")
getwd()
## [1] "/Users/user/prj/oldhse-2010-11/repo/2014-15/ling-r"
Допустим, мы скачали файл duration-synth.csv и сохранили его в текущий рабочий каталог. Считать файл в переменную теперь можно вот так
df <- read.csv("duration-synth.csv")
Того же эффекта мы бы добились, если бы просто подставили адрес файла в Интернете:
df <- read.csv("http://math-info.hse.ru/f/2014-15/ling-r/duration-synth.csv")
Посмотрим, что лежит в df. Это можно сделать командой View(df) (обязательно с большой буквы), тогда содержимое файла откроется в верхнем окошке в виде такой таблички (как в Excel). Можно просто посмотреть начало этого файла.
head(df)
## duration year gender
## 1 57 1971 male
## 2 147 1971 male
## 3 68 1971 male
## 4 140 1971 male
## 5 58 1971 male
## 6 67 1971 male
Мы видим, что файл состоит из трёх столбцов. Каждый столбец (duration, year, gender) называется переменной (variable), а каждая строчка — наблюдением (observation). В данном случае перед нами результаты интервьюрования некоторого количество человек разного пола и возраста. Про каждого человека нас интересует параметр, называемый duration (я не буду углубляться в его лингвистичский смысл — возможно, это длительность произнесения какого-нибудь звука в каком-то слове или ещё что-то подобное).
В переменной df сейчас находится так называемый dataframe, по сути — внутреннее представление таблички. Вот так можно обращаться к строчкам и столбцам:
print(df[2,]) # вторая строчка
## duration year gender
## 2 147 1971 male
print(df$year) # столбец с годами
## [1] 1971 1971 1971 1971 1971 1971 1971 1971 1971 1971 1971 1971 1971 1971
## [15] 1971 1971 1971 1971 2001 2001 2001 2001 2001 2001 2001 2001 2001 2001
## [29] 2001 2001 2001 2001 2001 2001 2001 2001 2001 2001 2001 2001 2001 2001
## [43] 2001 2001
Вот так можно посмотреть сводную информацию:
summary(df)
## duration year gender
## Min. : 43.00 Min. :1971 female:23
## 1st Qu.: 68.75 1st Qu.:1971 male :21
## Median : 82.00 Median :2001
## Mean : 95.98 Mean :1989
## 3rd Qu.:119.00 3rd Qu.:2001
## Max. :185.00 Max. :2001
Видно, что столбцы duration и year воспринимаются системой как числовые (для них она считает минимумы-максимумы-средние-квантили и т.д.), а параметр gender воспринимается иначе: это так называемый фактор, то есть переменная, которая принимает одно из конечного (обычно не очень большого) множества значений (в данном случае их всего два).
Прежде, чем исследовать данные с помощью точной статистики, полезно их визуализировать.
hist(df$duration)
Это общая гистограмма переменной duration. Если нас интересует, как duration зависит от пола, можно нарисовать ящики с усами.
plot(duration ~ gender, data=df)
Обратите внимание на тильду между duration и gender – она показыает, что нам нужно сгруппировать значения переменнрой duration с помощью фактора gender.
Ящики с усами позволяют графически отобразить основные параметры выборок. В данном случае у нас есть две выборки, сгруппированные в соответствии с фактором year. Для каждой из них мы рисуем жирную горизонтальную прямую — это медиана выборки, сам ящик — его границы это первый и третий квартили распределения (то есть ровно половина всей выборки лежит «внутри ящика») и усы. Усы показывают уровень разброса: верхний ус заканчивается в максимальном элементе, отстоящим от верхней части ящика не более чем на полтора межквартильных интервала (то есть высоты ящика), нижний ус заканчивается в минимальном элементе, отстоящим от нижней части ящика не более, чем на полтора межквартильных интервала. Если есть элементы, выходящие за границы усов, их рисуют отдельно и считают выбросами (outliers).
В соответствии с картинкой, можно предполжить, что среднее значение параметра duration для женщин оказывается больше, чем для мужчин (хотя максимум у мужчин больше). Проверим, так ли это, с помощью t-теста. Это можно сделать разными способами — например, выделить из всего датафрейма отдельно строки, соответствующие мужчинами, и отдельно женщинам.
Как выделить нужные нам строчки? Например, так:
female <- df[df$gender=='female',]
Эта строчка выглядит немного эзотерически, давайте разберёмся повнимательнее, почему она работает. Пусть есть список.
somelist <- c(1,-3,4,2,-5)
Допустим, мы хотим выбрать из него только положительные числа. Можно сначала проверить, какие числа являются положительными.
somelist>0
## [1] TRUE FALSE TRUE TRUE FALSE
Как видите, выдаётся список, состоящий из TRUE и FALSE — там, где условие выполняется (значение больше 0), написано TRUE, а там, где не выполняется — FALSE. Оказывается, можно использовать эти данные, чтобы выбрать элементы из списка.
somelist[c(TRUE,FALSE,TRUE,TRUE,FALSE)]
## [1] 1 4 2
Если в качестве индекса указать список, содержащий TRUE и FALSE, то будет сформирован новый список, в который войдут только элементы, помеченные TRUE. Вот другие примеры:
somelist[c(FALSE,FALSE,FALSE,TRUE,TRUE)] # выдать два последних элемента
## [1] 2 -5
somelist[c(TRUE,FALSE,FALSE,FALSE,TRUE)] # выдать первый и последний элемент
## [1] 1 -5
Наконец, для решения нашей задачи в общем виде можно написать
somelist[somelist>0]
## [1] 1 4 2
Выражение в квадратных спобках сейчас заменяется на список, в котором TRUE стоит напротив положительных элементов, а затем именно они попадают в новый список. Можно было бы выбрать только отрицательные элементы:
somelist[somelist<0]
## [1] -3 -5
Наконец, в выражении df[df$gender=='female',] выжна запятая после условия: она показывает, что выбирать нужно строки.
Аналогично:
male <- df[df$gender=='male',]
И теперь можно применить t-тест как в предыдущей лекции.
t.test(female$duration, male$duration)
##
## Welch Two Sample t-test
##
## data: female$duration and male$duration
## t = 0.1385, df = 39.894, p-value = 0.8905
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -21.69728 24.88983
## sample estimates:
## mean of x mean of y
## 96.73913 95.14286
Несмотря на разницу средних, видно, что она совершенно не значима – p-value очень большое.
Другой способ состоит в том, чтобы использовать функцию split:
spl <- split(df, df$gender)
Теперь в spl$male и spl$female находятся соответствующие куски исходного датафрейма и можно было бы написать
male <- spl$male
female <- spl$female
Получилось бы то же самое, что было написано выше.
Наконец, можно было бы ничего не разделять! Можно упростить вызов t-теста, используя такую форму:
t.test(duration ~ gender, data=df)
##
## Welch Two Sample t-test
##
## data: duration by gender
## t = 0.1385, df = 39.894, p-value = 0.8905
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -21.69728 24.88983
## sample estimates:
## mean in group female mean in group male
## 96.73913 95.14286
В этом случае функция t.test сгруппирует данные по фактору автоматически.
Нам хотелось бы провести такой же анализ для группировки по годам.
plot(duration ~ year, data=df)
Получилась какая-то неправильная картинка, а совсем даже не ящики с усами. Это связано с тем, что вторая переменная (year) хоть и принимает всего два значения (1971 и 2001), но воспринимается системой как числовая. На самом деле её тоже можно сделать фактором (это полезно для дальнейшего). Например, вот так:
df$year <- as.factor(df$year)
summary(df)
## duration year gender
## Min. : 43.00 1971:18 female:23
## 1st Qu.: 68.75 2001:26 male :21
## Median : 82.00
## Mean : 95.98
## 3rd Qu.:119.00
## Max. :185.00
Теперь картинка рисуется правильно.
plot(duration ~ year, data=df)
Обратите внимание на выбросы в правой части.
Можно применить t-тест:
t.test(duration ~ year, data=df)
##
## Welch Two Sample t-test
##
## data: duration by year
## t = 2.62, df = 36.822, p-value = 0.0127
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## 6.397819 50.089360
## sample estimates:
## mean in group 1971 mean in group 2001
## 112.66667 84.42308
Мы получили значимое различие: для респондентов 1971 года рождения продолжительность оказывается статистически значимо выше, чем для тех, кто родился в 2001 году!