---
title: "Основы программирования в R"
subtitle: "Списки в R"
author: "Алла Тамбовцева, НИУ ВШЭ"
output:
  pdf_document:
    latex_engine: xelatex
    toc: true
mainfont: CMU Serif
header-includes:
- \usepackage[russian]{babel}
- \usepackage{hyperref}
- \hypersetup{colorlinks = true, urlcolor = blue, linkcolor=magenta}
---

## Создание списков 

Если сравнивать списки (*lists*) в R со структурами данных в Python, списки можно сравнить со словарями: они могут обладать вложенной структурой и хранить в себе объекты разных типов. В то же время списки в Python и списки в R похожи. Списки в R – это вложенные списки в Python.

Посмотрим на пример списка, который содержит в себе два числовых вектора:

```{r}
L <- list(c(1, 2, 3, 4), c(5, 6, 7))
L
```

А теперь на пример списка с векторами разных типов:

```{r}
grades <- list(c("Ann", "Sam", "Tom"), c(8, 7, 5))
grades
```

Что интересно, в список можно объединять не только вектора, но и структуры разных типов. Например, мы можем создать список с описанием датафрейма (строки, тип *character*) и самим датафреймом (тип *data.frame*). Для начала посмотрим на встроенный в R датафрейм `mtcars`:

```{r}
mtcars
```

А теперь создадим список `dat`, который содержит название датафрейма, его краткое описание и сам датафрейм:

```{r}
dat <- list("mtcars", "from R", mtcars)
dat
```

Получилось!

Так как в списках может храниться большое число разных векторов, для удобства им можно давать названия. Список `grades` можно было записать и так:

```{r}
grades <- list(names = c("Ann", "Sam", "Tom"), marks = c(8, 7, 5))
grades
```

## Работа с элементами списка

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

```{r}
L[[1]]
```

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

```{r}
L[1]
```

Но разница есть. В первом случае (двойные квадратные скобки) мы получаем сразу вектор, а во втором (одинарные квадратные скобки) — маленький список, внутри которого вектор. Сравним типы результатов:

```{r}
class(L[[1]])
class(L[1])
```

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

```{r}
grades$names
grades$marks
```

Если нужно обратиться к «элементу элемента» списка, нужно сначала указать номер вектора, в котором находится элемент, а затем номер самого элемента в этом векторе. Выберем второй элемент в первом векторе списка `L`: 

```{r}
L[[1]][2]
```

Можно заметить, что список похож на матрицу: для того, чтобы обратиться к элементу, нужно указать «строку» (вектор) и «столбец» (положение в векторе).

А теперь выберем третий элемент вектора `names`:

```{r}
grades$names[3]
```

Для того, чтобы добавить элемент в список, нужно чётко понимать положение элемента в этом списке: будет ли это элементом самого списка или «элементом элемента. Добавим в список `L` третий элемент:

```{r}
L[[3]] <- c(0, 9)
L
```

А теперь аналогичным образом изменим первый элемент второго вектора:

```{r}
L[[2]][1] <- 50
L
```

Запросим структуру списков с помощью функцию `str()`:

```{r}
str(grades)
str(L)
```

## Списки в статистике

Со списками легко можно встретиться, создавая статистические модели. Многие статистические функции выдают результат в виде списков. Когда результаты выводятся на экран, это не всегда заметно, но если мы захотим заглянуть внутрь, то увидим, что та же регрессионная выдача представляет собой объект, похожий на список, из которого можно выбрать вектор коэффициентов (`coefficients`), вектор остатков (`residuals`), предсказанных значений (`fitted.values`) и так далее. 

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

```{r}
model <- lm(data = mtcars, hp ~ cyl)
model
```

Интерпретировать полученную модель мы пока не будем, а лучше посмотрим на её структуру:

```{r}
str(model)
```

Внутри модель, действительно, выглядит как список!

## Преобразование списков

При необходимости структуру списка можно упростить — превратить его в вектор с помощью функции `unlist()`. Если в списке всего один вектор, он таковым и останется:

```{r}
small <- list(c("a", "b", "c"))
small
```

```{r}
unlist(small)
```

А если в списке несколько векторов, тогда все склеится в один длинный вектор: 

```{r}
unlist(L)
```

