0Pricing
R Academy · Урок

map2() и pmap() для нескольких входных данных

Одновременно перебирайте два или более списка с помощью map2() и pmap().

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

Перебор нескольких входных данных

map() за один раз выполняет перебор одного входного набора. Однако многим функциям нужны два или более параллельных входных набора. map2() из purrr работает с двумя входными наборами, а pmap() — с любым их количеством. Обе функции гарантируют возвращаемое значение того же безопасного для типа типа.

library(purrr)

# Simulate: add corresponding elements from two vectors
x <- c(1, 2, 3, 4)
y <- c(10, 20, 30, 40)

# map2 applies fn(x[i], y[i]) for each i
result <- map2(x, y, function(a, b) a + b)
print(result)

map2() — два параллельных входных набора

map2(.x, .y, .f) применяет .f(x_i, y_i) к соответствующим элементам .x и .y. Оба вектора должны иметь одинаковую длину (либо длина одного из них должна быть равна 1, чтобы его можно было повторять). Функция возвращает список.

library(purrr)

names_vec <- c('Alice','Bob','Carol')
scores_vec <- c(85, 92, 78)

# Build a personalized message for each student
map2_chr(names_vec, scores_vec,
         ~paste(.x, 'scored', .y, 'points'))

map2() с сокращённой записью ~

Формульная сокращённая запись ~expr работает и с map2(): .x обозначает первый входной набор, а .y — второй. Благодаря этому анонимные функции с двумя аргументами остаются лаконичными.

library(purrr)

lower_bounds <- c(0, 10, 20, 50)
upper_bounds <- c(9, 19, 49, 100)

# Create labels for each range
map2_chr(lower_bounds, upper_bounds,
         ~paste0('[', .x, '-', .y, ']'))

Типизированные варианты map2()

Как и map(), map2() имеет типизированные варианты, гарантирующие тип результата: map2_dbl(), map2_chr(), map2_lgl(), map2_int() и map2_df(). Используйте вариант, соответствующий ожидаемому типу результата.

library(purrr)

actual <- c(100, 150, 200, 120)
target <- c(110, 140, 195, 130)

# Numeric: percentage achievement
map2_dbl(actual, target, ~round(100 * .x / .y, 1))

# Logical: did they meet their target?
map2_lgl(actual, target, ~.x >= .y)

pmap() — любое количество входных наборов

pmap(.l, .f) принимает первым аргументом список векторов. Каждый вектор представляет отдельный входной поток. Функция одновременно получает соответствующие элементы из всех входных потоков.

library(purrr)

# Three parallel inputs
params <- list(
  name = c('Alice','Bob','Carol'),
  score = c(85, 92, 78),
  grade = c('B','A','C')
)

pmap_chr(params, function(name, score, grade) {
  paste(name, ':', score, '(', grade, ')')
})

pmap() с датафреймом

Датафрейм — это список столбцов, поэтому его можно напрямую передать первым аргументом в pmap(). Функция получает значения одной строки в виде именованных аргументов: имена столбцов сопоставляются с именами параметров.

library(purrr)

params_df <- data.frame(
  mean_val = c(0, 5, 10),
  sd_val = c(1, 2, 3),
  n = c(100, 50, 200)
)

# Generate samples from different normal distributions
set.seed(42)
results <- pmap(params_df, function(mean_val, sd_val, n) {
  rnorm(n, mean=mean_val, sd=sd_val)
})

map_dbl(results, mean)

Перебор сеток параметров

Один из распространённых вариантов использования pmap() — перебор сетки параметров модели. Используйте expand.grid() или tidyr::expand_grid(), чтобы создать комбинации параметров, а затем pmap(), чтобы запустить эксперимент для каждой строки.

library(purrr)

# Create a parameter grid
grid <- expand.grid(
  learning_rate = c(0.01, 0.1),
  epochs = c(10, 50),
  batch_size = c(32, 64)
)

# Simulate model training results
set.seed(42)
grid$accuracy <- pmap_dbl(grid, function(learning_rate, epochs, batch_size) {
  base <- 0.5 + 0.3 * log10(epochs) + 0.1 * learning_rate
  round(min(base + rnorm(1, 0, 0.02), 0.99), 3)
})

print(grid[order(-grid$accuracy),])

map2_df() — создание датафреймов

