P2 // Матрицы и списки. Функции

Основные задания

#1

Создайте матрицу, размером 5×5, из единиц. Сохраните её в переменную m.

     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    1    1    1
[2,]    1    1    1    1    1
[3,]    1    1    1    1    1
[4,]    1    1    1    1    1
[5,]    1    1    1    1    1

#2

Замените все некрайние значения на нули. Перезапишите переменную m.

     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    1    1    1
[2,]    1    0    0    0    1
[3,]    1    0    0    0    1
[4,]    1    0    0    0    1
[5,]    1    1    1    1    1
Подсказки
Как делать задание?
Что надо сделать?
Ответ неверный

#3

Выделите из матрицы m:

  1. вторую строку
[1] 1 0 0 0 1
  1. первый столбец
[1] 1 1 1 1 1
  1. строки с третьей по пятую
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    0    0    0    1
[2,]    1    0    0    0    1
[3,]    1    1    1    1    1
  1. второй и третий столбы
     [,1] [,2]
[1,]    1    1
[2,]    0    0
[3,]    0    0
[4,]    0    0
[5,]    1    1

#4

Сравните вторую строку и третий столбец матрицы m.

[1] TRUE TRUE TRUE TRUE TRUE

#5

Создайте таблицу умножения. Это должна быть матрица, размером 9×9, в которой на пересечении \(i\)-ой строки и \(j\)-го столбца находится произведение \(i \times j\). Сохраните результат в переменную multab.

      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
 [1,]    1    2    3    4    5    6    7    8    9
 [2,]    2    4    6    8   10   12   14   16   18
 [3,]    3    6    9   12   15   18   21   24   27
 [4,]    4    8   12   16   20   24   28   32   36
 [5,]    5   10   15   20   25   30   35   40   45
 [6,]    6   12   18   24   30   36   42   48   54
 [7,]    7   14   21   28   35   42   49   56   63
 [8,]    8   16   24   32   40   48   56   64   72
 [9,]    9   18   27   36   45   54   63   72   81

#6

Поработайте с переменной multab.

  1. выделите 71-ый элемент матрицы
[1] 64
  1. замените все значения, меньшие 10, на пропуски (NA)
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
 [1,]   NA   NA   NA   NA   NA   NA   NA   NA   NA
 [2,]   NA   NA   NA   NA   10   12   14   16   18
 [3,]   NA   NA   NA   12   15   18   21   24   27
 [4,]   NA   NA   12   16   20   24   28   32   36
 [5,]   NA   10   15   20   25   30   35   40   45
 [6,]   NA   12   18   24   30   36   42   48   54
 [7,]   NA   14   21   28   35   42   49   56   63
 [8,]   NA   16   24   32   40   48   56   64   72
 [9,]   NA   18   27   36   45   54   63   72   81

#7

Примените к матрице multab функции sum(), mean(), median(), которые мы применяли к векторам. Учтите, что в данных есть пропуски — ведь мы их туда своими руками добавили.

Что получилось? Почему так?

[1] 1895
[1] 32.67241
[1] 28

#8

8.1 Для матрицы m посчитайте сумму:

  1. по каждой строке
[1] 5 2 2 2 5
  1. по каждому столбцу
[1] 5 2 2 2 5

8.2 Для матрицы multab посчитайте сумму по каждому столбцу.

[1]   0  70 117 168 220 264 308 352 396
Подсказка

apply()

#9

Создайте список, который будет содержать следующие элементы:

  • вектор letters под названием alphabet
  • значение TRUE под названием logic
  • матрицу multab под названием multab

Сохраните список в переменную first_list.

$alphabet
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
[20] "t" "u" "v" "w" "x" "y" "z"

$logic
[1] TRUE

$multab
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
 [1,]   NA   NA   NA   NA   NA   NA   NA   NA   NA
 [2,]   NA   NA   NA   NA   10   12   14   16   18
 [3,]   NA   NA   NA   12   15   18   21   24   27
 [4,]   NA   NA   12   16   20   24   28   32   36
 [5,]   NA   10   15   20   25   30   35   40   45
 [6,]   NA   12   18   24   30   36   42   48   54
 [7,]   NA   14   21   28   35   42   49   56   63
 [8,]   NA   16   24   32   40   48   56   64   72
 [9,]   NA   18   27   36   45   54   63   72   81

