Пакеты

R появился в 1993 году. Его “ядро” устаревает, но мир не стоит на месте и постоянно развивается. Следовательно, нужно вносить какие-то изменения в язых: улучшать и оптимизировать его функционал и так далее. Но изменение ядра может повлечь за собой серьезные последствия. Поэтому было принято не менять изначальный функционал, а создавать новые функции и методы. Функций очень много, и подгружать их все нет смысла. Для этого придумали пакеты(библиотеки), в которых лежат функции и многое другое, которые можно установить и начать ими пользоваться. Все пакеты распространяются через CRAN (Comprehensive R Archive Network).

Мы будем постоянно работать с различными пакетами, поэтому давайте научимся их устанавливать. Сначала нужно скачать пакет на наш компьютер, это нужно сделать только один раз. Сделать это можно с помощью функции install.packages(). Аргументом этой функции является название пакета в кавычках. Давайте установим пакет dplyr, который нужен для работы с набором данных.

install.packages('dplyr')

Отлично! Мы скачали пакет на свой компьютер. Чтобы начать пользоваться функционалом пакета, нужно подгрузить его с помощью команды library(). Аргументом этой функции также является название пакета, но вводить можно уже без кавычек. Эту команду нужно выполнять каждый раз, как вы заходите в RStudio и хотите воспользоваться функционалом пакета.

library('dplyr')

В нижнем правов окне есть вкладка “Packages”. В ней можно установить пакеты с помощью кнопки “Install”, обновить пакеты с помощью кнопки “Update”, а также увидеть список установленных пакетов на вашем компьютере. Галочкой отмечены пакеты, которые подгружены в данный момент.

Типы переменных

Переменная – это самый простой тип данных в R. Вы можете сохранить какое-либо значение под определённым названием. Помним, что название должно соблюдать некоторые правила.

К текущему моменту мы знаем следующие типы переменных в R:

  1. Числовой(numeric/integer/double)
  2. Строковый(character)
  3. Логический(logical)
  4. NA(not available)
  5. NaN(not a number)
(number <- 5)
## [1] 5
(name <- 'Ahmedushka')
## [1] "Ahmedushka"
(log <- TRUE)
## [1] TRUE
(na <- NA)
## [1] NA
(nan <- NaN)
## [1] NaN

Тип переменной всегда можно проверить с помощью функций class() и typeof(), а также семейства функций is.*. NA имеет на самом деле логический тип, а NaN числовой тип. Но их стоит выделять отдельно.

class(number)
## [1] "numeric"
class(name)
## [1] "character"
class(log)
## [1] "logical"
class(na)
## [1] "logical"
class(nan)
## [1] "numeric"

Иногда нужно менять тип переменной. Для этого используется семейство функций as.*.

  • as.numeric(as.integer)
  • as.character
  • as.logical

Создадим строковую переменную n равную “10”.

n <- "10"
class(n)
## [1] "character"

С такой переменной нельзя даже выполнить какие-либо арифметические операции. Поэтому преобразуем ее к числовому типу.

n <- as.numeric(n)
class(n)
## [1] "numeric"

Семейство функций может работать и с массивами.

(x <- 1:5)
## [1] 1 2 3 4 5
(y <- as.character(x))
## [1] "1" "2" "3" "4" "5"
(class(x))
## [1] "integer"
(class(y))
## [1] "character"

Рассмотрим еще два типа переменных:

  • Категориальный или факторный(factor)
  • Дата и время (date)

Факторный тип переменных

Факторный тип переменных – это фиксированны набор строковых переменных, на которых можно установить какой-то порядок, то есть сравнить друг с другом эти строковые переменные.

Например, название месяцев. Их фиксированное количество(12) и на них установлен порядок: февраль(2) > январь(1).

Давайте разбремся зачем нужны факторные переменные. Представьте, что у вас есть массив, в котором записаны названия месяцев.

year1 <- c('Dec', 'Jan', 'Apr', 'Mar')

При использовании обычного массива у вас возникают 2 проблемы:

  1. Этот список сортируется в алфавитном порядке, а не в том порядке, который мы хотели бы:
sort(year1)
## [1] "Apr" "Dec" "Jan" "Mar"
  1. Возможны опечатки:
year2 <- c('Dec', 'Jam', 'Apr', 'Mar')

