Решения по четвертой лекции

task
Author

Elena U

Published

March 24, 2023

Составлены в формате задание - ответ к нему.

Рассчитано на самопроверку: ваша задача написать такой код, чтобы совпал с моим правильным ответом. Плюс есть еще несколько заданий на подумать и вспомнить материал лекции.

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

Если вдруг найдутся ошибки/опечатки, пишите на почту e.ubogoeva@alumni.nsu.ru или в телеграм. Вопросы по заданиям также можно писать на почту или в телеграм, телеграм чуть предпочтительнее.

Установка tidyverse

Сначала необходимо установить и загрузить tidyverse:

install.packages('tidyverse')
library(tidyverse)

Работа с пайпами

Перепишите следующие выражения с помощью пайпа %>%:

sin(log(sqrt(1:10), 10))
 [1] 0.0000000 0.1499473 0.2363043 0.2965040 0.3424140 0.3793333 0.4100866
 [8] 0.4363562 0.4592238 0.4794255
c("Корень из", 2, "равен", sqrt(2))
[1] "Корень из"       "2"               "равен"           "1.4142135623731"
2 %>% 
  c("Корень из", ., "равен", sqrt(.))
[1] "Корень из"       "2"               "равен"           "1.4142135623731"

Работа со столбцами dplyr::select()

Загрузка данных:

wc3_units <- read_tsv('https://raw.githubusercontent.com/ubogoeva/tidyverse_tutorial/master/data/wc3_heroes.txt',
                      col_names = TRUE, 
                      na = '-', 
                      name_repair = 'minimal') %>% 
  janitor::clean_names()
  • Выберите столбец hp

    wc3_units %>% 
      select(hp)
    # A tibble: 71 × 1
          hp
       <dbl>
     1   220
     2   220
     3   420
     4   535
     5   835
     6   290
     7   325
     8   600
     9   200
    10   360
    # … with 61 more rows
  • Выберите столбцы unit, race, gold, armor

    wc3_units %>% 
      select(unit, race, gold, armor)
    # A tibble: 71 × 4
       unit           race   gold armor
       <chr>          <chr> <dbl> <dbl>
     1 Peasant        Human    75     0
     2 Militia        Human    NA     4
     3 Footman        Human   135     2
     4 Rifleman       Human   205     0
     5 Knight         Human   245     5
     6 Priest         Human   135     0
     7 Sorceress      Human   155     0
     8 Spell Breaker  Human   215     3
     9 Flying Machine Human    90     2
    10 Mortar Team    Human   180     0
    # … with 61 more rows
  • Выберите столбцы с hp по sight, и с cooldown по range

    wc3_units %>% 
      select(hp:sight, cooldown:range)
    # A tibble: 71 × 7
          hp armor_type armor sight cooldown   dps range
       <dbl> <chr>      <dbl> <dbl>    <dbl> <dbl> <dbl>
     1   220 Medium         0    80     2     2.75     0
     2   220 Heavy          4   140     1.2  10.4      0
     3   420 Heavy          2   140     1.35  9.26     0
     4   535 Medium         0   140     1.5  14       40
     5   835 Heavy          5   140     1.4  24.3      0
     6   290 Unarmored      0   140     2     4.25    60
     7   325 Unarmored      0   140     1.75  6.29    60
     8   600 Medium         3   140     1.9   7.37    25
     9   200 Heavy          2   180     2.5   3        0
    10   360 Heavy          0   140     3.5  16.6    115
    # … with 61 more rows
  • Выведите столбец gold в качестве вектора

    wc3_units %>% 
      pull(gold)
     [1]  75  NA 135 205 245 135 155 215  90 180 195 280 200  NA  NA  NA  NA  75 200
    [20] 135 135 220 180 280 130 145 195 255 265 160  NA  NA  NA  NA  60 130 195 210
    [39] 145 255  NA 425 425 160 135  NA 155  NA 330 330  NA  NA  NA  75 120 215 185
    [58] 240 230 145 155 385  NA  NA  NA  NA  NA  NA  NA 200  NA
  • Выведите все столбцы кроме первого unit (отрицательная индексация с помощью !)

    wc3_units %>% 
      select(!unit)
    # A tibble: 71 × 20
       race   gold  wood   pop    hp armor_…¹ armor sight speed  time groun…² damage
       <chr> <dbl> <dbl> <dbl> <dbl> <chr>    <dbl> <dbl> <dbl> <dbl> <chr>    <dbl>
     1 Human    75     0     1   220 Medium       0    80   190    15 Normal     5.5
     2 Human    NA    NA     1   220 Heavy        4   140   270    NA Normal    12.5
     3 Human   135     0     2   420 Heavy        2   140   270    20 Normal    12.5
     4 Human   205    30     3   535 Medium       0   140   270    26 Pierce    21  
     5 Human   245    60     4   835 Heavy        5   140   350    45 Normal    34  
     6 Human   135    10     2   290 Unarmor…     0   140   270    28 Magic      8.5
     7 Human   155    20     2   325 Unarmor…     0   140   270    30 Magic     11  
     8 Human   215    30     3   600 Medium       3   140   300    28 Normal    14  
     9 Human    90    30     1   200 Heavy        2   180   400    13 Siege      7.5
    10 Human   180    70     3   360 Heavy        0   140   270    40 Siege     58  
    # … with 61 more rows, 8 more variables: cooldown <dbl>, dps <dbl>,
    #   range <dbl>, air_attack <chr>, damage_2 <dbl>, cooldown_2 <dbl>,
    #   dps_2 <dbl>, range_2 <dbl>, and abbreviated variable names ¹​armor_type,
    #   ²​ground_attack