#10

Выделите из списка first_list:

  1. первый элемент (по номеру) — должен вернуться список
$alphabet
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
[20] "t" "u" "v" "w" "x" "y" "z"
  1. матрицу multab (по названию) — должен вернуться список
$multab
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
 [1,]   NA   NA   NA   NA   NA   NA   NA   NA   NA
 [2,]   NA   NA   NA   NA   10   12   14   16   18
 [3,]   NA   NA   NA   12   15   18   21   24   27
 [4,]   NA   NA   12   16   20   24   28   32   36
 [5,]   NA   10   15   20   25   30   35   40   45
 [6,]   NA   12   18   24   30   36   42   48   54
 [7,]   NA   14   21   28   35   42   49   56   63
 [8,]   NA   16   24   32   40   48   56   64   72
 [9,]   NA   18   27   36   45   54   63   72   81
  1. матрицу multab — должна вернуться матрица
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
 [1,]   NA   NA   NA   NA   NA   NA   NA   NA   NA
 [2,]   NA   NA   NA   NA   10   12   14   16   18
 [3,]   NA   NA   NA   12   15   18   21   24   27
 [4,]   NA   NA   12   16   20   24   28   32   36
 [5,]   NA   10   15   20   25   30   35   40   45
 [6,]   NA   12   18   24   30   36   42   48   54
 [7,]   NA   14   21   28   35   42   49   56   63
 [8,]   NA   16   24   32   40   48   56   64   72
 [9,]   NA   18   27   36   45   54   63   72   81
  1. логический элемент logic — должен вернуться вектор
[1] TRUE

#11

Выделите из списка first_list:

  1. первые 5 элементов вектора alphabet
[1] "a" "b" "c" "d" "e"
  1. два последних столбца матрицы multab
      [,1] [,2]
 [1,]   NA   NA
 [2,]   16   18
 [3,]   24   27
 [4,]   32   36
 [5,]   40   45
 [6,]   48   54
 [7,]   56   63
 [8,]   64   72
 [9,]   72   81

с. третий элемент логического вектора logic

[1] NA

#12

  1. Напишите функцию mul(x, y), которая будет перемножать два своих аргумента.
mul(2,3)
[1] 6
mul(-4, -8)
[1] 32
mul(0.5, 6)
[1] 3
  1. Напишите функцию sqrtn(x, n), которая будет извлекать корень любой степени из любого числа.
sqrtn(4, 2)
[1] 2
sqrtn(27, 3)
[1] 3
sqrtn(30, -5)
[1] 0.5064957
sqrtn(-2, 2)
[1] NaN
Подсказка

\[ \sqrt[n]{x} = x^{\frac{1}{n}} \]

#13

Модифицируйте функцию из предыдущего задания, чтобы она могла обрабатывать отрицательный x при любом n — то есть функция не должна возвращать NaN.

[1] 2
[1] 3
[1] 0.5064957
[1] 0+1.414214i
[1] 1.5+2.598076i
Подсказка

Чтобы извлечь корень из отрицательного числа, необходимо привести его типу complex.

#14

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

Модифицируйте функцию из предыдущего задания так, чтобы по умолчанию она возвращала NaN, если x отрицательный, но могла вычислить значение при необходимости.

sqrtn(4, 2)
[1] 2
sqrtn(27, 3)
[1] 3
sqrtn(30, -5)
[1] 0.5064957
sqrtn(-2, 2)
[1] NaN
sqrtn(-2, 2, complex = TRUE)
[1] 0+1.414214i
Подсказка

Нужен дополнительный аргумент (в примерах он назван complex), который по умолчанию будет равен FALSE.

#15

Напишите функцию, которая реализует следующую математическую функцию:

\[ f(x) = \cases{ 0, \quad x < 0 \\ x^2, \quad 0 \leq x \leq 1 \\ x^3, \quad x > 1} \]

