R Academy · Les

furrr: parallelle purrr-bewerkingen

Vervang map() rechtstreeks door future_map() om direct te parallelliseren.

Les 3 van 413 stappen

furrr: parallelle purrr-bewerkingen is een gratis R Academy-les op CoddyKit. Dit is les 3 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject R Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus R Academy bevat in totaal 4 lessen.

furrr: parallelle purrr

furrr (future + purrr) biedt directe parallelle vervangers voor alle purrr::map_*()-functies. Vervang eenvoudig map() door future_map() nadat je een plan() hebt ingesteld; je pijplijn wordt dan parallel uitgevoerd zonder structurele wijzigingen.

library(furrr)
library(future)

# Set up parallel workers
plan(multisession, workers = 4)

# Sequential (purrr)
# result <- purrr::map(1:8, ~.x^2)

# Parallel (furrr) — identical API
result <- future_map(1:8, ~.x^2)
cat(unlist(result), '\n')  # 1 4 9 16 25 36 49 64

plan(sequential)

plan(multisession, workers = 4)

Door workers expliciet in plan() op te geven, beperk je het aantal parallelle R-sessies. Voor taken die de processor intensief gebruiken, is workers = parallel::detectCores() - 1 een gebruikelijke conventie, zodat één processorkern beschikbaar blijft voor het besturingssysteem.

library(furrr)
library(future)
library(parallel)

# Explicit worker count
n_workers <- max(1, detectCores() - 1)
plan(multisession, workers = n_workers)

cat('Active workers:', nbrOfWorkers(), '\n')
cat('Strategy:', class(plan())[1], '\n')

# Run a simple parallel task
results <- future_map_dbl(1:8, ~sqrt(.x))
cat(round(results, 3), '\n')

plan(sequential)

future_map_dbl en varianten met een vast type

Net als purrr biedt furrr varianten met een vast type: future_map_dbl(), future_map_int(), future_map_chr() en future_map_lgl(). Ze dwingen het retourtype af en geven een atomair vector terug in plaats van een lijst.

library(furrr)
plan(multisession, workers = 2)

# Returns a numeric vector
square_roots <- future_map_dbl(1:6, ~sqrt(.x))
cat('dbl:', round(square_roots, 3), '\n')

# Returns an integer vector
counts <- future_map_int(list('hello', 'world', 'R'), nchar)
cat('int:', counts, '\n')

# Returns a character vector
formatted <- future_map_chr(c(1.23, 4.56, 7.89), ~sprintf('%.1f', .x))
cat('chr:', formatted, '\n')

# Returns a logical vector
positive <- future_map_lgl(-3:3, ~.x > 0)
cat('lgl:', positive, '\n')

plan(sequential)

future_map2: toewijzing met twee invoeren

future_map2(.x, .y, .f) doorloopt twee lijsten of vectoren parallel en geeft overeenkomstige paren door aan de functie. Dit is het parallelle equivalent van purrr::map2().

library(furrr)
plan(multisession, workers = 2)

# Simulate different sample sizes and means
sizes <- c(100, 200, 300, 400)
means <- c(0, 5, -3, 10)

# future_map2 passes each (n, mu) pair to rnorm
samples <- future_map2(sizes, means, ~rnorm(.x, mean = .y))

# Verify: each element has the expected length and approximate mean
for (i in seq_along(samples)) {
  cat('n=', sizes[i], 'target_mean=', means[i],
      'observed_mean=', round(mean(samples[[i]]), 2), '\n')
}

plan(sequential)

furrr_options: gedrag bepalen

furrr_options() wordt als het argument .options doorgegeven aan elke aanroep van future_map_*(). De belangrijkste instelling is seed = TRUE, waarmee de parallelle RNG van L'Ecuyer-CMRG wordt geactiveerd voor reproduceerbare willekeurige getallen op verschillende workers.

library(furrr)
plan(multisession, workers = 2)

# Without seed: results differ each run
r1 <- future_map_dbl(1:4, ~rnorm(1))
r2 <- future_map_dbl(1:4, ~rnorm(1))
cat('Without seed - same?', identical(r1, r2), '\n')

