R Academy · Урок

Вложенные и развёрнутые таблицы данных

Используйте nest() и unnest() для работы со столбцами-списками в аккуратных рабочих процессах.

Урок 4 из 413 шагов

«Вложенные и развёрнутые таблицы данных» — бесплатный урок R Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения R Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс R Academy содержит 4 уроков всего.

Столбцы-списки и вложенные данные

Столбец-список — это столбец таблицы данных, в каждой ячейке которого содержится объект R (вектор, таблица данных, модель или список). Это позволяет хранить структурированные подданные рядом с другими столбцами и выполнять мощные операции по группам.

library(tidyr)
library(dplyr)

# A simple data frame with a list-column
df <- data.frame(
  group = c('A','B','C'),
  n = c(3, 2, 4)
)
df$values <- list(c(1,2,3), c(4,5), c(6,7,8,9))

print(df)
print(df$values[[1]])  # Access the first list element

nest() — создание вложенных таблиц данных

nest(df, data = c(col1, col2)) группирует строки по столбцам, не включённым во вложенные данные, и упаковывает указанные столбцы в столбец-список из таблиц данных. Для каждой группы создаётся одна строка, содержащая небольшую таблицу данных.

library(tidyr)
library(dplyr)

df <- data.frame(
  region = c('East','East','East','West','West'),
  month = c(1,2,3,1,2),
  sales = c(100,120,110,200,190)
)

nested <- df %>%
  nest(data = c(month, sales))

print(nested)
print(nested$data[[1]])  # East region's data

nest() с group_by()

Наиболее распространённый шаблон: используйте group_by(), а затем nest(), чтобы создать по одной строке на группу, упаковав все остальные столбцы в столбец-список data. В новых версиях tidyr это эквивалентно nest(.by = group_col).

library(tidyr)
library(dplyr)

df <- data.frame(
  category = c('A','A','A','B','B','C','C','C','C'),
  x = c(1,2,3,4,5,6,7,8,9),
  y = c(2,4,3,8,7,5,6,9,8)
)

nested <- df %>%
  group_by(category) %>%
  nest()

print(nested)
cat('Rows per category B:', nrow(nested$data[[2]]))

map() с вложенными таблицами данных

После вложения данных используйте purrr::map(), чтобы применить функцию к каждой небольшой таблице данных. Функция получает по одной таблице данных за раз, а результаты становятся новым столбцом-списком — часто содержащим подогнанную модель.

library(tidyr)
library(dplyr)
library(purrr)

df <- data.frame(
  group = c('A','A','A','B','B','B'),
  x = c(1,2,3,1,2,3),
  y = c(2.1,4.0,5.9,3.2,5.8,9.1)
)

models <- df %>%
  group_by(group) %>%
  nest() %>%
  mutate(model = map(data, ~lm(y ~ x, data = .x)))

print(models)

Извлечение результатов моделей с помощью map()

После построения моделей для каждой группы используйте map() с такими функциями, как broom::tidy() или coef(), чтобы извлечь результаты каждой модели. Результатом будет ещё один столбец-список, который позднее можно развернуть.

library(tidyr)
library(dplyr)
library(purrr)

df <- data.frame(
  group = c('A','A','A','B','B','B'),
  x = c(1,2,3,1,2,3),
  y = c(2.1,4.0,5.9,3.2,5.8,9.1)
)

df %>%
  group_by(group) %>%
  nest() %>%
  mutate(
    model = map(data, ~lm(y ~ x, data = .x)),
    r_squared = map_dbl(model, ~summary(.x)$r.squared),
    intercept = map_dbl(model, ~coef(.x)[1]),
    slope = map_dbl(model, ~coef(.x)[2])
  ) %>%
  select(group, r_squared, intercept, slope)

unnest() — разворачивание столбцов-списков

unnest(df, cols = data) является обратной операцией по отношению к nest(). Она разворачивает столбец-список обратно в обычные столбцы, при необходимости повторяя столбцы с идентификаторами. Используйте cols, чтобы указать, какой столбец-список нужно развернуть.

library(tidyr)
library(dplyr)

nested <- data.frame(
  region = c('East','West')
)
nested$data <- list(
  data.frame(month=1:3, sales=c(100,120,110)),
  data.frame(month=1:2, sales=c(200,190))
)

unnested <- unnest(nested, cols = data)
print(unnested)

unnest_longer() — разворачивание списка в строки

unnest_longer(df, col) разворачивает столбец-список так, чтобы каждый элемент списка стал отдельной строкой. В отличие от unnest(), ожидающей таблицы данных, unnest_longer() работает со списками векторов или отдельных значений.

library(tidyr)

df <- data.frame(
  person = c('Alice','Bob','Carol')
)
df$skills <- list(
  c('R','Python','SQL'),
  c('Excel','Tableau'),
  c('R','Julia','Stan','BUGS')
)

unnest_longer(df, skills)

unnest_wider() — разворачивание списка в столбцы

unnest_wider(df, col) разворачивает каждый элемент списка в набор новых столбцов. Список должен содержать именованные элементы — их имена становятся именами столбцов. Это полезно для вложенных структур, подобных JSON.