Эти 2 проблемы можно избежать с помощью факторного типа переменных. Он создается с помощью функции factor. Также у этой функции есть аргумент levels, в который можно передать список допустимых значений и порядок:

months <- c('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec') 
year1_2 <- factor(year1, levels = months)
year2_2 <- factor(year2, levels = months)
class(year1_2)
## [1] "factor"

Если мы совершим ошибку, то выставится значение NA. А теперь попробуем отсортировать наш фактор.

sort(year1_2)
## [1] Jan Mar Apr Dec
## Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec

Для создания факторного типа, можно испольовать функцию as.factor().

Тип переменной дата и время

Даты очень важны в анализе данных. Например, при работе с временными рядами. Самым простым способом создания даты и времени являются базовые функции Sys.Date() и Sys.time(), которые

(date <- Sys.Date())
## [1] "2020-09-29"
(time <- Sys.time())
## [1] "2020-09-29 22:56:01 MSK"
(class(date))
## [1] "Date"
(class(time))
## [1] "POSIXct" "POSIXt"

Обычно время дано в виде строковой переменной. С помощью базовых функций as.Date() и as.POSIXct() можно создавать переменные типа дата и время. Но мы не будем пользоваться этими старыми не очень удорбными функциями. Мы будем использовать современные функции из пакета lubridate, который предназначен для работы со временем. Давайте установим и подгрузим этот пакет.

# install.packages('lubridate')
library('lubridate')

Рассмотрим основные функции в этом пакете:

  • dmy
  • dym
  • mdy
  • myd
  • ymd
  • ydm

Все эти функции расшифровываются как day month year, только в разном порядке. Эти функции позволяют из строковой или числовой переменной получить переменную с типом дата. Порядок букв означает в каком порядке представлена дата. Если в дате сначала идет день, потом месяц и потом год, то нужно использовать функцию dmy. Давайте попробуем.

(mdy("January 18 2005"))
## [1] "2005-01-18"
(ymd('01/02/03'))
## [1] "2001-02-03"
(d <- dmy(10092018))
## [1] "2018-09-10"
(class(d))
## [1] "Date"

Все даты приведены к формату “year-month-day”. Эти функции могут работать и с массивами.

x <- c("09-01-01", "09-01-02", "09-01-03")
ymd(x)
## [1] "2009-01-01" "2009-01-02" "2009-01-03"

Мы еще более подробно поговорим о пакете lubridate и о работе с факторными переменными.

Контейнеры для хранения данных

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

  1. Переменная
  2. Массив(вектор)
  3. Матрица

Про каждый из контейнеров мы говорили. Давайте только вспомним, что массив может состоять только из переменных одного типа. Матрица – это двумерный массив, поэтому тоже может состоять только из переменных одного типа.

Формат данных для анализа

То, как должны выглядеть данные зависит от задачи. Мы можем работать с временными рядами, картинками, видео и многим другим. От того с какими данными мы работаем, зависит как они должны выглядеть. В этом курсе мы будем работать с данными типа наблюдения(observations) – переменные(variables). Давайте рассмотрим эту концепцию на примере.

Name Age Gender Birthday Homework grade
Jack 19 M 10 May 2000 A
Emma 21 F 22 February 1998 B+
Henry 18 M 3 September 2001 C-
Aria 20 F 26 June 1999 D

В этом наборе данных каждая строчка это наблюдение о каком-то человеке. А какждый столбце это переменная, которая описывает какую-то характеристику людей. Важно заметить, что столбцы – это массивы, так как они содержат один тип переменных.

  • Name – строковый(character)
  • Age – числовой(numeric)
  • Gender – категориальный(без порядка)(factor)
  • Birthday – дата(date)
  • Homework grade – категориальный(с порядком)(factor)

То есть, набор данных – это набор массивов с разным типом переменных. Матрица, как говорилось ранее, не подходит под это описание. Для хранения такого набора данных был придуман data frame(дата фрейм или фрейм данных), коротко df. Грубо говоря, это матрица, состоящая из массивов рызных типов переменных.

Data Frame

Давайте создадим наш первый data frame. Для этого нам нужна функция data.frame, в которой мы даем название нашим переменным и передаем массив значений. Создадим набор данных, который разбирали выше.