Сохраните её в переменную quad_cube и выполните на векторе \(\pmatrix{-5.0 & -4.9 & -4.8 & \dots -0.9 & 0.0 & 0.1 & \dots & 4.8 & 4.9 & 5.0}\).

Сохраните результат в переменную qcres.

qcres
  [1]   0.000   0.000   0.000   0.000   0.000   0.000   0.000   0.000   0.000
 [10]   0.000   0.000   0.000   0.000   0.000   0.000   0.000   0.000   0.000
 [19]   0.000   0.000   0.000   0.000   0.000   0.000   0.000   0.000   0.000
 [28]   0.000   0.000   0.000   0.000   0.000   0.000   0.000   0.000   0.000
 [37]   0.000   0.000   0.000   0.000   0.000   0.000   0.000   0.000   0.000
 [46]   0.000   0.000   0.000   0.000   0.000   0.000   0.010   0.040   0.090
 [55]   0.160   0.250   0.360   0.490   0.640   0.810   1.000   1.331   1.728
 [64]   2.197   2.744   3.375   4.096   4.913   5.832   6.859   8.000   9.261
 [73]  10.648  12.167  13.824  15.625  17.576  19.683  21.952  24.389  27.000
 [82]  29.791  32.768  35.937  39.304  42.875  46.656  50.653  54.872  59.319
 [91]  64.000  68.921  74.088  79.507  85.184  91.125  97.336 103.823 110.592
[100] 117.649 125.000

Воспользуйтесь командой ниже, чтобы визуализировать вектор и сравнить результат с ожидаемым.

plot(qcres, type = "l")

Подсказка

Может быть два решения:

  • для одного понадобиться
for (variable in vector) {
  ...
}
  • для другого
Map(function, vector)
unlist(list)

#16

В задании 8 мы считали сумму по столбцам матрицы. Но что делать, если нам нужно посчитать несколько статистик по столбцам?

Напишите функцию mat_desc(m), которая будет считать сумму, среднее и медиану по столбцам матрицы.

Фунция должна:

  • принимать на вход матрицу произвольного размера
  • возвращать матрицу с числом столбцов, равным числу столбцов входной матрицы, в которой в первой строке будут суммы, во второй — средние, в третьей — медианы, рассчитанные по столбцам входной матрицы
  • строки матрицы должны быть подписаны sum, mean и median соответственно
       [,1] [,2] [,3] [,4] [,5]
sum       5  2.0  2.0  2.0    5
mean      1  0.4  0.4  0.4    1
median    1  0.0  0.0  0.0    1
Подсказки
apply()
rbind()
rownames()

#17

Создадим список с результатами статистических тестов. Вот такой:

ttests <- list(test1 = list(t = 1.33,
                            p = 0.1),
               test2 = list(t = 2.306,
                            p = 0.025),
               test3 = list(t = 3.527,
                            p = 0.001))
ttests
$test1
$test1$t
[1] 1.33

$test1$p
[1] 0.1


$test2
$test2$t
[1] 2.306

$test2$p
[1] 0.025


$test3
$test3$t
[1] 3.527

$test3$p
[1] 0.001

Этот список состоит из результатов неких трёх t-тестов — test1, test2, test3 — которые являются его элементами. В свою очередь каждый результат также является списком и состоит из двух значений — t и p.

Вытащите из списка ttests p-значения. Результатом должен быть вектор из трех значений.

[1] 0.100 0.025 0.001
Подсказка

Надо пройтись по элементами списка и вытащить из них нужный элемент. Подойдет

for (variable in vector) {
  ...
}

#18

Функции, которые внутри себя содержат цикл — это что-то сложное. Можно вынести его из функции и использовать функцию внутри цикла. Но и то, и другое выглядит громоздко и работает медленно. Есть более красивый вариант.

Ниже представлена функция из задания 15, из которой удален цикл — теперь она может работать только с одним значением x (вектором, длины 1). Согласитель, читаться стало проще:

quad_cube2 <- function(x) {
    if (x < 0) return(0)
    else if (x > 1) return(x^3)
    else return(x^2)
}

C помощью функции Map() выполните её на векторе \(\pmatrix{-5.0 & -4.9 & -4.8 & \dots -0.9 & 0.0 & 0.1 & \dots & 4.8 & 4.9 & 5.0}\).

Изучите результат. При необходимости, переведите его в вектор.

Сохраните результат в переменную qcres2.

Воспользуйтесь командой ниже, чтобы убедиться, что мы получили тот же самый результат.

plot(qcres2, type = "l")

Подсказки
Map(function, vector)
unlist(list)

#19

Давайте аналогичным способом возведем каждый элемент вектора в квадрат. Возьмите вектор \(\pmatrix{1 & 2 & 3 & 4 & 5}\) и возведите каждый его элемент в квадрат с помощью функции Map().

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

[1]  1  4  9 16 25
Подсказка
Map(function(x) ..., vector)

#20

Вытащите p-значения из списка ttests из задания 17 без использования цикла и создания функций. Результат должен быть вектором.

test1 test2 test3 
0.100 0.025 0.001 
Подсказки
Map(function, list)
unlist(list)
Map(function(x) ..., list)

Дополнительные задания

#1

Сгенерируйте 5 [независимых] выборок по 30 наблюдений из генеральной совокупности с нормальным распределением rnorm(..., mean = 10, sd = 20). Результат генерации должен быть представлен в виде матрицы 30×5, где каждый столбец — это одна выборка. Сохраните результат генерации в переменной sim.

Пример сгенерирован при set.seed(24).

             [,1]        [,2]       [,3]        [,4]        [,5]
 [1,]  -0.9176152   9.3252415  39.041504   5.3446569  30.2567252
 [2,]  20.7317061  -1.7085511  18.164031 -18.4072626  10.5068688
 [3,]  18.3924630  22.2570273   1.193319  -6.2664546  -0.1430004
 [4,]  -1.6725440  40.3424499  36.371324  19.2213861  -0.1388647
 [5,]  26.9492003  23.1476087  21.427732   5.7021278  15.2997753
 [6,]  15.3204396 -11.4836267 -15.599744  12.7789050  21.8336348
 [7,]  18.8917054 -79.3912882 -14.777592  26.8846072   4.2331858
 [8,]   0.6700975  17.3809004  -8.451822 -16.1690067  -0.5814076
 [9,]  -6.9674009  13.3845338  36.992241  30.9033732   6.4026923
[10,]  10.0462388 -26.4438064 -21.352332  34.2034785  -8.6087539
[11,] -16.3381625  11.3471540  12.875999  11.6628735 -39.3491209
[12,]  21.9653823  10.3421192  -7.722200  65.6989406   8.9918515
[13,]  -5.2442874   3.1268126   9.488516  21.9056464  14.9287636
[14,] -18.5818061  -3.3578439   3.445292  11.5533270  40.6272574
[15,]  16.6448890   4.8851086   8.480780  -1.1739321  21.8327574
[16,]   0.6187862   0.7758408 -17.093273  -6.1353535 -22.3708390
[17,]   3.3002641  39.4328316  -9.216176  -0.2141812  -2.6986435
[18,]  40.7250431   8.1607937  14.499087  -1.1297424  37.1350898
[19,]  22.1998907  16.7038860   7.536791  14.8225033  -5.1605424
[20,]  20.3267140   5.3627081  10.020820  -1.5067405  17.5072807
[21,]   8.5138288  20.5330512  -1.424865  49.7113946  23.3432774
[22,]  -2.1031389 -11.4725213  18.452436  19.2640549   9.8284752
[23,] -24.1929037  25.3936375 -23.467716  15.8486882  11.8488091
[24,]   4.6261379  45.4181075 -12.720519  -0.2796531  16.4056528
[25,]  -2.9718301   6.0763562  17.224250 -14.7147764  13.3018250
[26,]   8.1177975  14.0949947  31.137284 -40.0246250 -11.0641347
[27,]   8.2891810  -1.9319614 -29.858409 -17.9325648  18.9478935
[28,]  12.3906214  33.5649550  25.287701  -7.9827048  31.1427365
[29,]   7.6740721  30.9884244  10.143307 -16.5459271 -19.5031466
[30,]  -8.8765447  21.2196233  12.039487  14.0573286  14.0146572

