1 🅡 Знакомство со средой R

1.2 Подготовьте рабочее место

  • Рассмотрите кнопки и вкладки RStudio

  • Организуйте окна RStudio.

  • Создайте новый (пустой) R скрипт.

  • Назначьте рабочую папку данного проекта setwd() [set working directory]

    • Например: setwd("/Users/maksimrudnev/Teaching/R2021")
  • Проверьте, сработала ли предыдущая команда, запустив getwd() [get working directory]

Рабочее пространство (Environment) - часть оперативной памяти, которая хранит объекты R в текущей сессии.

Рабочая папка (working directory)- это папка на компьютере, в которой сохраняется рабочее пространство, откуда по умолчанию считываются и куда записываются файлы.

2 🔤 Векторы

  • Попробуйте написать команду в консоли: 1+2.
  • Создайте объект justnumber и припишите ему значение 25. Посмотрите, что изменилось во вкладке Environment.
    • лучше писать все команды в файле скрипта и запускать их используя Control+Enter (Command+Enter on Mac).
  • Создайте вектор из 5 текстовых значений, используя функцию c. Все текстовые значения берутся в кавычки. Сохраните этот вектор как объект R.
  • Попробуйте “запустить” название этого объекта.
  • Удалите объект из памяти функцией rm.
1 + 2
> [1] 3
justnumber <- 25

tvector <- c("a", "bla", "bla", "blo", "blu")

tvector
> [1] "a"   "bla" "bla" "blo" "blu"
rm(tvector)

2.1 Сложение числовых векторов

  • Создайте вектор числовых значений от 1 до 5 и сложите его с числом 5 используя оператор +. Посмотрите на результат.

Полезный оператор : для создания последовательностей чисел.

1:5
> [1] 1 2 3 4 5
  • Создайте второй вектор значений от 21 до 25 и сложите его с первым вектором. Посмотрите на результат – что к чему прибавлялось?
nvector <- c(1,2,3,4,5)

nvector + 5
> [1]  6  7  8  9 10
nvector2 <- c(10,11, 12, 13, 14, 15, 16, 17, 18, 19)

nvector + nvector2
>  [1] 11 13 15 17 19 16 18 20 22 24

2.2 Индексирование векторов

Для индексирования используются квадратные скобки и порядковый номер элемента. Например: vectorA[2] вернет второй элемент вектора.

  • Проиндексируйте последний созданный вектор, чтобы был возвращен его

    • а) пятый элемент,
    • б) с третьего по пятый,
    • в) второй и пятый (используйте функцию c())
  • Примените к этому вектору функции sort() и order(). В чем разница между результатами?

  • Отсортируйте вектор в обратном порядке, изменив значение аргумента decreasing в функции sort().

  • Проиндексируйте последний созданный вектор, чтобы были возвращены с первого по пятый элементы.

2.3 Векторы с именами элементов

Векторы могут содержать имена каждого из элементов. Имена также могут использоваться для индексирования.

named.vector <- c(pervyi = 1, 
                  vtoroy = 2, 
                  tretiy = 4
                  )
  • Проиндексируйте вектор named.vector, чтобы вернуть элемент под названием "vtoroy".

2.4 Номинальные переменные (factor)

Номинальные переменные - дискретные значения с ограниченным числом вариантов.

# эксплицитно

myfactor <- factor(c("a", "a", "b", "b", "a", "b"), 
                     levels = c("b", "a")
                   )

# или автоматически

myfactor <- factor(c("a", "a", "b", "b", "a", "b"))

myfactor
> [1] a a b b a b
> Levels: a b
  • Очистите рабочее пространство (Environment) от всех объектов кнопкой 🧹.

2.5 Логические операторы

Как создавать логические переменные – нужно что-то с чем-то сравнить.

  • == равно, эквивалентно; != (не равно); а также <, >.

Логические выражения могут быть сложнее, чем одно сравнение. Для этого используются булевы операторы.

  • !x [не x] обратное значение (если TRUE, станет FALSE и наоборот)
  • x & y Логическое И. И x, и y являются TRUE. Если один из них FALSE, то возвращаемые значения FALSE.
  • x | y Логическое ИЛИ. Если x или y является TRUE, то возвращаемое значение будет TRUE.