df <- data.frame('Name' = c('Jack', 'Emma', 'Henry', 'Aria'),
                   'Age' = c(19, 21, 18, 20),
                   'Gender' = c('M', 'F', 'M', 'F'),
                   'Birthday' = c('10 May 2000', '22 February 1998', 
                                  '3 September 2001', '26 June 1999'),
                   'Homework grade' = c('A', 'B+', 'C-', 'D'),
                   stringsAsFactors = FALSE)
print(df)
##    Name Age Gender         Birthday Homework.grade
## 1  Jack  19      M      10 May 2000              A
## 2  Emma  21      F 22 February 1998             B+
## 3 Henry  18      M 3 September 2001             C-
## 4  Aria  20      F     26 June 1999              D

При использовании функции, мы установили аргумент stringsAsFactors = FALSE, чтобы строковые переменные не форматировались в факторные.

Посмотреть на наш df под названием data можно с помощью функции print(). Также можно использовать функцию View() или нажать на df в верхнем левом окне, где находятся все наши переменные, функции и прочее.

View(df)

Заметим, что название переменной “Homework grade” изменилось на “Homework.grade”. Это происхоит, потому что data frame запрещает иметь в названии пробелы, а также он запрещает называть переменные, начиная с цифр или символов.

Давайте начнем работать с нашим набором данных. Во-первых, давайте убедимся, что перед нами правда df. Сделаем это с помощью функции class.

class(df)
## [1] "data.frame"

Давайте посмотрим на размерность нашего df. Для этого используем функции nrow() и ncol().

(nrow(df)) # количество наблюдений
## [1] 4
(ncol(df)) # количество переменных
## [1] 5

Видим, что у нас есть 4 наблюдения и 5 переменных. Чтобы получить эти два числа сразу, можно использовать функцию dim().

dim(df)
## [1] 4 5

Фреймы данных бывают очень большие, поэтмому посмотреть вручную столбцы и наблюения бывает сложно. Когда вы только начинаете работать с таким df, лучше сначала использовать функцию str. Она показывает его структуру.

str(df)
## 'data.frame':    4 obs. of  5 variables:
##  $ Name          : chr  "Jack" "Emma" "Henry" "Aria"
##  $ Age           : num  19 21 18 20
##  $ Gender        : chr  "M" "F" "M" "F"
##  $ Birthday      : chr  "10 May 2000" "22 February 1998" "3 September 2001" "26 June 1999"
##  $ Homework.grade: chr  "A" "B+" "C-" "D"

Можно увидеть уже знакомую нам информацию, что мы имеем дело с df, у которого 4 наблюдения и 5 переменных, а также информацию по каждому столбцу(переменной). После названия столбца(переменной) идет тип переменных в нем.

Обратиться к какой-то переменной можно с помощью $. Сначала пишем название df, потом ставим $ и пишем название переменной, данные по которой мы хотим получить.

df$Age # массив, состоящий из значений возраста
## [1] 19 21 18 20

При создании df, мы не использовали только строковый и числовой тип переменных. Чтобы работать с нужными типами переменных, используем функции, которые изучили ранее.

df$Gender <- factor(df$Gender)
df$Birthday <- dmy(df$Birthday)
df$Homework.grade <- factor(df$Homework.grade, 
                              levels = c('A', 'A-', 'B+', 'B', 'B-', 'C+', 'C',
                                         'C-', 'D+', 'D', 'E', 'F'))

Посмотрим теперь на структуру нашего df.

str(df)
## 'data.frame':    4 obs. of  5 variables:
##  $ Name          : chr  "Jack" "Emma" "Henry" "Aria"
##  $ Age           : num  19 21 18 20
##  $ Gender        : Factor w/ 2 levels "F","M": 2 1 2 1
##  $ Birthday      : Date, format: "2000-05-10" "1998-02-22" ...
##  $ Homework.grade: Factor w/ 12 levels "A","A-","B+",..: 1 3 8 10

Наш датасет(df) очень маленький. В R и его пакетах есть встроенные датасеты. Давайте воспользуемся датасетом mtcars. Об этом датасете можно подробнее прочитать с помощью команды ?mtcars. Этот датасет о характеристиках машин 1974 года.