# With seed: reproducible
opts <- furrr_options(seed = 42L)
r3 <- future_map_dbl(1:4, ~rnorm(1), .options = opts)
r4 <- future_map_dbl(1:4, ~rnorm(1), .options = opts)
cat('With seed - same?', identical(r3, r4), '\n')
cat('r3:', round(r3, 4), '\n')

plan(sequential)

Voortgang rapporteren met progressr

Het pakket progressr werkt samen met furrr om tijdens parallelle uitvoering voortgangsbalken weer te geven. Wikkel je code in with_progress() en maak binnen de toegepaste functie een progressor().

library(furrr)
library(progressr)
plan(multisession, workers = 2)

# Enable progress reporting
handlers(global = TRUE)  # show progress in console

with_progress({
  p <- progressor(steps = 8)

  results <- future_map(1:8, function(i) {
    p()  # increment the progress bar
    Sys.sleep(0.1)
    i^2
  })
})

cat('Results:', unlist(results), '\n')

plan(sequential)

Globale variabelen in furrr

Net als het pakket future detecteert furrr automatisch globale variabelen waarnaar binnen .f wordt verwezen. Je kunt dit overschrijven met furrr_options(globals = c('var1', 'var2')) om precies op te geven welke globale variabelen moeten worden verzonden. Zo beperk je de overhead voor grote omgevingen.

library(furrr)
plan(multisession, workers = 2)

# Global variables auto-detected
scale_factor <- 10
offset <- 5

result <- future_map_dbl(
  1:6,
  function(x) x * scale_factor + offset
)
cat(result, '\n')  # 15 25 35 45 55 65

# Explicit globals control
opts <- furrr_options(
  globals = c('scale_factor', 'offset'),
  seed = FALSE
)
result2 <- future_map_dbl(
  1:6,
  function(x) x * scale_factor + offset,
  .options = opts
)
cat('Manual globals:', result2, '\n')

plan(sequential)

future_pmap: toewijzing met meerdere argumenten

future_pmap(.l, .f) is de parallelle versie van purrr::pmap(). De functie accepteert een lijst met vectoren/lijsten en geeft overeenkomstige rijen door als benoemde argumenten, zodat parallel rekenen over meerdere parametercombinaties mogelijk wordt.

library(furrr)
plan(multisession, workers = 2)

# Parameter grid
params <- list(
  n    = c(50, 100, 150, 200),
  mean = c(0, 1, 2, 3),
  sd   = c(1, 2, 1, 0.5)
)

# future_pmap passes each row as arguments to rnorm
samples <- future_pmap(params, function(n, mean, sd) {
  x <- rnorm(n, mean = mean, sd = sd)
  c(obs_mean = round(mean(x), 3), obs_sd = round(sd(x), 3))
})

for (i in seq_along(samples)) {
  cat('n=', params$n[i], ':', samples[[i]], '\n')
}

plan(sequential)

furrr vergelijken met purrr

De voordelen van parallellisme groeien mee met de zwaarte van de taak. Bij triviale bewerkingen (x^2) overheerst de overhead en is sequentiële uitvoering sneller. Bij zware taken, zoals het fitten van veel modellen, bespaart parallelle uitvoering aanzienlijk veel tijd.

library(furrr)
library(purrr)
plan(multisession, workers = 4)

# Heavy task: bootstrap a linear model 100 times
heavy <- function(i) {
  n <- 200
  df <- data.frame(x = rnorm(n), y = rnorm(n))
  coef(lm(y ~ x, data = df))[['x']]
}

seq_time <- system.time(map_dbl(1:40, heavy))[['elapsed']]
par_time <- system.time(
  future_map_dbl(1:40, heavy, .options = furrr_options(seed = TRUE))
)[['elapsed']]

cat('Sequential:', round(seq_time, 2), 's\n')
cat('Parallel:  ', round(par_time, 2), 's\n')
cat('Speedup:   ', round(seq_time / max(par_time, 0.001), 2), 'x\n')