Работа со строками dplyr::filter(), dplyr::slice()

  • Выберите юнитов, показатель здоровья hp которых больше 950
wc3_units %>% 
  filter(hp > 950)
# A tibble: 12 × 21
   unit    race   gold  wood   pop    hp armor…¹ armor sight speed  time groun…²
   <chr>   <chr> <dbl> <dbl> <dbl> <dbl> <chr>   <dbl> <dbl> <dbl> <dbl> <chr>  
 1 Phoenix Human    NA    NA    NA  1250 Light       1   160   320    NA Magic  
 2 Tauren  Orc     280    80     5  1300 Heavy       3   140   270    44 Normal 
 3 Kodo B… Orc     255    60     4  1000 Unarmo…     1   140   220    30 Pierce 
 4 DoC Be… N.Elf    NA    NA     4   960 Heavy       3   140   270    NA Normal 
 5 Mounta… N.Elf   425   100     7  1600 Medium      4   120   270    45 Normal 
 6 Mounta… N.Elf   425   100     7  1600 Medium     10   120   270    45 Siege  
 7 Chimae… N.Elf   330    70     5  1000 Light       2   160   250    65 Magic  
 8 Chimae… N.Elf   330    70     5  1000 Light       2   160   250    65 Siege  
 9 Avatar… N.Elf    NA    NA    NA  1200 Heavy       2   120   320    NA Normal 