Можно написать в консоли mtcars, и мы увидим этот датасет. Но лучше подгрузить его, чтобы мы видели его в верхнем правом окне. Это можно сделать с помощью функции data.

data(mtcars)

Изучим структуру набора данных.

str(mtcars)
## 'data.frame':    32 obs. of  11 variables:
##  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: num  160 160 108 258 360 ...
##  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
##  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
##  $ qsec: num  16.5 17 18.6 19.4 17 ...
##  $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
##  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

Видим, что имеется 32 наблюдения и 11 переменных, все из которых числовые. Когда датасет очень большой, неудобно просматривать его весь. Обычно смотрят на первые и последние 6 наблюдений с помощью функций head и tail. Можно выводить другое количество наблюдений на экран с помощью парметра n.

head(mtcars)
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
tail(mtcars, n = 3)
##                mpg cyl disp  hp drat   wt qsec vs am gear carb
## Ferrari Dino  19.7   6  145 175 3.62 2.77 15.5  0  1    5    6
## Maserati Bora 15.0   8  301 335 3.54 3.57 14.6  0  1    5    8
## Volvo 142E    21.4   4  121 109 4.11 2.78 18.6  1  1    4    2

Датасет очень похож на матрицу. Он тоже двумерный, поэтому к нему можно обращаться как к матрице. Давайте найдем значение в 1 строке(наблюдении), во 2 столбце(переменной). Выведем полностью 1 строку(наблюдение) и 3 столбец(переменную).

mtcars[1, 2]
## [1] 6
mtcars[1, ]
##           mpg cyl disp  hp drat   wt  qsec vs am gear carb
## Mazda RX4  21   6  160 110  3.9 2.62 16.46  0  1    4    4
mtcars[, 3]
##  [1] 160.0 160.0 108.0 258.0 360.0 225.0 360.0 146.7 140.8 167.6 167.6 275.8
## [13] 275.8 275.8 472.0 460.0 440.0  78.7  75.7  71.1 120.1 318.0 304.0 350.0
## [25] 400.0  79.0 120.3  95.1 351.0 145.0 301.0 121.0

Можно получать срезы. Например мне нужны 1-3 наблюдения и 2-4 переменные.

mtcars[1:3,2:4]
##               cyl disp  hp
## Mazda RX4       6  160 110
## Mazda RX4 Wag   6  160 110
## Datsun 710      4  108  93

Чтобы получить полный список названий переменных, можно использовать функцию names. На выходе вы получите массив названий переменных.

names(mtcars)
##  [1] "mpg"  "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"   "am"   "gear"
## [11] "carb"

Переменные можно выбирать и с помощью названия.

mtcars[1:3,"disp"]
## [1] 160 160 108

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

mtcars$wt
##  [1] 2.620 2.875 2.320 3.215 3.440 3.460 3.570 3.190 3.150 3.440 3.440 4.070
## [13] 3.730 3.780 5.250 5.424 5.345 2.200 1.615 1.835 2.465 3.520 3.435 3.840
## [25] 3.845 1.935 2.140 1.513 3.170 2.770 3.570 2.780

Можно получить сводную статистику по каждой переменной с помощью функции summary.

summary(mtcars)
##       mpg             cyl             disp             hp       
##  Min.   :10.40   Min.   :4.000   Min.   : 71.1   Min.   : 52.0  
##  1st Qu.:15.43   1st Qu.:4.000   1st Qu.:120.8   1st Qu.: 96.5  
##  Median :19.20   Median :6.000   Median :196.3   Median :123.0  
##  Mean   :20.09   Mean   :6.188   Mean   :230.7   Mean   :146.7  
##  3rd Qu.:22.80   3rd Qu.:8.000   3rd Qu.:326.0   3rd Qu.:180.0  
##  Max.   :33.90   Max.   :8.000   Max.   :472.0   Max.   :335.0  
##       drat             wt             qsec             vs        
##  Min.   :2.760   Min.   :1.513   Min.   :14.50   Min.   :0.0000  
##  1st Qu.:3.080   1st Qu.:2.581   1st Qu.:16.89   1st Qu.:0.0000  
##  Median :3.695   Median :3.325   Median :17.71   Median :0.0000  
##  Mean   :3.597   Mean   :3.217   Mean   :17.85   Mean   :0.4375  
##  3rd Qu.:3.920   3rd Qu.:3.610   3rd Qu.:18.90   3rd Qu.:1.0000  
##  Max.   :4.930   Max.   :5.424   Max.   :22.90   Max.   :1.0000  
##        am              gear            carb      
##  Min.   :0.0000   Min.   :3.000   Min.   :1.000  
##  1st Qu.:0.0000   1st Qu.:3.000   1st Qu.:2.000  
##  Median :0.0000   Median :4.000   Median :2.000  
##  Mean   :0.4062   Mean   :3.688   Mean   :2.812  
##  3rd Qu.:1.0000   3rd Qu.:4.000   3rd Qu.:4.000  
##  Max.   :1.0000   Max.   :5.000   Max.   :8.000

