R Academy · レッスン

keep()、discard()、リストのフィルタリング

述語関数でリスト要素をフィルタリングし、すっきりしたパイプラインを作ります。

レッスン 4/413 ステップ

「keep()、discard()、リストのフィルタリング」はCoddyKit上の無料R Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはR Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 R Academyコースには全4レッスンが含まれています。

purrrでリストをフィルタリングする

purrrには、述語に基づいてリストをフィルタリング、検索、テストする関数群があります。述語とは、TRUEまたはFALSEを返す関数です。これらの関数を使うと、冗長なFilter()の呼び出しや条件付きループを置き換えられます。

library(purrr)

# A mixed list to filter
mixed <- list(1L, 'hello', 3.14, NULL, TRUE, 42L, 'world', NULL)

cat('Total elements:', length(mixed), '\n')
cat('Non-NULL elements:', length(compact(mixed)))

keep() — 述語に一致する要素を残す

keep(.x, .p)は、述語.pがTRUEを返す.xの要素だけを残します。discard()とは反対の動作です。述語には、関数名、数式、論理ベクトルを指定できます。

library(purrr)

mixed <- list(1L, 'hello', 3.14, TRUE, 42L, 'world', 2.7)

# Keep only numeric values
numeric_only <- keep(mixed, is.numeric)
print(numeric_only)

# Keep values greater than 5
keep(mixed, ~is.numeric(.x) && .x > 5)

discard() — 述語に一致する要素を削除する

discard(.x, .p)は、述語がTRUEを返す要素を削除し、それ以外を残します。keep()と対になる関数です。リストからNULL、NA、不要な型を除外する場合に使用します。

library(purrr)

results <- list(
  model_a = list(rmse=2.5, converged=TRUE),
  model_b = list(rmse=NA, converged=FALSE),
  model_c = list(rmse=1.8, converged=TRUE),
  model_d = list(rmse=NA, converged=FALSE)
)

# Discard models that did not converge
converged_models <- discard(results, ~!.x$converged)
map_dbl(converged_models, ~.x$rmse)

compact() — NULL要素を削除する

compact(.x)は、リストからすべてのNULL要素を削除します。discard(.x, is.null)と同等ですが、より簡潔に記述できます。一部の入力に対してNULLを返す可能性があるmap()呼び出しの後に特に便利です。

library(purrr)

# Simulate fetching data that might return NULL
ids <- 1:6
fetch_data <- function(id) {
  if (id %% 2 == 0) NULL else list(id=id, value=id*10)
}

raw_results <- map(ids, fetch_data)
cat('With NULLs:', length(raw_results), '\n')

clean_results <- compact(raw_results)
cat('Without NULLs:', length(clean_results))

detect() — 最初の一致を見つける

detect(.x, .p)は、述語を満たす最初の要素を返します。一致する要素がない場合はNULLを返します。detect(.right=TRUE)を使うと右から検索し、最後に一致する要素を見つけられます。

library(purrr)

prices <- list(15.99, 8.50, 23.99, 5.25, 19.99, 4.75)

# Find first price under $10
first_cheap <- detect(prices, ~.x < 10)
cat('First price under $10:', first_cheap, '\n')

# Find last price under $10
last_cheap <- detect(prices, ~.x < 10, .right=TRUE)
cat('Last price under $10:', last_cheap)

detect_index() — 最初の一致の位置を見つける

detect_index(.x, .p)は、述語を満たす最初の要素のインデックスを返します(見つからない場合は0L)。値ではなく位置が必要な場合に便利です。たとえば、その要素を更新または抽出するときに使います。

library(purrr)

models <- list(
  list(name='lm', rmse=3.5),
  list(name='rf', rmse=2.1),
  list(name='xgb', rmse=1.8),
  list(name='svm', rmse=2.4)
)

# Find the index of the best model (lowest RMSE)
best_idx <- detect_index(models, function(m) m$rmse < 2.0)
cat('Best model index:', best_idx, '\n')
cat('Best model name:', models[[best_idx]]$name)

every() — すべての要素が一致するか

every(.x, .p)は、すべての要素で述語が満たされる場合にTRUEを返します。最初にFALSEになった時点で評価を短絡します。all(map_lgl(.x, .p))と同等ですが、遅延評価されます。

library(purrr)

batch_results <- list(
  list(status='success', rows=150),
  list(status='success', rows=200),
  list(status='success', rows=175)
)

failed_batch <- list(
  list(status='success', rows=150),
  list(status='error', rows=0),
  list(status='success', rows=175)
)

cat('All success (good):', every(batch_results, ~.x$status == 'success'), '\n')
cat('All success (bad):', every(failed_batch, ~.x$status == 'success'))

some() — いずれかの要素が一致するか