10 Abomin… Unde…   240    70     4  1175 Heavy       2   140   270    40 Normal 
11 Frost … Unde…   385   120     7  1350 Light       1   160   270    65 Magic  
12 Infern… Unde…    NA    NA    NA  1500 Heavy       6   140   320    NA Chaos  
# … with 9 more variables: damage <dbl>, cooldown <dbl>, dps <dbl>,
#   range <dbl>, air_attack <chr>, damage_2 <dbl>, cooldown_2 <dbl>,
#   dps_2 <dbl>, range_2 <dbl>, and abbreviated variable names ¹​armor_type,
#   ²​ground_attack
  • Выберите юнитов орков (Orc) с легким (Light) типом брони (armor_type)

    wc3_units %>% 
      filter(race == 'Orc' & armor_type == 'Light')
    # A tibble: 2 × 21
      unit     race   gold  wood   pop    hp armor…¹ armor sight speed  time groun…²
      <chr>    <chr> <dbl> <dbl> <dbl> <dbl> <chr>   <dbl> <dbl> <dbl> <dbl> <chr>  
    1 Wind Ri… Orc     265    40     4   570 Light       0   160   320    35 Pierce 
    2 Troll B… Orc     160    40     2   325 Light       0   140   320    28 Siege  
    # … with 9 more variables: damage <dbl>, cooldown <dbl>, dps <dbl>,
    #   range <dbl>, air_attack <chr>, damage_2 <dbl>, cooldown_2 <dbl>,
    #   dps_2 <dbl>, range_2 <dbl>, and abbreviated variable names ¹​armor_type,
    #   ²​ground_attack
  • Выведите первые 6 юнитов Undead с максимальным показателем затраченного дерева (wood).

    wc3_units %>% 
      filter(race == 'Undead') %>% 
      slice_max(wood, n = 6)
    # A tibble: 7 × 21
      unit     race   gold  wood   pop    hp armor…¹ armor sight speed  time groun…²
      <chr>    <chr> <dbl> <dbl> <dbl> <dbl> <chr>   <dbl> <dbl> <dbl> <dbl> <chr>  
    1 Frost W… Unde…   385   120     7  1350 Light       1   160   270    65 Magic  
    2 Abomina… Unde…   240    70     4  1175 Heavy       2   140   270    40 Normal 
    3 Meat Wa… Unde…   230    50     4   380 Heavy       2   140   220    45 Siege  
    4 Crypt F… Unde…   215    40     3   550 Medium      0   140   270    30 Pierce 
    5 Obsidia… Unde…   200    35     3   550 Heavy       4   120   270    45 Magic  
    6 Gargoyle Unde…   185    30     2   410 Unarmo…     3   160   350    35 Pierce 
    7 Banshee  Unde…   155    30     2   285 Unarmo…     0   140   270    28 Magic  
    # … with 9 more variables: damage <dbl>, cooldown <dbl>, dps <dbl>,
    #   range <dbl>, air_attack <chr>, damage_2 <dbl>, cooldown_2 <dbl>,
    #   dps_2 <dbl>, range_2 <dbl>, and abbreviated variable names ¹​armor_type,
    #   ²​ground_attack

    Хм, почему-то вывелось 7 строчек. Почему это произошло, можно узнать, прочитав справку функции slice_max() (аргумент with_ties).

  • Попробуем вывести только 6 строчек в предыдущем задании.

    wc3_units %>% 
      filter(race == 'Undead') %>% 
      slice_max(wood, n = 6, with_ties = FALSE)
    # A tibble: 6 × 21
      unit     race   gold  wood   pop    hp armor…¹ armor sight speed  time groun…²
      <chr>    <chr> <dbl> <dbl> <dbl> <dbl> <chr>   <dbl> <dbl> <dbl> <dbl> <chr>  
    1 Frost W… Unde…   385   120     7  1350 Light       1   160   270    65 Magic  
    2 Abomina… Unde…   240    70     4  1175 Heavy       2   140   270    40 Normal 
    3 Meat Wa… Unde…   230    50     4   380 Heavy       2   140   220    45 Siege  
    4 Crypt F… Unde…   215    40     3   550 Medium      0   140   270    30 Pierce 
    5 Obsidia… Unde…   200    35     3   550 Heavy       4   120   270    45 Magic  
    6 Gargoyle Unde…   185    30     2   410 Unarmo…     3   160   350    35 Pierce 
    # … with 9 more variables: damage <dbl>, cooldown <dbl>, dps <dbl>,
    #   range <dbl>, air_attack <chr>, damage_2 <dbl>, cooldown_2 <dbl>,
    #   dps_2 <dbl>, range_2 <dbl>, and abbreviated variable names ¹​armor_type,
    #   ²​ground_attack

Но вообще лучше сохранять дефолтное значение параметра with_ties

