class: center, middle, inverse, title-slide .title[ # Структуры данных и циклы ] .subtitle[ ## Программирование и анализ данных ] .author[ ### Тимофей Самсонов ] .institute[ ### МГУ имени Ломоносова, Географический факультет ] .date[ ### 2024-09-10 ] --- # Структуры данных в R <img src="img//data_structures.svg" width="100%" /> > __Структура данных__ — это программная единица, позволяющая хранить и обрабатывать множество однотипных и/или логически связанных данных. --- # Векторы Для создания вектора путем __перечисления__ элементов используется функция `c()`: ``` r colors = c("Красная", "Зеленая", "Синяя", "Коричневая", "Оранжевая") colors ## [1] "Красная" "Зеленая" "Синяя" "Коричневая" "Оранжевая" ``` ``` r lengths = c(41, 43, 45, 19, 38) lengths ## [1] 41 43 45 19 38 ``` ``` r opens = c(FALSE, TRUE, TRUE, FALSE, FALSE) opens ## [1] FALSE TRUE TRUE FALSE FALSE ``` --- # Генерация последовательности .pull-left[ Арифметическая с шагом 1: ``` r index = -2:2 # эквивалентно c(1,2,3,4,5) index ## [1] -2 -1 0 1 2 seq_along(index) ## [1] 1 2 3 4 5 ``` ] .pull-right[ Случайная: ``` r runif(5, 0, 100) # равномерное ## [1] 52.87479 92.61149 20.78704 62.30628 92.76375 rnorm(5, 10, 5) # нормальное ## [1] 12.863609 14.258501 8.868637 10.834205 12.536329 ``` ] Арифметическая общего вида: ``` r seq(from = 1, by = 2, length.out = 10) ## [1] 1 3 5 7 9 11 13 15 17 19 seq(from = 2, to = 20, by = 3) ## [1] 2 5 8 11 14 17 20 seq(length.out = 10, to = 2, by = -2) ## [1] 20 18 16 14 12 10 8 6 4 2 ``` --- # Извлечение и условия .pull-left[ Извлечение по индексам: ``` r colors[3] ## [1] "Синяя" lengths[1:4] ## [1] 41 43 45 19 lengths[c(5, 1, 4, 2)] ## [1] 38 41 19 43 ``` ] .pull-right[ Извлечение по условию: ``` r lengths ## [1] 41 43 45 19 38 lengths > 40 ## [1] TRUE TRUE TRUE FALSE FALSE lengths[lengths > 40] ## [1] 41 43 45 ``` ] Формирование по условию: ``` r ifelse(lengths > 40, 'Длинная', 'Короткая') ## [1] "Длинная" "Длинная" "Длинная" "Короткая" "Короткая" ``` --- # Преобразования и статистики .pull-left[ Преобразования: ``` r lengths * 1000 ## [1] 41000 43000 45000 19000 38000 sqrt(lengths) ## [1] 6.403124 6.557439 6.708204 4.358899 6.164414 stations = c(26, 24, 22, 12, 24) stations / lengths ## [1] 0.6341463 0.5581395 0.4888889 0.6315789 0.6315789 ``` ] .pull-right[ Статистики: ``` r min(lengths) ## [1] 19 max(lengths) ## [1] 45 mean(lengths) ## [1] 37.2 ``` ] Описательные статистики: ``` r summary(lengths) ## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 19.0 38.0 41.0 37.2 43.0 45.0 ``` --- # Поиск и сортировка .pull-left[ __Поиск__ ``` r # Исходный вектор lengths ## [1] 41 43 45 19 38 # максимальное значение (l = max(lengths)) ## [1] 45 # индекс максимального элемента (idx = match(l, lengths)) ## [1] 3 # извлечение (color = colors[idx]) ## [1] "Синяя" ``` ] .pull-right[ __Сортировка__ ``` r # по возрастанию значений sort(lengths) ## [1] 19 38 41 43 45 # по убыванию значений sort(lengths, decreasing = TRUE) ## [1] 45 43 41 38 19 # какой порядок значений? order(lengths) ## [1] 4 5 1 2 3 # сортировка по упорядоченным индексам lengths[order(lengths)] ## [1] 19 38 41 43 45 ``` ] --- # Факторы __Фактор__ — категориальный вектор со словарем допустимых значений: ``` r depot = c('Северное', 'Черкизово', 'Сокол', 'Замоскворецкое', 'Братеево', 'Измайлово', 'Фили', 'Митино', 'Красная Пресня', 'Калужское', 'Свиблово') line_number = c(1, 1, 2, 2, 2, 3, 3, 3, 5, 6, 6) summary(line_number) ## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 1.000 2.000 3.000 3.091 4.000 6.000 (line_number = as.factor(line_number)) ## [1] 1 1 2 2 2 3 3 3 5 6 6 ## Levels: 1 2 3 5 6 summary(line_number) ## 1 2 3 5 6 ## 2 3 3 1 2 ``` --- # Матрицы .pull-left[ Создание ``` r v = 1:12 m = matrix(v, nrow = 3, ncol = 4) m ## [,1] [,2] [,3] [,4] ## [1,] 1 4 7 10 ## [2,] 2 5 8 11 ## [3,] 3 6 9 12 matrix(v, nrow = 3, byrow = TRUE) ## [,1] [,2] [,3] [,4] ## [1,] 1 2 3 4 ## [2,] 5 6 7 8 ## [3,] 9 10 11 12 ``` ] .pull-right[ Индексирование: ``` r m[2,4] # 2 строка, 4 толбец ## [1] 11 m[2,] # 2 строка ## [1] 2 5 8 11 m[,3] # 3 cтолбец ## [1] 7 8 9 ``` Преобразование: ``` r log(m) # натуральный логарифм ото всех элементов ## [,1] [,2] [,3] [,4] ## [1,] 0.0000000 1.386294 1.945910 2.302585 ## [2,] 0.6931472 1.609438 2.079442 2.397895 ## [3,] 1.0986123 1.791759 2.197225 2.484907 ``` ] --- # Матрицы .pull-left[ Транспонирование: ``` r t(m) # транспонированная матрица ## [,1] [,2] [,3] ## [1,] 1 2 3 ## [2,] 4 5 6 ## [3,] 7 8 9 ## [4,] 10 11 12 m2 = matrix(-3:3,nrow = 3, ncol = 3) det(m2) # определитель матрицы ## [1] -21 ``` ] .pull-right[ Умножение с помощью `%*%`: ``` r m2 %*% m ## [,1] [,2] [,3] [,4] ## [1,] 6 6 6 6 ## [2,] -9 -21 -33 -45 ## [3,] -3 -6 -9 -12 ``` Сортировка создает вектор: ``` r sort(m) ## [1] 1 2 3 4 5 6 7 8 9 10 11 12 ``` ] --- # Матрицы .pull-left[ Поиск элементов: ``` r m ## [,1] [,2] [,3] [,4] ## [1,] 1 4 7 10 ## [2,] 2 5 8 11 ## [3,] 3 6 9 12 indexes = which(m == 8, arr.ind = TRUE) row = indexes[1,1] col = indexes[1,2] m[row,col] ## [1] 8 ``` ] .pull-right[ Сборка из векторов: ``` r lengths = c(28, 40, 45, 19, 38) stations = c(20, 21, 22, 12, 24) cbind(lengths, stations) # соединим вектора в качестве столбцов ## lengths stations ## [1,] 28 20 ## [2,] 40 21 ## [3,] 45 22 ## [4,] 19 12 ## [5,] 38 24 rbind(lengths, stations) # соединим вектора в качестве строк ## [,1] [,2] [,3] [,4] [,5] ## lengths 28 40 45 19 38 ## stations 20 21 22 12 24 ``` ] --- # Списки .pull-left[ Создание: ``` r list(lengths, summary(lengths)) ## [[1]] ## [1] 28 40 45 19 38 ## ## [[2]] ## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 19 28 38 34 40 45 (res = list(data = lengths, sum = summary(lengths))) ## $data ## [1] 28 40 45 19 38 ## ## $sum ## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 19 28 38 34 40 45 ``` ] .pull-right[ Извлечение: ``` r res[1] # список! ## $data ## [1] 28 40 45 19 38 res["sum"] # список! ## $sum ## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 19 28 38 34 40 45 res[[1]] # элемент! ## [1] 28 40 45 19 38 res[["sum"]] # элемент! ## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 19 28 38 34 40 45 res$sum ## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 19 28 38 34 40 45 ``` ] --- # Фреймы данных __Фрейм данных__ — это список, в котором все элементы строго одинаковой длины ``` r (df = data.frame(colors,lengths,stations)) ## colors lengths stations ## 1 Красная 28 20 ## 2 Зеленая 40 21 ## 3 Синяя 45 22 ## 4 Коричневая 19 12 ## 5 Оранжевая 38 24 ``` К фреймам также можно пристыковывать новые столбцы: ``` r (df = cbind(df, dens = stations / lengths)) ## colors lengths stations dens ## 1 Красная 28 20 0.7142857 ## 2 Зеленая 40 21 0.5250000 ## 3 Синяя 45 22 0.4888889 ## 4 Коричневая 19 12 0.6315789 ## 5 Оранжевая 38 24 0.6315789 ``` --- # Фреймы данных Извлечение элементов фрейма данных — гибрид возможностей матрицы и списка .pull-left[ __Как матрица__: ``` r df ## colors lengths stations dens ## 1 Красная 28 20 0.7142857 ## 2 Зеленая 40 21 0.5250000 ## 3 Синяя 45 22 0.4888889 ## 4 Коричневая 19 12 0.6315789 ## 5 Оранжевая 38 24 0.6315789 df[2,2] ## [1] 40 df[,3] ## [1] 20 21 22 12 24 df[4,] # ДОРОГО! ## colors lengths stations dens ## 4 Коричневая 19 12 0.6315789 ``` ] .pull-right[ __Как список__: ``` r df[3] ## stations ## 1 20 ## 2 21 ## 3 22 ## 4 12 ## 5 24 df[[3]] ## [1] 20 21 22 12 24 df$stations ## [1] 20 21 22 12 24 df[['stations']] ## [1] 20 21 22 12 24 ``` ] --- # Фреймы данных Вычисления: ``` r max(df$stations) ## [1] 24 df$ratio = df$lengths / df$stations df ## colors lengths stations dens ratio ## 1 Красная 28 20 0.7142857 1.400000 ## 2 Зеленая 40 21 0.5250000 1.904762 ## 3 Синяя 45 22 0.4888889 2.045455 ## 4 Коричневая 19 12 0.6315789 1.583333 ## 5 Оранжевая 38 24 0.6315789 1.583333 ``` Названия столбцов: ``` r colnames(df) ## [1] "colors" "lengths" "stations" "dens" "ratio" ``` --- # Фреймы данных Чтобы присоединить строку, сначала можно создать фрейм данных из одной строки и перенести в него названия столбцов: ``` r row = data.frame("Фиолетовая", 40.5, 22, 22/45, 45/22) colnames(row) = colnames(df) ``` После того как столбцы приведены в соответствие, можно присоединить новую строку: ``` r (df = rbind(df,row)) ## colors lengths stations dens ratio ## 1 Красная 28.0 20 0.7142857 1.400000 ## 2 Зеленая 40.0 21 0.5250000 1.904762 ## 3 Синяя 45.0 22 0.4888889 2.045455 ## 4 Коричневая 19.0 12 0.6315789 1.583333 ## 5 Оранжевая 38.0 24 0.6315789 1.583333 ## 6 Фиолетовая 40.5 22 0.4888889 2.045455 ``` --- # Фреймы данных .pull-left[ Сортировка: ``` r df[order(df$lengths), ] ## colors lengths stations dens ratio ## 4 Коричневая 19.0 12 0.6315789 1.583333 ## 1 Красная 28.0 20 0.7142857 1.400000 ## 5 Оранжевая 38.0 24 0.6315789 1.583333 ## 2 Зеленая 40.0 21 0.5250000 1.904762 ## 6 Фиолетовая 40.5 22 0.4888889 2.045455 ## 3 Синяя 45.0 22 0.4888889 2.045455 ``` ] .pull-right[ Фильтрация: ``` r df[df$lengths > 25, ] ## colors lengths stations dens ratio ## 1 Красная 28.0 20 0.7142857 1.400000 ## 2 Зеленая 40.0 21 0.5250000 1.904762 ## 3 Синяя 45.0 22 0.4888889 2.045455 ## 5 Оранжевая 38.0 24 0.6315789 1.583333 ## 6 Фиолетовая 40.5 22 0.4888889 2.045455 ``` ] --- # Фреймы данных Описательные статистики: ``` r summary(df) ## colors lengths stations dens ## Length:6 Min. :19.00 Min. :12.00 Min. :0.4889 ## Class :character 1st Qu.:30.50 1st Qu.:20.25 1st Qu.:0.4979 ## Mode :character Median :39.00 Median :21.50 Median :0.5783 ## Mean :35.08 Mean :20.17 Mean :0.5800 ## 3rd Qu.:40.38 3rd Qu.:22.00 3rd Qu.:0.6316 ## Max. :45.00 Max. :24.00 Max. :0.7143 ## ratio ## Min. :1.400 ## 1st Qu.:1.583 ## Median :1.744 ## Mean :1.760 ## 3rd Qu.:2.010 ## Max. :2.045 ``` --- # Описание структуры данных ``` r typeof(df) # тип структуры данных ## [1] "list" class(df) # класс объекта ## [1] "data.frame" str(df) # структура объекта ## 'data.frame': 6 obs. of 5 variables: ## $ colors : chr "Красная" "Зеленая" "Синяя" "Коричневая" ... ## $ lengths : num 28 40 45 19 38 40.5 ## $ stations: num 20 21 22 12 24 22 ## $ dens : num 0.714 0.525 0.489 0.632 0.632 ... ## $ ratio : num 1.4 1.9 2.05 1.58 1.58 ... ``` --- # Циклы .left-40[ ``` r for (i in 1:5) print(i) ## [1] 1 ## [1] 2 ## [1] 3 ## [1] 4 ## [1] 5 i = 1 while(i < 5) { i = 2 * i print(i) } ## [1] 2 ## [1] 4 ## [1] 8 ``` ] .right-60[ ``` r for (i in 1:10) { a = factorial(i) # факториал i b = exp(i) # e в степени i print(a/b) # факториал растет быстрее экспоненты } ## [1] 0.3678794 ## [1] 0.2706706 ## [1] 0.2987224 ## [1] 0.4395753 ## [1] 0.8085536 ## [1] 1.784702 ## [1] 4.595885 ## [1] 13.52585 ## [1] 44.78295 ## [1] 164.7473 ``` ] --- # Циклы Пример по столбцам — вычисление медианы каждой переменной: ``` r n = ncol(df) medians = vector('numeric', n) for (i in 1:n) { if(is.numeric(df[, i])){ medians[i] = median(df[, i]) } else { medians[i] = NA } } colnames(df) # Переменные ## [1] "colors" "lengths" "stations" "dens" "ratio" medians # Медианные значения ## [1] NA 39.0000000 21.5000000 0.5782895 1.7440476 ``` --- # Циклы Пример по строкам — вывод информации о каждой станции: ``` r k = nrow(df) for (i in 1:k) { cat(df[i, 'colors'], 'ветка метро имеет длину', df[i, 'lengths'], 'км', fill = TRUE) } ## Красная ветка метро имеет длину 28 км ## Зеленая ветка метро имеет длину 40 км ## Синяя ветка метро имеет длину 45 км ## Коричневая ветка метро имеет длину 19 км ## Оранжевая ветка метро имеет длину 38 км ## Фиолетовая ветка метро имеет длину 40.5 км ``` --- # Циклы - `break` прерывает цикл - `next` прерывает текущую итерацию цикла ``` r while (TRUE) { cat('Введите номер ветки метро:') input = readline() if (input == 'q') break else { n = as.numeric(input) if (!is.na(n)) depots[depots$line_number == n, ] } } ```