some(.x, .p)は、述語を満たす要素が少なくとも1つある場合にTRUEを返します。最初にTRUEになった時点で評価を短絡します。any(map_lgl(.x, .p))と同等ですが、遅延評価されます。

library(purrr)

datasets <- list(
  data.frame(x=1:3, y=c(1,NA,3)),
  data.frame(x=4:6, y=7:9),
  data.frame(x=7:9, y=c(NA,NA,NA))
)

# Does any dataset contain NAs?
cat('Any NAs:', some(datasets, anyNA), '\n')

# Is every dataset NA-free?
cat('All clean:', every(datasets, ~!anyNA(.x)))

none() — 一致する要素がないか

none(.x, .p)は、述語を満たす要素がない場合にTRUEを返します。!some(.x, .p)と同等ですが、条件が存在しないことを検証する場面では、こちらの方が意図を明確に表現できます。

library(purrr)

api_responses <- list(
  list(code=200, data='OK'),
  list(code=200, data='OK'),
  list(code=201, data='Created')
)

# Ensure no errors occurred
no_errors <- none(api_responses, ~.x$code >= 400)
cat('No errors:', no_errors, '\n')

# Check another batch
bad_batch <- c(api_responses, list(list(code=500, data='Error')))
none(bad_batch, ~.x$code >= 400)

keep() と map() の組み合わせ

keep()(またはdiscard())とmap()をチェーンするのは、よく使われるパターンです。まずリストを関係のある要素に絞り込み、その後で変換を適用します。これにより、フィルタリングのロジックと処理のロジックをきれいに分離できます。

library(purrr)

model_results <- list(
  list(name='A', converged=TRUE, rmse=2.5),
  list(name='B', converged=FALSE, rmse=NA),
  list(name='C', converged=TRUE, rmse=1.8),
  list(name='D', converged=TRUE, rmse=3.1)
)

# Keep converged, extract RMSE
model_results %>%
  keep(~.x$converged) %>%
  map_dbl(~.x$rmse)

keep() と is.* 関数の使用

R組み込みのis.*述語関数(is.numeric、is.character、is.null、is.na、is.finite)は、~でラップしなくても、keep()やdiscard()の述語として直接使用できます。

library(purrr)

mixed_env <- list(
  count = 42L,
  name = 'Alice',
  ratio = 3.14,
  flag = TRUE,
  missing = NULL,
  data = data.frame(x=1:3)
)

# Extract different types
numeric_items <- keep(mixed_env, is.numeric)
cat('Numeric items:', length(numeric_items), '\n')

# Remove NULL items
cleaned <- discard(mixed_env, is.null)
cat('After removing NULL:', length(cleaned))

確認問題

.xのどの要素も述語.pを満たさない場合、detect(.x, .p)は何を返しますか?

まとめ:リストのフィルタリング関数

purrrのリストフィルタリングツールの要点:

  • keep(.x, .p) — 述語がTRUEになる要素を残します
  • discard(.x, .p) — 述語がTRUEになる要素を削除します
  • compact(.x) — すべてのNULL要素を削除します
  • detect(.x, .p) — 述語に一致する最初の要素を返します(またはNULL)
  • detect_index(.x, .p) — 最初に一致する要素のインデックスを返します(または0L)
  • every(.x, .p) — すべての要素が一致する場合にTRUEを返します
  • some(.x, .p) — いずれかの要素が一致する場合にTRUEを返します
  • none(.x, .p) — どの要素も一致しない場合にTRUEを返します
library(purrr)

scores <- list(45, 72, 88, 53, 91, 67, 39, 85)

passing <- keep(scores, ~.x >= 60)
failing <- discard(scores, ~.x >= 60)

cat('Passing:', length(passing), 'students\n')
cat('Failing:', length(failing), 'students\n')
cat('All pass:', every(scores, ~.x >= 60), '\n')
cat('Any fail:', some(scores, ~.x < 60), '\n')
cat('First pass score:', detect(scores, ~.x >= 60))
無料で開始

AI チューターと学ぶ R — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
43
レッスン
159

よくある質問

「keep()、discard()、リストのフィルタリング」レッスンは無料ですか?

はい。「keep()、discard()、リストのフィルタリング」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、R Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 R Academyコースには全4レッスンが含まれています。

「keep()、discard()、リストのフィルタリング」で何を学びますか?

述語関数でリスト要素をフィルタリングし、すっきりしたパイプラインを作ります。 ブラウザで直接実行するハンズオンコードでR Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

R Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのR Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「keep()、discard()、リストのフィルタリング」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このR Academyレッスンでコードを書いて実行できますか?

はい。すべてのR Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. map()と型付きバリエーション
  2. 複数の入力に対応するmap2()とpmap()
  3. reduce()、accumulate()、walk()
  4. keep()、discard()、リストのフィルタリング
← R Academyに戻る