reduce()、accumulate()、walk()
リストを畳み込み、累積結果を作成し、walk()で副作用を適用します。
「reduce()、accumulate()、walk()」はCoddyKit上の無料R Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはR Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 R Academyコースには全4レッスンが含まれています。
map()の先へ — その他のpurrr動詞
map()は各要素に独立して関数を適用しますが、タスクによっては要素を結合(reduce)したり、中間結果を蓄積したり、純粋に副作用のために関数を適用したり(walk)する必要があります。purrrには、それぞれの用途に対応する専用関数があります。
library(purrr)
# Example: combining a list of numbers into a single value
nums <- list(1, 2, 3, 4, 5)
# We want: 1 + 2 + 3 + 4 + 5 = 15
# map() can't do this — it returns 5 separate results
# reduce() folds the list into one value
result <- reduce(nums, `+`)
cat('Sum via reduce:', result)reduce() — リストを1つの値に畳み込む
reduce(.x, .f, .init)は、.xの要素に左から右へ.fを累積的に適用し、リストを1つの値に縮約します。reduce(list(a,b,c), f)はf(f(a,b),c)を計算します。
library(purrr)
# reduce with max: find the overall maximum
values <- list(42, 17, 89, 55, 23)
result <- reduce(values, max)
cat('Maximum:', result, '\n')
# reduce with paste: concatenate strings
words <- list('The', 'quick', 'brown', 'fox')
reduce(words, paste).initを指定したreduce()
.init引数は開始値(シード値)を指定します。最初の呼び出しはf(.init, x[1])になります。リストが空になる可能性がある場合(.initに縮約されます)や、特定の初期状態が必要な場合に不可欠です。
library(purrr)
# Running count of elements matching a condition
data <- list(5, 12, 3, 18, 7, 15, 2)
# Count values greater than 10, starting from 0
reduce(data, function(count, x) count + (x > 10), .init = 0L)
# Also useful for string building:
reduce(c('A','B','C'), paste, sep='-', .init='START')データフレームでreduce()を使う — joinの連結
reduce()の特に強力な用途の1つが、データフレームのリストを結合することです。left_join(left_join(df1, df2), df3)と書く代わりに、reduce(list_of_dfs, left_join, by='key')を使用できます。
library(purrr)
library(dplyr)
base_df <- data.frame(id=1:3, name=c('Alice','Bob','Carol'))
scores <- data.frame(id=1:3, score=c(85,90,78))
grades <- data.frame(id=1:3, grade=c('B','A','C'))
city <- data.frame(id=1:3, city=c('NYC','LA','Chicago'))
dfs <- list(base_df, scores, grades, city)
reduce(dfs, left_join, by='id')accumulate() — 中間結果を保持する
accumulate(.x, .f)はreduce()に似ていますが、すべての中間値を保持します。入力と同じ長さのベクトル(またはリスト)を返し、各ステップ後の累積結果を示します。
library(purrr)
# Running sum — same as cumsum() but via accumulate
values <- c(100, 120, 95, 140, 160)
accumulate(values, `+`)
# Running maximum
accumulate(c(50, 52, 48, 55, 53, 58), max)accumulate()による段階的な結果
accumulate()は、アルゴリズムの各ステップを追跡したり、文字列を1文字ずつ組み立てたり、最終結果だけでなくすべての中間状態を確認したい処理に特に便利です。
library(purrr)
# Compound interest step by step
principal <- 1000
rates <- c(0.05, 0.05, 0.05, 0.05, 0.05) # 5% per year
accumulate(rates, function(balance, rate) {
round(balance * (1 + rate), 2)
}, .init = principal)walk() — 戻り値を使わず副作用を実行する
walk(.x, .f)は、印刷、ファイルへの書き込み、メッセージの送信などの副作用だけを目的として、.xの各要素に.fを適用します。.xを不可視で返すため、チェーンを中断せずにパイプラインで使用できます。
library(purrr)
# Print a summary for each dataset
datasets <- list(
mtcars = mtcars[,1:3],
iris = iris[,1:3]
)
walk(datasets, function(df) {
cat('Rows:', nrow(df), '| Cols:', ncol(df),
'| NAs:', sum(is.na(df)), '\n')
})パイプラインでwalk()を使う
walk()は.xを不可視で返すため、流れを中断せずに中間結果をログ出力または表示する目的で、dplyrのパイプラインに挿入できます。デバッグやログ出力のためのタップとして考えるとよいでしょう。
library(purrr)
library(dplyr)
results <- list(
East = data.frame(rep=c('A','B'), sales=c(100,120)),
West = data.frame(rep=c('C','D'), sales=c(200,190))
)
# Log each region's data, then continue processing
region_totals <- results %>%
walk(~cat('Processing:', nrow(.x), 'rows\n')) %>%
map_dbl(~sum(.x$sales))
print(region_totals)walk2() — 2つの入力に対する副作用
walk2(.x, .y, .f)は、walk()の2入力版です。典型的な用途は、複数のデータフレームをファイルに書き出すことです。この場合、.xはデータフレームのリスト、.yはファイルパスのリストです。
library(purrr)
data_list <- list(
east = data.frame(x=1:3, y=4:6),
west = data.frame(x=7:9, y=10:12)
)
file_paths <- list(
'/tmp/east_data.csv',
'/tmp/west_data.csv'
)
# Write each data frame to its corresponding path
walk2(data_list, file_paths, function(df, path) {
write.csv(df, path, row.names=FALSE)
cat('Written:', path, '\n')
})iwalk() — インデックス付きのwalk
iwalk(.x, .f)はwalk()に似ていますが、要素名(またはインデックス)を2つ目の引数.yとして渡します。副作用を実行する要素がどれかを把握する必要がある場合に便利です。
library(purrr)
region_counts <- list(East=150, West=200, North=85, South=120)
# Print each region with its rank
iwalk(region_counts, function(count, name) {
cat(name, ':', count, 'customers\n')
})reduce_right() — 右から左への縮約
reduce(.x, .f, .dir='backward')(または非推奨のreduce_right())は、右から左に関数を適用します。結果はf(a, f(b, f(c, d)))のようになります。これは、減算や文字列の組み立てなど、可換でない演算で重要です。
library(purrr)
words <- c('fox','brown','quick','The')
# Left-to-right: 'The quick brown fox'
reduce(rev(words), paste)
# Right-to-left: same effect but starting from right
reduce(words, function(a, b) paste(b, a))理解度チェック
map()ではなくwalk()を使うのはどのような場合ですか?
まとめ:reduce、accumulate、walk
reduce、accumulate、walkの要点:
reduce(.x, .f)— リストを左から右へ1つの値に畳み込みます。.initで開始値を設定しますreduce(list_of_dfs, left_join)— joinを連結する強力なパターンですaccumulate(.x, .f)— reduceに似ていますが、すべての中間結果を返しますwalk(.x, .f)— 副作用(表示、書き込み、ログ出力)のために適用し、.xを返しますwalk2(.x, .y, .f)— 2入力版のwalkです(例:データフレームとファイルパス)iwalk(.x, .f)— 要素名を2つ目の引数として渡すwalkです
library(purrr)
library(dplyr)
# reduce() joins a list of data frames, accumulate() shows interim states
monthly_sums <- c(100, 120, 95, 140, 160, 130)
cat('reduce (total): ', reduce(monthly_sums, `+`), '\n')
cat('accumulate (running):', accumulate(monthly_sums, `+`), '\n')
# walk() for side-effect logging
results <- list(a=42, b=17, c=89)
walk(results, ~cat('Value:', .x, '\n'))よくある質問
「reduce()、accumulate()、walk()」レッスンは無料ですか?
はい。「reduce()、accumulate()、walk()」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、R Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 R Academyコースには全4レッスンが含まれています。
「reduce()、accumulate()、walk()」で何を学びますか?
リストを畳み込み、累積結果を作成し、walk()で副作用を適用します。 ブラウザで直接実行するハンズオンコードでR Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
R Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのR Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「reduce()、accumulate()、walk()」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このR Academyレッスンでコードを書いて実行できますか?
はい。すべてのR Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- map()と型付きバリエーション
- 複数の入力に対応するmap2()とpmap()
- reduce()、accumulate()、walk()
- keep()、discard()、リストのフィルタリング