В ней мы видим:

  • минимуальное значение;
  • значение 1 квартиля;
  • значение 2 квартиля(медиану);
  • среднее;
  • значение 3 квартиля;
  • максимальное значение.

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

Переменная cyl показывает количество цилиндров в машине. Можно увидеть сколько наблюдений приходится на определенное количество цилиндров с помощью функции table, то есть понять сколько машин есть в выборке с 4-мя цилиндрами, 6-ю и так далее.

table(mtcars$cyl)
## 
##  4  6  8 
## 11  7 14

Можно получить не количество машин, а их долю.

table(mtcars$cyl)/sum(table(mtcars$cyl))
## 
##       4       6       8 
## 0.34375 0.21875 0.43750

Больше сводной статистики можно получить с помощью пакета psych. Давайте его установим и подгрузим.

# install.packages('psych')
library(psych)

В пакете есть функция describe. Она нам и нужна! Она выдает очень много статистик.

describe(mtcars)
##      vars  n   mean     sd median trimmed    mad   min    max  range  skew
## mpg     1 32  20.09   6.03  19.20   19.70   5.41 10.40  33.90  23.50  0.61
## cyl     2 32   6.19   1.79   6.00    6.23   2.97  4.00   8.00   4.00 -0.17
## disp    3 32 230.72 123.94 196.30  222.52 140.48 71.10 472.00 400.90  0.38
## hp      4 32 146.69  68.56 123.00  141.19  77.10 52.00 335.00 283.00  0.73
## drat    5 32   3.60   0.53   3.70    3.58   0.70  2.76   4.93   2.17  0.27
## wt      6 32   3.22   0.98   3.33    3.15   0.77  1.51   5.42   3.91  0.42
## qsec    7 32  17.85   1.79  17.71   17.83   1.42 14.50  22.90   8.40  0.37
## vs      8 32   0.44   0.50   0.00    0.42   0.00  0.00   1.00   1.00  0.24
## am      9 32   0.41   0.50   0.00    0.38   0.00  0.00   1.00   1.00  0.36
## gear   10 32   3.69   0.74   4.00    3.62   1.48  3.00   5.00   2.00  0.53
## carb   11 32   2.81   1.62   2.00    2.65   1.48  1.00   8.00   7.00  1.05
##      kurtosis    se
## mpg     -0.37  1.07
## cyl     -1.76  0.32
## disp    -1.21 21.91
## hp      -0.14 12.12
## drat    -0.71  0.09
## wt      -0.02  0.17
## qsec     0.34  0.32
## vs      -2.00  0.09
## am      -1.92  0.09
## gear    -1.07  0.13
## carb     1.26  0.29

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

