Работа с данными

Чтобы работать с данными нужно их сперва окуда-то загрузить. Можно загружать данные из локального файла, находящегося в каком-то каталоге на жёстком диске компьютера, а можно сразу из Интернета. Делается это примерно одинаково. Самый простой формат, в котором можно хранить данные для статистической обработки, называется 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

Другой способ состоит в том, чтобы использовать функцию 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 году!