Создание колонок dplyr::mutate()

  • Создайте новую колонку is_air_attack, которая будет заполнена TRUE, если у юнита есть воздушная атака (air_attack), и FALSE, если нет. Выведите на печать колонки unit, race, air_attack и is_air_attack

    wc3_units %>% 
      mutate(is_air_attack = !is.na(air_attack)) %>% 
      select(unit, race, air_attack, is_air_attack)
    # A tibble: 71 × 4
       unit           race  air_attack is_air_attack
       <chr>          <chr> <chr>      <lgl>        
     1 Peasant        Human <NA>       FALSE        
     2 Militia        Human <NA>       FALSE        
     3 Footman        Human <NA>       FALSE        
     4 Rifleman       Human Pierce     TRUE         
     5 Knight         Human <NA>       FALSE        
     6 Priest         Human Magic      TRUE         
     7 Sorceress      Human Magic      TRUE         
     8 Spell Breaker  Human <NA>       FALSE        
     9 Flying Machine Human Pierce     TRUE         
    10 Mortar Team    Human <NA>       FALSE        
    # … with 61 more rows
  • Создайте колонку how_fast, заполненную значениями: если скорость speed больше 270 - fast, равно 270 - middle, меньше 270 - slow. Выведите на печать колонки unit, race, speed, how_fast.

    wc3_units %>% 
      mutate(how_fast = case_when(speed > 270 ~ 'fast',
                                  speed == 270 ~ 'middle',
                                  TRUE ~ 'slow')) %>% 
      select(unit, race, speed, how_fast)
    # A tibble: 71 × 4
       unit           race  speed how_fast
       <chr>          <chr> <dbl> <chr>   
     1 Peasant        Human   190 slow    
     2 Militia        Human   270 middle  
     3 Footman        Human   270 middle  
     4 Rifleman       Human   270 middle  
     5 Knight         Human   350 fast    
     6 Priest         Human   270 middle  
     7 Sorceress      Human   270 middle  
     8 Spell Breaker  Human   300 fast    
     9 Flying Machine Human   400 fast    
    10 Mortar Team    Human   270 middle  
    # … with 61 more rows

Сортировка dplyr::arrange()

  • Отсортируйте колонку dps по убыванию, выберите колонки unit, race, damage, cooldown, dps.
wc3_units %>% 
  arrange(desc(dps)) %>% 
  select(unit, race, damage, cooldown, dps)
# A tibble: 71 × 5
   unit              race   damage cooldown   dps
   <chr>             <chr>   <dbl>    <dbl> <dbl>
 1 Phoenix           Human    68       1.4   48.6
 2 Infernal          Undead   54.5     1.35  40.4
 3 Frost Wyrm        Undead  104       3     34.7
 4 Water Elemental 3 Human    45       1.5   30  
 5 Chimaera          N.Elf    75       2.5   30  
 6 DoC Bear Form     N.Elf    36.5     1.5   24.3
 7 Knight            Human    34       1.4   24.3
 8 Siege Engine      Human    50       2.1   23.8
 9 Water Elemental 2 Human    35       1.5   23.3
10 Gryphon Rider     Human    50       2.2   22.7
# … with 61 more rows
  • Отсортируйте колонку hp по возрастанию, armor по убыванию, выберите unit, race, hp, armor.

    wc3_units %>% 
      arrange(hp, desc(armor)) %>% 
      select(unit, race, hp, armor)
    # A tibble: 71 × 4
       unit             race      hp armor
       <chr>            <chr>  <dbl> <dbl>
     1 Serpent Ward     Orc       75     0
     2 Wisp             N.Elf    120     0
     3 Shade            Undead   125     0
     4 DoC Druid Form   N.Elf    130     1
     5 Carrion Beetle 1 Undead   140     2
     6 Skeleton Warrior Undead   180     1
     7 Flying Machine   Human    200     2
     8 Spirit Wolf      Orc      200     0
     9 Militia          Human    220     4
    10 Peasant          Human    220     0
    # … with 61 more rows

Аггрегация group_by() + summarise()

  • Посчитайте средний урон и здоровье для юнитов, сгруппированных по типам брони (armor_type). Можно сделать это несколькими способами.
wc3_units %>% 
  group_by(armor_type) %>% 
  summarise(mean_damage = mean(damage, na.rm = TRUE),
            mean_hp = mean(hp, na.rm = TRUE))
# A tibble: 6 × 3
  armor_type   mean_damage mean_hp
  <chr>              <dbl>   <dbl>