describeBy(mtcars, group = mtcars$cyl)
## 
##  Descriptive statistics by group 
## group: 4
##      vars  n   mean    sd median trimmed   mad   min    max range  skew
## mpg     1 11  26.66  4.51  26.00   26.44  6.52 21.40  33.90 12.50  0.26
## cyl     2 11   4.00  0.00   4.00    4.00  0.00  4.00   4.00  0.00   NaN
## disp    3 11 105.14 26.87 108.00  104.30 43.00 71.10 146.70 75.60  0.12
## hp      4 11  82.64 20.93  91.00   82.67 32.62 52.00 113.00 61.00  0.01
## drat    5 11   4.07  0.37   4.08    4.02  0.34  3.69   4.93  1.24  1.00
## wt      6 11   2.29  0.57   2.20    2.27  0.54  1.51   3.19  1.68  0.30
## qsec    7 11  19.14  1.68  18.90   18.99  1.48 16.70  22.90  6.20  0.55
## vs      8 11   0.91  0.30   1.00    1.00  0.00  0.00   1.00  1.00 -2.47
## am      9 11   0.73  0.47   1.00    0.78  0.00  0.00   1.00  1.00 -0.88
## gear   10 11   4.09  0.54   4.00    4.11  0.00  3.00   5.00  2.00  0.11
## carb   11 11   1.55  0.52   2.00    1.56  0.00  1.00   2.00  1.00 -0.16
##      kurtosis   se
## mpg     -1.65 1.36
## cyl       NaN 0.00
## disp    -1.64 8.10
## hp      -1.71 6.31
## drat     0.12 0.11
## wt      -1.36 0.17
## qsec    -0.02 0.51
## vs       4.52 0.09
## am      -1.31 0.14
## gear    -0.01 0.16
## carb    -2.15 0.16
## ------------------------------------------------------------ 
## group: 6
##      vars n   mean    sd median trimmed   mad    min    max  range  skew
## mpg     1 7  19.74  1.45  19.70   19.74  1.93  17.80  21.40   3.60 -0.16
## cyl     2 7   6.00  0.00   6.00    6.00  0.00   6.00   6.00   0.00   NaN
## disp    3 7 183.31 41.56 167.60  183.31 11.27 145.00 258.00 113.00  0.80
## hp      4 7 122.29 24.26 110.00  122.29  7.41 105.00 175.00  70.00  1.36
## drat    5 7   3.59  0.48   3.90    3.59  0.03   2.76   3.92   1.16 -0.74
## wt      6 7   3.12  0.36   3.21    3.12  0.36   2.62   3.46   0.84 -0.22
## qsec    7 7  17.98  1.71  18.30   17.98  1.90  15.50  20.22   4.72 -0.12
## vs      8 7   0.57  0.53   1.00    0.57  0.00   0.00   1.00   1.00 -0.23
## am      9 7   0.43  0.53   0.00    0.43  0.00   0.00   1.00   1.00  0.23
## gear   10 7   3.86  0.69   4.00    3.86  0.00   3.00   5.00   2.00  0.11
## carb   11 7   3.43  1.81   4.00    3.43  0.00   1.00   6.00   5.00 -0.26
##      kurtosis    se
## mpg     -1.91  0.55
## cyl       NaN  0.00
## disp    -1.23 15.71
## hp       0.25  9.17
## drat    -1.40  0.18
## wt      -1.98  0.13
## qsec    -1.75  0.65
## vs      -2.20  0.20
## am      -2.20  0.20
## gear    -1.24  0.26
## carb    -1.50  0.69
## ------------------------------------------------------------ 
## group: 8
##      vars  n   mean    sd median trimmed   mad    min    max  range  skew
## mpg     1 14  15.10  2.56  15.20   15.15  1.56  10.40  19.20   8.80 -0.36
## cyl     2 14   8.00  0.00   8.00    8.00  0.00   8.00   8.00   0.00   NaN
## disp    3 14 353.10 67.77 350.50  349.63 73.39 275.80 472.00 196.20  0.45
## hp      4 14 209.21 50.98 192.50  203.67 44.48 150.00 335.00 185.00  0.91
## drat    5 14   3.23  0.37   3.12    3.19  0.16   2.76   4.22   1.46  1.34
## wt      6 14   4.00  0.76   3.76    3.95  0.41   3.17   5.42   2.25  0.99
## qsec    7 14  16.77  1.20  17.18   16.86  0.79  14.50  18.00   3.50 -0.80
## vs      8 14   0.00  0.00   0.00    0.00  0.00   0.00   0.00   0.00   NaN
## am      9 14   0.14  0.36   0.00    0.08  0.00   0.00   1.00   1.00  1.83
## gear   10 14   3.29  0.73   3.00    3.17  0.00   3.00   5.00   2.00  1.83
## carb   11 14   3.50  1.56   3.50    3.25  0.74   2.00   8.00   6.00  1.48
##      kurtosis    se
## mpg     -0.57  0.68
## cyl       NaN  0.00
## disp    -1.26 18.11
## hp       0.09 13.62
## drat     1.08  0.10
## wt      -0.71  0.20
## qsec    -0.92  0.32
## vs        NaN  0.00
## am       1.45  0.10
## gear     1.45  0.19
## carb     2.24  0.42