plan(sequential)

Foutafhandeling in future_map

Als de berekening van een element een fout veroorzaakt, stopt future_map() en gooit de functie de fout opnieuw. Gebruik purrr::safely() of purrr::possibly() als wikkelfunctie rond je functie om ondanks fouten door te gaan.

library(furrr)
library(purrr)
plan(multisession, workers = 2)

# Wrap with safely() to capture errors as results
safe_log <- safely(log, otherwise = NA_real_)

inputs <- list(10, -1, 100, 'text', 0.5)
results <- future_map(inputs, safe_log)

for (i in seq_along(results)) {
  if (is.null(results[[i]]$error)) {
    cat('Input', i, '-> result:', round(results[[i]]$result, 4), '\n')
  } else {
    cat('Input', i, '-> error:', conditionMessage(results[[i]]$error), '\n')
  }
}

plan(sequential)

Praktische furrr-pijplijn

Hier is een complete pijplijn van begin tot eind: gegevens laden, meerdere modellen parallel fitten met reproduceerbare seeds, prestatiemetrieken ophalen en het beste model selecteren — allemaal met de furrr-werkwijze.

library(furrr)
library(purrr)
plan(multisession, workers = 4)

set.seed(1)
n <- 300
df <- data.frame(
  x1 = rnorm(n), x2 = rnorm(n), x3 = rnorm(n),
  y  = rnorm(n)
)

formulas <- list(
  y ~ x1,
  y ~ x1 + x2,
  y ~ x1 + x2 + x3,
  y ~ x1 * x2
)

# Fit all models in parallel
models <- future_map(
  formulas,
  ~lm(.x, data = df),
  .options = furrr_options(seed = FALSE)
)

# Extract adjusted R-squared
adj_r2 <- map_dbl(models, ~summary(.x)$adj.r.squared)
cat('Adjusted R2 per model:',
    paste(round(adj_r2, 4), collapse = ', '), '\n')
cat('Best model:', which.max(adj_r2), '\n')

plan(sequential)

Korte controle

Je wilt reproduceerbare willekeurige getallen bij parallelle aanroepen van future_map(). Welke instelling van furrr_options() maakt dit mogelijk?

Samenvatting: het furrr-pakket

Belangrijkste punten:

  • furrr is een directe parallelle vervanger voor purrr — vervang map eenvoudig door future_map
  • Stel eerst een backend in met plan(multisession, workers = n)
  • Varianten met een vast type: future_map_dbl(), future_map_int(), future_map_chr()
  • Gebruik future_map2() en future_pmap() voor parallelle toewijzing met meerdere invoeren
  • Gebruik furrr_options(seed = 42L) voor reproduceerbare parallelle RNG
  • Integreer progressr voor voortgangsbalken tijdens langdurige parallelle taken
  • Gebruik purrr::safely() binnen future_map() voor pijplijnen die bestand zijn tegen fouten
library(furrr)
plan(multisession, workers = 2)

results <- future_map_dbl(
  1:6,
  ~.x^2 + sqrt(.x),
  .options = furrr_options(seed = TRUE)
)
cat(round(results, 3), '\n')

plan(sequential)
Gratis beginnen

Leer R met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
43
Lessen
159

Veelgestelde vragen

Is de les “furrr: parallelle purrr-bewerkingen” gratis?

Ja — je kunt hier op het web alle 3 lessen van het leerpad R Academy, waaronder “furrr: parallelle purrr-bewerkingen”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus R Academy bevat in totaal 4 lessen.

Wat leer ik in “furrr: parallelle purrr-bewerkingen”?

Vervang map() rechtstreeks door future_map() om direct te parallelliseren. Je oefent met R Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met R Academy te beginnen?

Ervaring vooraf is niet nodig. R Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.

Hoe lang duurt de les “furrr: parallelle purrr-bewerkingen”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over R Academy?

Ja. Elke les over R Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Pakket parallel en detectCores()
  2. Het future-framework
  3. furrr: parallelle purrr-bewerkingen
  4. Parallelle code debuggen en load balancing
← Terug naar R Academy