#2

Посчитайте среднее (mean()) и стандартное отклонение (sd()) по каждой сгенерированной выборке.

[1] 6.617608 9.582486 5.737908 7.036012 8.625692
[1] 14.40673 23.38371 18.80144 21.72927 17.70765

#3

Продолжим работу над функцией из задания 14.

Модифицируйте её так, чтобы она выводила предупреждение (warning) с содержанием Warning: x has negative value, если в качестве аргумента x передано отрицательное число и аргумент complex равен FALSE.

sqrtn(4, 2)
[1] 2
sqrtn(27, 3)
[1] 3
sqrtn(30, -5)
[1] 0.5064957
sqrtn(-2, 2)
Warning in sqrtn(-2, 2): x has negative value
[1] NaN
sqrtn(-2, 2, complex = TRUE)
[1] 0+1.414214i
Подсказки
warning()
"\n" # new line

#4

Продолжим работу над функцией из предыдущего задания.

Модифицируйте её так, чтобы она выводила сообщение (message) с содержанием x coerced to complex, если в качестве аргумента x передано отрицательное число и аргумент complex равен TRUE, чтобы пользователь был проинформирован о том, что происходит.

sqrtn(4, 2)
[1] 2
sqrtn(27, 3)
[1] 3
sqrtn(30, -5)
[1] 0.5064957
sqrtn(-2, 2)
Warning in sqrtn(-2, 2): x has negative value
[1] NaN
sqrtn(-2, 2, complex = TRUE)
x coerced to complex
[1] 0+1.414214i
Подсказка
message()

#5

Продолжим работу над функцией из предыдущего задания и доведем её до совершенства.

Модифицируйте её так, чтобы она заканчивала работу с ошибкой (error) с содержанием argument `complex` must be a logical constant, если в качестве аргумента complex передано какое-либо значение, кроме логического.

sqrtn(4, 2)
[1] 2
sqrtn(27, 3)
[1] 3
sqrtn(30, -5)
[1] 0.5064957
sqrtn(-2, 2)
Warning in sqrtn(-2, 2): x has negative value
[1] NaN
sqrtn(-2, 2, complex = TRUE)
x coerced to complex
[1] 0+1.414214i
sqrtn(-2, 2, complex = "no")
Error in sqrtn(-2, 2, complex = "no"): argument `complex` must be a logical constant
Подсказка
stop()

#6

В задании 16 мы сделали функцию, которая считает сумму, среднее и медиану по столбцам матрицы.

а. Попробуйте вызвать её на матрице multab. Каков результат? Почему так?

  1. Модифицируйте функцию так, чтобы она могла принимать на вход аргументы, необходимые для её внутренних функций, и пробрасывать их им. Функция должна корректно обрабатывать любые необходимые аргументы.
mat_desc(multab)
       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
sum      NA   NA   NA   NA   NA   NA   NA   NA   NA
mean     NA   NA   NA   NA   NA   NA   NA   NA   NA
median   NA   NA   NA   NA   NA   NA   NA   NA   NA
mat_desc(multab, na.rm = TRUE)
       [,1] [,2]  [,3] [,4]  [,5] [,6]  [,7] [,8]  [,9]
sum       0   70 117.0  168 220.0  264 308.0  352 396.0
mean    NaN   14  19.5   24  27.5   33  38.5   44  49.5
median   NA   14  19.5   24  27.5   33  38.5   44  49.5
mat_desc(sim)
             [,1]       [,2]       [,3]       [,4]       [,5]
sum    198.528225 287.474567 172.137252 211.080367 258.770756
mean     6.617608   9.582486   5.737908   7.036012   8.625692
median   7.895935  10.844637   8.984648   5.523392  11.177839
mat_desc(sim, trim = .5)
             [,1]      [,2]       [,3]       [,4]      [,5]