Tibble

Функция data.frame была придумана 10-20 лет назад. Но мир не стоит на месте. R развивается, многие функции улучшаются и оптимизируются. Сейчас все пользуются функцией tibble для создания df. Данная функция находится в одноименном пакете tibble. Удалить функцию data.frame нельзя, потому что можно поставить работоспособность существующего кода. Я советую пользоваться tibble, так как он является ядром библиотеки tidyverse с которой мы будем работать весь курс.Все пакеты в этой библиотеке взаимосвязаны и предназначены для работы с tibble. Давайте подгрузим пакет.

# install.packages('tibble')
library('tibble')

У tibble есть красивая справка. Её можно вызвать с помощью команды vignette('tibble'). Давайте создадим первый датасет.

df <- tibble(
        x = 1:5,
        y = 1,
        c = 'a', 
        z = x^2 + y,
        `:)` = 10,
        ` ` = NA
      )
df
## # A tibble: 5 x 6
##       x     y c         z  `:)` ` `  
##   <int> <dbl> <chr> <dbl> <dbl> <lgl>
## 1     1     1 a         2    10 NA   
## 2     2     1 a         5    10 NA   
## 3     3     1 a        10    10 NA   
## 4     4     1 a        17    10 NA   
## 5     5     1 a        26    10 NA