2.5.1 Задание

  • Создайте объект fifty и объект twenty и присвойте им значения 50 и 20.
  • Сравните эти два объекта используя оператор ==.
  • Теперь сравните их, используя операторы != [не равно] и >.
  • Создайте вектор значений от одного до десяти и сравните его с числом 5, используя оператор >.
  • Создайте логическую переменную, которая принимает значение TRUE в тех случаях, когда ваш предыдущий вектор НЕ равен 9.
  • Создайте логическую переменную, которая принимает значение TRUE в тех случаях, когда значения вашего вектора больше 3 и меньше 7.
  • Создайте логическую переменную, которая принимает значение TRUE в тех случаях, когда значения вашего вектора меньше 3 или больше 7.
  • Очистите рабочее пространство.
fifty <- 50
twenty <- 20
fifty == twenty
> [1] FALSE
fifty != twenty
> [1] TRUE
fifty > twenty
> [1] TRUE
nvector <- c(1,2,3,4,5,6,7,8,9,10)

nvector > 5
>  [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE
three.seven <- nvector > 3 & nvector < 7
not.three.seven <- nvector < 3 | nvector > 7

3 🔡 Cоздание и индексирование data.frame

  • Поскольку data.frame – это таблица данных, все переменные должны быть одинаковой длины (содержать одинаковое количество элементов).
df <- data.frame(
  имя.переменной = вектор/переменная,
  имя.переменной = вектор/переменная,
  ...
)

3.1 Задание

  1. Создайте data.frame с двумя переменными, одна из которых числовая (от 5 до 1), вторая – фактор с любыми значениями.

  2. Создайте новую переменную в этом data.frame, которая имеет текстовое значение donda для всех случаев.

Новые переменные создаются через оператор присвоения, например

mydata$My.New.Variable <- 3
  1. Создайте новую логическую переменную в этом data.frame под названием more.than.three, которая принимала бы значения TRUE когда первая переменная больше 3.

3.2 Индексирование data.frame

плоская.таблица[строки, колонки]

Например по номеру строки или переменной:

mydata[1, 1]

Или по имени переменной

mydata[1,  "idno"]

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

mydata[,  "idno"]

или более коротко с использованием знака $ для обозначения колонки (переменной)

mydata$idno

3.3 Задание

  1. Попробуйте запустить каждую из следующих строк и посмотреть, какие части вашего data.frame будут отобраны
mydata[1, 1]
mydata[4, 3]
mydata[, 2]
mydata[2, ]
mydata[-1, ]
mydata[, -1]
mydata[, c(1, 3)]
mydata[, "more.than.three"]
mydata$more.than.three
mydata[mydata$more.than.three, ]
  • Какие из этих строк возвращают одинаковый результат?
  • Как работают отрицательные индексы (-1)?
  • Что происходит в последней строке?
  1. Отберите из массива третьи значения первой и второй переменных тремя способами:

    • по именам переменных,
    • по номерам переменных используя оператор :,
    • по номерам переменнах, используя функцию c().
  2. Отберите из массива строки, в которых первая переменная принимает значение меньше 3 не создавая при этом новой переменной.

3.4 Сортировка данных – задание

  1. Отсортируйте ваш объект с данными по первой (числовой) переменной, используя функцию order() и правила индексирования.

4 ↗️ Экспортирование данных и просмотр

Данные можно просматривать функцией View(), но если таблицу нужно экспортировать подойдут пакеты knitr и kableExtra

a <- data.frame(one = 1:5, two = 5:1)


library(knitr)  # подгружаем необходимые библиотеки
library(kableExtra)

tab1 <- kable(a)  # оформляем data.frame в таблицу

kable_styling(tab1)  # выводим таблицу на экран (дополнительно можно настроить опции вывода таблицы)
one two
1 5
2 4
3 3
4 2
5 1

4.1 Задание

  1. Установите пакеты knitr и kableExtra
  2. Экспортируйте ваш data.frame.

5 ⬇️ Импортирование данных

5.1 Установка пакета

  • установите пакет “foreign”, используя функцию install.packages
  • запустите пакет “foreign”, используя функцию library
  • откройте документацию пакета foreign во вкладке Packages и найдите функцию, которая может импортировать данные SPSS.

5.2 Считывание реальных данных

  • скачайте файл данных ESS7e02_1.sav;
  • переместите файл данных в вашу рабочую папку;
  • считайте эти данные, используя найденную вами функцию и сохраните в объект mydata.
mydata <- найденная.вами.функция(
  file = ... ,             # путь к файлу данных
  use.value.labels = ... , # нужно ли использовать ярлыки?
  use.missings = ...,          # включать ли пропущенные значения?
  to.data.frame = ...      # сформировать из данных data.frame?  
  )
mydata1 <- read.spss(
  file= "data/ESS7e02_1.sav",  # путь к файлу данных
  use.value.labels = TRUE,   # нужно ли использовать ярлыки/метки в качестве значений?
  use.missings = TRUE,         # включать ли пропущенные значения?
  to.data.frame = TRUE       # сформировать из данных data.frame?    
  )
  • Обратите внимание на аргументы use.value.labels, use.missings и to.data.frame - попробуйте выяснить, что они означают.
  • Запустите код и проверьте, появился ли соответствующий объект во вкладке Environment. Откройте его, посмотрите на содержимое.
  • Посмотрите на структуру этого объекта, используя функцию str().
  • Поменяйте значение аргумента use.value.labels на FALSE и посмотрите, как изменился результат. В дальнейшем используйте именно этот заново считанный массив.
mydata <- read.spss(
  file = "data/ESS7e02_1.sav",
  use.value.labels = FALSE,  # значение этого аргумента изменилось
  use.missings = TRUE,
  to.data.frame = TRUE
  )

str(mydata, list.len = 6)
> 'data.frame': 40185 obs. of  601 variables:
>  $ name    : chr  "ESS7e02_1   " "ESS7e02_1   " "ESS7e02_1   " "ESS7e02_1   " ...
>  $ essround: num  7 7 7 7 7 7 7 7 7 7 ...
>  $ edition : chr  "2.1" "2.1" "2.1" "2.1" ...
>  $ proddate: chr  "01.12.2016" "01.12.2016" "01.12.2016" "01.12.2016" ...
>  $ idno    : num  1 2 3 4 5 6 7 13 14 21 ...
>  $ cntry   : chr  "AT" "AT" "AT" "AT" ...
>   ..- attr(*, "value.labels")= Named chr [1:21] "SI      " "SE      " "PT      " "PL      " ...
>   .. ..- attr(*, "names")= chr [1:21] "Slovenia" "Sweden" "Portugal" "Poland" ...
>   [list output truncated]
>  - attr(*, "variable.labels")= Named chr [1:601] "Title of dataset" "ESS round" "Edition" "Production date" ...
>   ..- attr(*, "names")= chr [1:601] "name" "essround" "edition" "proddate" ...
>  - attr(*, "codepage")= int 1252

6 ✂️ Фильтрация

В разных ситуациях различные способы индексирования полезны. Существует много способов: через квадратные скобки (см. выше), базовый R subset(), filter() из пакета dplyr, функция ifelse() и т.д.

6.1 Задание 1

  • Узнайте тип переменной cntry используя функцию class()
  • Посчитайте частоты и заодно посмотрите на все возможные значения переменной cntry с помощью функции table().

6.2 Задание 2

  • создайте подмассив Belgium, используя логические значения как указатель строк. Для этого предварительно нужно создать логическую переменную, которая принимает значение TRUE когда переменная cntry равна значению BE (код Бельгии).
  • Проверьте, сколько наблюдений в новом подмассиве данных.
  • Теперь создайте фильтр и отсортируйте массив по двум параметрам - по гендеру (gndr) со значением 1 и стране (cntry) Бельгии.
  • Посмотрите на структуру нового подмассива данных, кликнув по этому объекту в окне Environment, либо воспользовавшись функцией str().
Belgium <- mydata[mydata$cntry=="BE", ]

# str(Belgium)

6.3 Задание 3

  • удалите из нового массива Belgium переменную idno.
  • удалите из этого массива все переменные, кроме agea, gndr, domicil, tvtot и polintr.
Belgium <- Belgium[,c('agea', 'domicil', 'tvtot', 'polintr', 'gndr')]

6.4 Задание 4

  • напишите в одну строку код, который создаст массив значений указанных выше переменных среди бельгийцев-мужчин;
  • отсортируйте в получившемся массиве переменные по алфавиту. Для того, чтобы вернуть вектор имен переменных используйте функцию colnames().

7 ✳️Добавление переменных в data.frame

Новые переменные можно добавлять напрямую приписывая им значения. Например,

Belgium$ones <- 1 # создаст константу, т.е. 1 для всех респондентов.

Belgium$female <- Belgium$gndr == 2 #  создаст логическую переменную.
  • Вычислите год рождения респондента, используя переменную возраст (agea) и год опроса (2014) и запишите его в новую переменную.
  • Проверьте, появилась ли эта переменная в массиве данных Belgium.

8 🔣 Перекодирование

Переменная polintr (интерес к политике) имеет обратную кодировку (1 = Very interested, 4 = Not at all interested). Перевернем ее кодировку, чтобы было удобнее интерпретировать результаты.

8.1 Ручной способ

# сначала создается переменная состоящая из пропущенных значений NA
Belgium$polintr.recoded <- NA 

# затем эта новая переменная наполняется с помощью индексирования по старой переменной и приписывания новых значений
Belgium$polintr.recoded[ Belgium$polintr == 4 ] <- 1
Belgium$polintr.recoded[ Belgium$polintr == 3 ] <- 2
Belgium$polintr.recoded[ Belgium$polintr == 2 ] <- 3
Belgium$polintr.recoded[ Belgium$polintr == 1 ] <- 4

# проверим результат
table(Belgium$polintr.recoded, Belgium$polintr)
>    
>       1   2   3   4
>   1   0   0   0 348
>   2   0   0 578   0
>   3   0 655   0   0
>   4 188   0   0   0

8.2 Перекодирование в пакете car

library("car")
Belgium$polintr.rec <- Recode(
  # Переменная, которую нужно перекодировать.
  var = Belgium$polintr,  
  # Перекодировка в формате {входящее значение = исходящее значение}
  recodes = "4=1; 3=2; 2=3; 1=4; else=NA",    
  # Сохранить ли переменную как factor, т.е. номинальную?
  as.factor = FALSE
  )

8.3 Задание

  • Установите пакет car.
  • Cчитайте данные ESS7e02_1.sav и отфильтруйте всех, кроме бельгийцев (закодировано “Belgium”, “BE” или 2).
  • Перекодируйте переменную domicil из numeric в класс переменных factor, т.е. в номинальную переменную под названием, например, big.city с тремя уровнями - большой город (1), окраины или маленький город (2 и 3), село или ферма (4 и 5).
  • Проверьте результат, построив таблицу сопряженности (table) исходной переменной и перекодированной.
library(car) # Запускаем пакет

Belgium$big.city <- Recode(
  var = Belgium$domicil,  # Переменная, которую нужно перекодировать.
  recodes = # Перекодировка в формате {входящее значение = исходящее значение}
    "     1  = 'Большой город';             
      c(2,3) = 'Окраина и небольшой город';  
      c(4,5) = 'Село';
      else=NA
    ",    
  as.factor=TRUE          # Сохранить ли переменную как factor, т.е. номинальную?
  )
table(Belgium$big.city)
> 
>             Большой город Окраина и небольшой город                      Село 
>                       232                       618                       919

9 🏷 Извлечение ярлыков/меток данных

9.1 Если данные считаны пакетом foreign

# 1. Сначала найдем нужные переменные
var.labels <- attr(mydata, "variable.labels")
var.labels[1:10]
>                                                            name 
>                                              "Title of dataset" 
>                                                        essround 
>                                                     "ESS round" 
>                                                         edition 
>                                                       "Edition" 
>                                                        proddate 
>                                               "Production date" 
>                                                            idno 
>                            "Respondent's identification number" 
>                                                           cntry 
>                                                       "Country" 
>                                                           tvtot 
>                    "TV watching, total time on average weekday" 
>                                                           tvpol 
> "TV watching, news/politics/current affairs on average weekday" 
>                                                         ppltrst 
>        "Most people can be trusted or you can't be too careful" 
>                                                         pplfair 
>   "Most people try to take advantage of you, or try to be fair"
# или, чтобы показать ярлыки/метки переменных в виде таблицы
as.data.frame(var.labels)[1:10,]
>  [1] "Title of dataset"                                             
>  [2] "ESS round"                                                    
>  [3] "Edition"                                                      
>  [4] "Production date"                                              
>  [5] "Respondent's identification number"                           
>  [6] "Country"                                                      
>  [7] "TV watching, total time on average weekday"                   
>  [8] "TV watching, news/politics/current affairs on average weekday"
>  [9] "Most people can be trusted or you can't be too careful"       
> [10] "Most people try to take advantage of you, or try to be fair"
# 2. затем можно смотреть на кодировку внутри каждой из переменных

attr(mydata$gndr, "value.labels")
> Female   Male 
>    "2"    "1"

9.2 Если данные считаны пакетом haven

mydat1 <- haven::read_spss("data/ESS7e02_1.sav")

attr(mydat1$cntry, "label")
> [1] "Country"
attr(mydat1$cntry, "labels")
> United Kingdom        Belgium        Germany        Estonia        Ireland         Sweden    Switzerland 
>           "GB"           "BE"           "DE"           "EE"           "IE"           "SE"           "CH" 
>        Finland       Slovenia        Denmark         Israel    Netherlands         Poland         Norway 
>           "FI"           "SI"           "DK"           "IL"           "NL"           "PL"           "NO" 
>         France          Spain        Austria      Lithuania       Portugal        Hungary Czech Republic 
>           "FR"           "ES"           "AT"           "LT"           "PT"           "HU"           "CZ"
# или, чтобы показать его в виде таблицы
as.data.frame(attr(mydat1$cntry, "labels"))
>                attr(mydat1$cntry, "labels")
> United Kingdom                           GB
> Belgium                                  BE
> Germany                                  DE
> Estonia                                  EE
> Ireland                                  IE
> Sweden                                   SE
> Switzerland                              CH
> Finland                                  FI
> Slovenia                                 SI
> Denmark                                  DK
> Israel                                   IL
> Netherlands                              NL
> Poland                                   PL
> Norway                                   NO
> France                                   FR
> Spain                                    ES
> Austria                                  AT
> Lithuania                                LT
> Portugal                                 PT
> Hungary                                  HU
> Czech Republic                           CZ

Полезная функция, которая автоматически извлекает ярлыки/метки значений и переменных:

labels_haven <- function(data, n) {
    lapply(data, function(x) {
           if(!is.null(attr(x, "labels"))) {
             val.tab = data.frame(values=attr(x, "labels"))
           } else {
             val.tab = data.frame(NA, NA)
           }
             list(Variable.label = attr(x, "label"),
                  values = val.tab)
            
          })[n]
}


labels_haven(mydat1, 10:11)
> $pplfair
> $pplfair$Variable.label
> [1] "Most people try to take advantage of you, or try to be fair"
> 
> $pplfair$values
>                                         values
> Most people try to take advantage of me      0
> 1                                            1
> 2                                            2
> 3                                            3
> 4                                            4
> 5                                            5
> 6                                            6
> 7                                            7
> 8                                            8
> 9                                            9
> Most people try to be fair                  10
> Refusal                                     77
> Don't know                                  88
> No answer                                   99
> 
> 
> $pplhlp
> $pplhlp$Variable.label
> [1] "Most of the time people helpful or mostly looking out for themselves"
> 
> $pplhlp$values
>                                       values
> People mostly look out for themselves      0
> 1                                          1
> 2                                          2
> 3                                          3
> 4                                          4
> 5                                          5
> 6                                          6
> 7                                          7
> 8                                          8
> 9                                          9
> People mostly try to be helpful           10
> Refusal                                   77
> Don't know                                88
> No answer                                 99

9.3 Задание

  1. Выясните, как закодирована переменная vote в используемых данных.
  2. Перекодируйте переменную vote в фактор с осмысленными категориями вместо чисел.

10 👻 Пропущенные значения

Подробнее в лекции 2

10.1 Типы пропущенных и полезные функции

  • Основной формат пропущенных значений – NA – “Not Available”.
  • Функция is.na() возвращает логические значения TRUE когда значения аргумента являются пропущенными NA.
  • Логические переменные можно суммировать (делить, умножать и т.д.), для этого R превращает их числовую переменную со значениями 1 (TRUE) и 0 (FALSE).
  • Функция na.omit() исключает из данных все строки/значения в которых есть NA.

10.2 Задание

  1. Создайте логическую переменную, которая принимает значение TRUE когда значения переменной vote являются пропущенными.
  2. Сколько пропущенных значений в переменной vote?
  3. Создайте подмассив данных с тремя переменными vote, gndr и agea, удалив из него строки с пропущенными значениями. Сколько строк в итоге осталось? А сколько было удалено? Какая переменная из этих трех содержит больше всего пропущенных значений?

11 👉 Большое задание

В данных 8 раунда ESS найдите переменные, содержащие информацию о здоровье, счастье и частоте молитв. Сделайте подмассив, содержащий эти три переменные и только тех респондентов, которые родились в 2000 году или позже и проживают в России. Перекодируйте все переменные так, чтобы бóльшие их значения соответствовали бóльшей выраженности признака (а не наоборот). Удалите все строки с пропущенными значениями. Отсортируйте итоговые данные по счастью и экспортируйте в красиво оформленном виде, чтобы таблицу можно было скопировать в Word.

Дополнительно – постройте точечный график (функция plot(x, y)), описывающий взаимосвязь между счастьем и здоровьем на этом подмассиве.

12 Дома - к следующему семинару

  1. Вспомните статистики парной связи (главы 2 и 3 из учебника Крыштановского; Глава 7 из учебника Кабакова): коэффициенты корреляции Спирмена и Пирсона, t-критерий, хи-квадрат, дисперсионный анализ (ANOVA), F-статистику.
  2. Найдите пакеты R, которые могут вычислять эти тесты.



Максим Руднев, 2018-2021 на основе RMarkdown.