sum    199.028225 287.97457 172.637252 211.580367 259.27076
mean     7.895935  10.84464   8.984648   5.523392  11.17784
median   7.895935  10.84464   8.984648   5.523392  11.17784
Подсказка
help("...")

#7

До этого мы генерировали случайные вектора только из нормального распределения (rnorm()), однако мир распределений одним нормальным не ограничивается.

Напишите функцию, которая генерирует [независимые] выборки из любого заданного распределения.

Функция — назовем её gen_dist — должна:

  • принимать на вход следующие параметры:
    • количество выборок, которые необходимо сгенерировать — n_samples
    • количество наблюдений в одной выборке — n_obs
    • функцию распределения, из которого необходимо выполнить генерацию — fun
      • по умолчанию функция должна генерировать выборки из нормального распределения
    • другие аргументы, необходимые для работы функции распределения
  • возвращать матрицу, размером n_obs×n_samples, содержащую сгенерированные значения
gen_dist(5, 10)
             [,1]        [,2]       [,3]       [,4]       [,5]
 [1,] -0.07045269 -0.28676782  1.3595626 -0.2782413  0.3287331
 [2,] -0.75031916 -0.52928746  1.3923633  1.1369704  1.2029108
 [3,] -0.09401376 -0.55704503 -1.6319603  0.9784894 -1.1780358
 [4,]  0.41274946 -0.54843891  0.9944335  1.6473931  0.9161471
 [5,] -1.25747896  0.06374339  1.5975855 -1.5064649 -0.3907390
 [6,]  0.19706349 -1.17805997 -0.6759391 -1.7938317 -0.3312926
 [7,] -1.89231492 -1.37490185  0.5056523 -1.3929986 -0.8074692
 [8,]  0.25217616  0.33334974  0.8613147  0.4638977  0.1419368
 [9,] -0.64785092  0.55974467  0.7455506  0.7481314  0.3662677
[10,] -0.26605768 -1.15775671  0.9483999  1.2235673 -2.0921697
gen_dist(5, 3, mean = 8, sd = 12)
          [,1]      [,2]        [,3]       [,4]       [,5]
[1,]  7.752419 14.334106 13.17928270  27.391833 -0.7910348
[2,] -2.844010 -5.938432 22.74866106 -26.272741 28.1433925
[3,] 33.761001 11.920114 -0.07093902   1.166308 12.6606099
gen_dist(3, 5, fun = rbeta, shape1 = 2, shape2 = 3)
          [,1]      [,2]      [,3]
[1,] 0.3045953 0.4159781 0.5546832
[2,] 0.1453501 0.3029234 0.1187707
[3,] 0.5764221 0.4637129 0.1048004
[4,] 0.6585448 0.3387338 0.2995576
[5,] 0.2085483 0.1863473 0.3125800

#8

Вычислите:

  1. \(\sum_{i=1}^{30}\sum_{j=1}^{10} \frac{i^4}{1 + j}\)
[1] 81138.45
  1. \(\sum_{i=1}^{30}\sum_{j=1}^{10} \frac{i^4}{i + j}\)
[1] 837.1427
Подсказка
outer()

#9

Вычислите:

  1. \(\sum_{i=1}^{10}\sum_{j=2}^8\sum_{k=3}^6 \frac{i^k}{i-j}\)
[1] 28.28571
  1. \(\sum_{i=1}^{10}\sum_{j=1}^i \frac{i^4}{3 + ij}\)
[1] 6944.743
Подсказка
outer(..., ..., function)

#10

Вычислите первые 20 чисел Фибоначчи. Первым числом считайте \(F_0 = 0\).

Числа Фибоначчи задаются следующей последовательностью:

\[ F_0 = 0, \quad F_1 = 1, F_n = F_{n-1} + F_{n-2} \]

 [1]    0    1    1    2    3    5    8   13   21   34   55   89  144  233  377
[16]  610  987 1597 2584 4181

Некоторые задания, а также форматы заданий, подсмотрены у Мороз (2022) и Grinberg and Reed (2016).