library(tidyr)

df <- data.frame(id = 1:3)
df$info <- list(
  list(name='Alice', age=30, city='NYC'),
  list(name='Bob', age=25, city='LA'),
  list(name='Carol', age=35, city='Chicago')
)

unnest_wider(df, info)

Полный шаблон работы с вложенными данными

Полный рабочий процесс с вложенной таблицей данных: group_by() + nest() → применение функций с помощью map() → извлечение результатов → unnest() для возврата к плоской таблице данных. Этот шаблон позволяет выполнять любой анализ отдельно для каждой группы.

library(tidyr)
library(dplyr)
library(purrr)

df <- data.frame(
  region = c('East','East','East','West','West','West'),
  month = c(1,2,3,1,2,3),
  revenue = c(100,120,115,200,195,210)
)

df %>%
  group_by(region) %>%
  nest() %>%
  mutate(
    mean_rev = map_dbl(data, ~mean(.x$revenue)),
    trend = map_dbl(data, ~coef(lm(revenue~month, data=.x))[2])
  ) %>%
  select(region, mean_rev, trend)

Вложение нескольких столбцов

Вы можете выборочно указать, какие столбцы должны войти во вложенную таблицу данных. Явно укажите их в nest(data = c(...)). Неуказанные столбцы останутся обычными столбцами внешней таблицы данных рядом со столбцом-списком.

library(tidyr)
library(dplyr)

df <- data.frame(
  region = c('East','East','West','West'),
  year = c(2023,2024,2023,2024),
  q1 = c(100,110,200,210),
  q2 = c(105,115,195,215),
  target = c(105,112,198,212)
)

# Only nest quarterly data, keep target as outer column
nested <- df %>%
  group_by(region, year) %>%
  nest(quarters = c(q1, q2))

print(nested)

Когда использовать вложенные таблицы данных

Вложенные таблицы данных особенно полезны, когда нужно обучить одну и ту же модель для разных групп, выполнить симуляции по группам, применить сложные преобразования к подмножествам или работать с иерархическими данными, подобными JSON. Они позволяют хранить данные групп рядом с метаданными на уровне группы.

library(tidyr)
library(dplyr)
library(purrr)

# Bootstrap confidence interval per group
df <- data.frame(
  group = c('A','A','A','A','B','B','B','B'),
  value = c(10,12,11,13,20,22,19,21)
)

set.seed(42)
df %>%
  group_by(group) %>%
  nest() %>%
  mutate(
    boot_means = map(data, function(d) {
      replicate(100, mean(sample(d$value, replace=TRUE)))
    }),
    ci_low = map_dbl(boot_means, ~quantile(.x, 0.025)),
    ci_high = map_dbl(boot_means, ~quantile(.x, 0.975))
  ) %>%
  select(group, ci_low, ci_high)

Быстрая проверка

Как правильно развернуть столбец-список из таблиц данных обратно в плоскую таблицу данных?

Итоги: вложение и разворачивание

Главные выводы о работе с вложенными таблицами данных:

  • nest(data = c(cols)) — упаковывает столбцы в столбец-список из таблиц данных, по одной на группу
  • group_by() + nest() — стандартный шаблон вложения данных по группам
  • map(nested$data, fn) — применяет любую функцию к каждой вложенной таблице данных
  • unnest(cols = data) — разворачивает столбец-список из таблиц данных обратно в плоский формат
  • unnest_longer(col) — разворачивает список векторов или отдельных значений в строки
  • unnest_wider(col) — разворачивает именованный список в столбцы
  • Идеально подходит для моделирования по группам, бутстрепа и обработки данных JSON
library(tidyr)
library(dplyr)
library(purrr)

data.frame(
  team = c('A','A','B','B'),
  x = c(1,2,1,2),
  y = c(2,4,3,6)
) %>%
  group_by(team) %>%
  nest() %>%
  mutate(
    model = map(data, ~lm(y ~ x, data = .x)),
    slope = map_dbl(model, ~coef(.x)['x'])
  ) %>%
  select(team, slope)
Можно начать бесплатно

Изучай R с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
43
Уроки
159

Часто задаваемые вопросы

Урок «Вложенные и развёрнутые таблицы данных» бесплатный?

Да — полный текст урока «Вложенные и развёрнутые таблицы данных» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс R Academy, подпишись на CoddyKit PRO. Курс R Academy содержит 4 уроков всего.

Чему я научусь в уроке «Вложенные и развёрнутые таблицы данных»?

Используйте nest() и unnest() для работы со столбцами-списками в аккуратных рабочих процессах. Ты практикуешь R Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать R Academy?

Предыдущий опыт не требуется. R Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Вложенные и развёрнутые таблицы данных»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке R Academy?

Да. Каждый урок R Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Из широкого формата в длинный с pivot_longer()
  2. Из длинного формата в широкий с pivot_wider()
  3. separate() и unite() для строковых столбцов
  4. Вложенные и развёрнутые таблицы данных
← Назад к R Academy