1 Fort                50      700 
2 Heavy               28.3    534.
3 Invulnerable        16      500 
4 Light               42.9    819.
5 Medium              20.3    514.
6 Unarmored           13.6    423.
wc3_units %>% 
  group_by(armor_type) %>% 
  summarise(across(c(damage, hp), function(x) mean(x, na.rm = TRUE)))
# A tibble: 6 × 3
  armor_type   damage    hp
  <chr>         <dbl> <dbl>
1 Fort           50    700 
2 Heavy          28.3  534.
3 Invulnerable   16    500 
4 Light          42.9  819.
5 Medium         20.3  514.
6 Unarmored      13.6  423.
  • Подсчитайте средние по всем числовым переменным, группируя по типу брони. Подсказка: здесь пригодится функция across().

    wc3_units %>% 
      group_by(armor_type) %>% 
      summarise(across(where(is.numeric), function(x) mean(x, na.rm = TRUE)))
    # A tibble: 6 × 17
      armor_type    gold  wood    pop    hp   armor sight speed  time damage coold…¹
      <chr>        <dbl> <dbl>  <dbl> <dbl>   <dbl> <dbl> <dbl> <dbl>  <dbl>   <dbl>
    1 Fort          195   60     3     700    2      140   220   55     50      2.1 
    2 Heavy         200.  45.4   2.47  534.   1.76   130.  276.  35.6   28.3    1.85
    3 Invulnerable  NaN  NaN   NaN     500  NaN      120   270  NaN     16      1.35
    4 Light         263.  58.1   4.1   819.   1      155.  311.  44.5   42.9    1.94
    5 Medium        181.  30     2.47  514.   1.2    126   269.  24.1   20.3    2.11
    6 Unarmored     164.  28.5   2.36  423.   0.429  144.  296.  30.4   13.6    1.80
    # … with 6 more variables: dps <dbl>, range <dbl>, damage_2 <dbl>,
    #   cooldown_2 <dbl>, dps_2 <dbl>, range_2 <dbl>, and abbreviated variable name
    #   ¹​cooldown

Преобразование таблиц pivot_longer(), pivot_wider()

Сначала создадим таблицу

wc3_dps <- wc3_units %>% 
  mutate(if_summon = if_else((pop == 0) | is.na(pop), 
                            'summoned', 'not_summoned')) %>% 
  group_by(race, if_summon) %>% 
  summarise(mean_dps = mean(dps, na.rm = TRUE)) 
`summarise()` has grouped output by 'race'. You can override using the
`.groups` argument.
wc3_dps
# A tibble: 8 × 3
# Groups:   race [4]
  race   if_summon    mean_dps
  <chr>  <chr>           <dbl>
1 Human  not_summoned     12.0
2 Human  summoned         28.8
3 N.Elf  not_summoned     14.8
4 N.Elf  summoned         14.5
5 Orc    not_summoned     11.3
6 Orc    summoned         14.4
7 Undead not_summoned     12.8
8 Undead summoned         14.7

Теперь попробуем превратить таблицу в широкую

wc3_dps_wide <- wc3_dps %>% 
  pivot_wider(id_cols = race, names_from = if_summon, 
              values_from = mean_dps)
wc3_dps_wide
# A tibble: 4 × 3
# Groups:   race [4]
  race   not_summoned summoned
  <chr>         <dbl>    <dbl>
1 Human          12.0     28.8
2 N.Elf          14.8     14.5
3 Orc            11.3     14.4
4 Undead         12.8     14.7

Полученную таблицу превратить обратно в длинную

wc3_dps_wide %>% 
  pivot_longer(cols = c(not_summoned, summoned), 
               names_to = 'if_summon', 
               values_to = 'mean_dps')
# A tibble: 8 × 3
# Groups:   race [4]
  race   if_summon    mean_dps
  <chr>  <chr>           <dbl>
1 Human  not_summoned     12.0
2 Human  summoned         28.8
3 N.Elf  not_summoned     14.8
4 N.Elf  summoned         14.5
5 Orc    not_summoned     11.3
6 Orc    summoned         14.4
7 Undead not_summoned     12.8
8 Undead summoned         14.7