map2_df() (или map2_dfr()) применяет функцию к двум параллельным входным наборам и объединяет полученные датафреймы по строкам. Это удобно для сравнения двух наборов элементов или объединения параллельных наборов данных.

library(purrr)

q1_sales <- list(East=100, West=200, North=80)
q2_sales <- list(East=120, West=190, North=95)

map2_df(q1_sales, q2_sales, function(q1, q2) {
  data.frame(
    q1 = q1,
    q2 = q2,
    change = q2 - q1,
    pct = round(100*(q2-q1)/q1, 1)
  )
}, .id = 'region')

Сочетание pmap() и nest()

Сочетание pmap() с вложенными датафреймами и параметрами модели позволяет использовать мощный шаблон: хранить гиперпараметры и данные в одном датафрейме, а затем применять pmap() к строкам, обучая модели с каждым набором параметров.

library(purrr)
library(dplyr)

# Simulate polynomial regression with different degrees
set.seed(42)
x <- 1:20
y <- 2*x + 0.5*x^2 + rnorm(20, 0, 10)
df <- data.frame(x=x, y=y)

configs <- data.frame(degree = 1:3)
configs$r2 <- map_dbl(configs$degree, function(d) {
  m <- lm(y ~ poly(x, d), data=df)
  summary(m)$r.squared
})

print(configs)

Обработка ошибок с possibly()

В рабочих процессах с map2()/pmap() один некорректный вход может прервать всю операцию. Оберните функцию в possibly(fn, otherwise=NA), чтобы перехватывать ошибки и возвращать значение по умолчанию. Так конвейер продолжит работу, даже если обработка некоторых входных данных завершится неудачно.

library(purrr)

safe_log <- possibly(log, otherwise=NA_real_)

values <- list(10, -5, 100, 0, 50)

# Without possibly(): log() warns for negative numbers
# With possibly(): errors return NA, computation continues
map_dbl(values, safe_log)

Практика: перекрёстная проверка с pmap()

Практическое применение pmap(): выполните k-кратную перекрёстную проверку, перебирая разбиения на блоки. pmap() передаёт функции обучения данные для обучения и проверки каждого блока, возвращая показатель качества для каждого из них.

library(purrr)

set.seed(42)
df <- data.frame(x=1:20, y=2*(1:20)+rnorm(20,0,3))
df$fold <- sample(rep(1:5, 4))

# Compute RMSE for each held-out fold
folds <- 1:5
rmse_vals <- map_dbl(folds, function(k) {
  train <- df[df$fold != k, ]
  test <- df[df$fold == k, ]
  m <- lm(y ~ x, data=train)
  preds <- predict(m, newdata=test)
  sqrt(mean((test$y - preds)^2))
})

cat('Per-fold RMSE:', round(rmse_vals, 2), '\n')
cat('Mean RMSE:', round(mean(rmse_vals), 2))

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

Какая функция purrr подходит для одновременного перебора более двух параллельных входных векторов?

Итоги: map2() и pmap()

Главные выводы о сопоставлении нескольких входных наборов:

  • map2(.x, .y, .f) — перебирает два параллельных входных набора; в сокращённой записи ~ используются .x и .y
  • map2_dbl/chr/lgl/int/df() — типизированные варианты, гарантирующие тип результата
  • pmap(.l, .f) — одновременно перебирает список с любым количеством векторов
  • Передайте датафрейм в pmap() — имена столбцов станут именами параметров функции
  • Используйте expand.grid() + pmap() для поиска по сетке параметров
  • Оберните функции в possibly(fn, NA) для безопасной обработки ошибок
library(purrr)

# pmap with a data frame: each row = one function call
params <- data.frame(
  mean_val = c(0, 10, 100),
  sd_val = c(1, 5, 20),
  label = c('control','mid','high')
)

pmap_chr(params, function(mean_val, sd_val, label) {
  sprintf('%s: mean=%.0f, sd=%.0f', label, mean_val, sd_val)
})

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

Урок «map2() и pmap() для нескольких входных данных» бесплатный?

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

Чему я научусь в уроке «map2() и pmap() для нескольких входных данных»?

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

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

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

Сколько времени занимает урок «map2() и pmap() для нескольких входных данных»?

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

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

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

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

  1. map() и типизированные варианты
  2. map2() и pmap() для нескольких входных данных
  3. reduce(), accumulate() и walk()
  4. keep(), discard() и фильтрация списков
← Назад к R Academy