Заметим некоторые отличия от функции data.frame:

  • Можно ссылаться на уже созданные переменные(переменная z).
  • С помощью апострофа(`) можно давать любые названия переменным.
  • При отображении tibble под названиями переменных появляется тип переменных.
  • Для удобного отображения появляются только первые 10 наблюдений и все переменные, которые помещаются в пределах экрана.

Также бывает удобным задавать tibble в виде таблицы. Для этого можно использовать функцию tribble. Давайте попробуем.

df1 <- tribble(
        ~x, ~y, ~z,
        #--|--|---
        "a", 2, 3.6,
        "b", 1, 8.5
       )
df1
## # A tibble: 2 x 3
##   x         y     z
##   <chr> <dbl> <dbl>
## 1 a         2   3.6
## 2 b         1   8.5

Часто некоторые базовые функции не работают с tibble или некоторые функции из пакетов не очень хорошо работают с data.frame. В таких случаях вы можете перевести tibble в data.frame и наоборот с помощью функций as_tibble и as.data.frame.

as_tibble(mtcars)
## # A tibble: 32 x 11
##      mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
##    <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1  21       6  160    110  3.9   2.62  16.5     0     1     4     4
##  2  21       6  160    110  3.9   2.88  17.0     0     1     4     4
##  3  22.8     4  108     93  3.85  2.32  18.6     1     1     4     1
##  4  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
##  5  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
##  6  18.1     6  225    105  2.76  3.46  20.2     1     0     3     1
##  7  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
##  8  24.4     4  147.    62  3.69  3.19  20       1     0     4     2
##  9  22.8     4  141.    95  3.92  3.15  22.9     1     0     4     2
## 10  19.2     6  168.   123  3.92  3.44  18.3     1     0     4     4
## # … with 22 more rows
as.data.frame(df)
##   x y c  z :)   
## 1 1 1 a  2 10 NA
## 2 2 1 a  5 10 NA
## 3 3 1 a 10 10 NA
## 4 4 1 a 17 10 NA
## 5 5 1 a 26 10 NA

Функция str так же устарела. На смену ей пришла функция glimpse из пакета dplyr, который мы установили и подгрузили в самом начале.

glimpse(df)
## Rows: 5
## Columns: 6
## $ x    <int> 1, 2, 3, 4, 5
## $ y    <dbl> 1, 1, 1, 1, 1
## $ c    <chr> "a", "a", "a", "a", "a"
## $ z    <dbl> 2, 5, 10, 17, 26
## $ `:)` <dbl> 10, 10, 10, 10, 10
## $ ` `  <lgl> NA, NA, NA, NA, NA

Визуализация

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

hist(mtcars$mpg, breaks = 30)

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

plot(mtcars$disp, mtcars$mpg)

Данные функции так же устарели. Графики получаются некрасивыми. Поэтому в этом курсе мы будем пользоваться пакетом ggplot2 для более продвинутой и красивой визуализации.

# install.packages('ggplot2')
library('ggplot2')

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

Гистограмма распределения.

ggplot(mtcars, aes(x = mpg)) +
  geom_histogram() 
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Диаграмма рассеяния.

ggplot(mtcars, aes(x = disp, y = mpg)) +
  geom_point() 

List

Список(list) – это более усложненный вариант массива. В массиве мы могли хранить набор чисел или строк. Но не могли записать в первое значение массива еще один массив или матрицу. Для этого и был придуман список. Внутри него можно хранить любые данные.

Создавать списки можно с помощью функции list.

x <- list(1, 2, 3)
x
## [[1]]
## [1] 1
## 
## [[2]]
## [1] 2
## 
## [[3]]
## [1] 3

Можно посмотреть на структуру нашего списка с помощью уже известной нам функции str.

str(x)
## List of 3
##  $ : num 1
##  $ : num 2
##  $ : num 3

Можно давать имена объектам списка.

x <- list(a = 1, b = 2, c = 3)
str(x)
## List of 3
##  $ a: num 1
##  $ b: num 2
##  $ c: num 3

Список, который мы создали, можно было сделать и с помощью массива. Но списки могут хранить переменные разного типа.

y <- list('a', TRUE, 42.24)
str(y)
## List of 3
##  $ : chr "a"
##  $ : logi TRUE
##  $ : num 42.2

В списках можно хранить массивы, матрицы и другие объекты.

z <- list(1:10, matrix(0, 3,3))
z
## [[1]]
##  [1]  1  2  3  4  5  6  7  8  9 10
## 
## [[2]]
##      [,1] [,2] [,3]
## [1,]    0    0    0
## [2,]    0    0    0
## [3,]    0    0    0

В списках можно хранить списки!

k <- list(list(1, 2), list(3, 4), list(5, 6))
k
## [[1]]
## [[1]][[1]]
## [1] 1
## 
## [[1]][[2]]
## [1] 2
## 
## 
## [[2]]
## [[2]][[1]]
## [1] 3
## 
## [[2]][[2]]
## [1] 4
## 
## 
## [[3]]
## [[3]][[1]]
## [1] 5
## 
## [[3]][[2]]
## [1] 6
str(k)
## List of 3
##  $ :List of 2
##   ..$ : num 1
##   ..$ : num 2
##  $ :List of 2
##   ..$ : num 3
##   ..$ : num 4
##  $ :List of 2
##   ..$ : num 5
##   ..$ : num 6

Вообще список можно представить как обычный пакет. В пакете вы можете хранить какие-то вещи(переменные, массивы, матрицы и df). В этом же пакете у вас могут быть еще пакеты, внутри которых тоже что-то есть.

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

a <- list(a = 1:3, b = 'Hello', c = pi, d = list(-1, -5))
a
## $a
## [1] 1 2 3
## 
## $b
## [1] "Hello"
## 
## $c
## [1] 3.141593
## 
## $d
## $d[[1]]
## [1] -1
## 
## $d[[2]]
## [1] -5
  • [ – извлекает подсписок.
str(a[1:2])
## List of 2
##  $ a: int [1:3] 1 2 3
##  $ b: chr "Hello"
str(a[4])
## List of 1
##  $ d:List of 2
##   ..$ : num -1
##   ..$ : num -5
  • [[ – извлекает одиночный компонент списка.
print(a[[1]])
## [1] 1 2 3
print(a[[2]])
## [1] "Hello"
print(a[['c']])
## [1] 3.141593
  • $ – извлечение по имени элемента списка.
print(a$b)
## [1] "Hello"

Разница между [ и [[ играет важную роль, так как [[ проникает в список, тогда как [ возращает новый список меньшего размера.

Объекты списка можно изменять.

a[[1]] <- c(a[[1]], 4)
a[[1]][4]
## [1] 4

Если список состоит из одиночных элементов одного типа, при необходимости его можно быстро превратить в обычный вектор с помощью функции unlist():

l <- list(c("a", "b", "c"))
l
## [[1]]
## [1] "a" "b" "c"
unlist(l)
## [1] "a" "b" "c"