【R】case_match()でデータフレームの中身を置き換える

dplyrのcase_match()関数を使ったデータ置き換えの方法を、実務で使える例とともに解説します。

R
データ処理
公開

2025年11月24日

はじめに

この記事では、dplyrパッケージのcase_match()関数を使ったデータの置き換え方法について解説します。

以前「recode関数でデータフレームの中身を置き換える」という記事でrecode()関数を紹介しましたが、現在recode()はsuperseded(推奨されない・代替がある)となっています。そこで、より効率的な書き方としてcase_match()関数の使い方をまとめます。

dplyr::case_match()の基本

library(tidyverse)

df <- tibble(
  x = c(1, 2, 3, 4, 5)
)

print(df)
# A tibble: 5 × 1
      x
  <dbl>
1     1
2     2
3     3
4     4
5     5

case_match()関数は、指定した列の値に基づいて新しい値を割り当てることができます。

例えば、x列の値が1, 2, 3の場合は”A”、4, 5の場合は”B”という新しい列yを作成する場合、以下のように書きます。

df <- df |>
  mutate(
    y = case_match(x, c(1, 2, 3) ~ "A", c(4, 5) ~ "B")
  )

print(df)
# A tibble: 5 × 2
      x y    
  <dbl> <chr>
1     1 A    
2     2 A    
3     3 A    
4     4 B    
5     5 B    

似たような関数にcase_when()がありますが、case_when()は複数の条件式を評価して条件に応じた値を返すのに対して、case_match()は1つの変数に着目したうえで値を置き換えるという働きをします。

例:文字列の置き換え(都道府県コードから地域名へ)

実務ではよく、コードを人間が読みやすい形に変換することがあります。

# 都道府県コードから地方名へ変換
prefecture_df <- tibble(
  pref_code = c("01", "13", "27", "40", "47")
)

prefecture_df <- prefecture_df |>
  mutate(
    region = case_match(
      pref_code,
      "01" ~ "北海道",
      c("02", "03", "04", "05", "06", "07") ~ "東北",
      c("08", "09", "10", "11", "12", "13", "14") ~ "関東",
      c("21", "22", "23", "24", "25", "26", "27", "28", "29", "30") ~ "近畿",
      c("40", "41", "42", "43", "44", "45", "46", "47") ~ "九州・沖縄",
      .default = "その他"
    )
  )

print(prefecture_df)
# A tibble: 5 × 2
  pref_code region    
  <chr>     <chr>     
1 01        北海道    
2 13        関東      
3 27        近畿      
4 40        九州・沖縄
5 47        九州・沖縄

.default引数を使うことで、マッチしなかった値にデフォルト値を割り当てることができます。

名前付きベクトルを使った方法

マッピングルールが複雑な場合や再利用したい場合は、あらかじめ名前付きベクトルを定義しておくと便利です。

ただ、この場合は以前紹介したようなdplyr::recode()ではなく、今回のcase_match()でもなく、名前付きベクトルを[]でインデックス参照する方法で解決できます。

# 商品カテゴリコードから日本語名へのマッピングを定義
category_mapping <- c(
  "A" = "食品",
  "B" = "衣料品",
  "C" = "家電",
  "D" = "書籍",
  "E" = "その他"
)

product_df <- tibble(
  product_id = 1:6,
  category_code = c("A", "B", "C", "A", "D", "F")
)

# 方法1: 名前付きベクトルを使ってインデックス参照
product_df <- product_df |>
  mutate(
    category_name = category_mapping[category_code],
    category_name = if_else(is.na(category_name), "未分類", category_name)
  )

print(product_df)
# A tibble: 6 × 3
  product_id category_code category_name
       <int> <chr>         <chr>        
1          1 A             食品         
2          2 B             衣料品       
3          3 C             家電         
4          4 A             食品         
5          5 D             書籍         
6          6 F             未分類       

意外にも簡単でした。

名前付きベクトルを[]でインデックス参照することで、キーから値への変換が簡潔に書けます。マッチしない値はNAになるため、if_else()でデフォルト値を設定します1。この方法は、マッピングルールが多い場合や、複数の場所で同じマッピングを使いたい場合に特に有効です。

逆引きマッピング

今度は同じcategory_mappingを使って、カテゴリ名からカテゴリコードへの逆引きマッピングを行う方法についてまとめます。

# 逆引きマッピング用の名前付きベクトルを作成
reverse_mapping <- setNames(names(category_mapping), category_mapping)

df <- tibble(
  category_name = c("食品", "家電", "書籍", "未分類")
)

df <- df |>
  mutate(
    category_code = reverse_mapping[category_name],
    category_code = if_else(is.na(category_code), "不明", category_code)
  )

print(df)
# A tibble: 4 × 2
  category_name category_code
  <chr>         <chr>        
1 食品          A            
2 家電          C            
3 書籍          D            
4 未分類        不明         

ここではsetNames()関数を使って、元のcategory_mappingの名前と値を入れ替えた新しい名前付きベクトルreverse_mappingを作成しています。

その後、同様に[]でインデックス参照を使ってカテゴリ名からカテゴリコードへの変換を行い、マッチしない場合はif_else()でデフォルト値を設定しています2

setNames()関数は、ベクトルに名前を付けるための関数です。以下のように使います。

x <- 1:3
setNames(x, c("a", "b", "c"))
a b c 
1 2 3 
# 結果:
#  a b c
#  1 2 3

この例では、数値ベクトルxに対して、名前ベクトルc("a", "b", "c")を使って名前を付けています。結果として、xの各要素に対応する名前が付与されます。

さらに今回のようにnames()ではA, B, Cなどの名前を取得し、それに対応する値を逆に設定する3ことで、逆引きマッピング用の名前付きベクトルを作成できます。

特に長いマッピングルールを扱う場合に、また1から名前付きベクトルを作成しなくてよくなるため便利だと思います。

おわりに

この記事では、dplyr::case_match()を使ったデータの置き換え方法について解説しました。

case_match()は単一の列の値を置き換える際に直感的で読みやすいコードが書けます。また、名前付きベクトルを使ったインデックス参照を組み合わせることで、複雑なマッピングルールも効率的に管理できます。

データクリーニングや前処理の際にぜひ活用してみてください。

  1. 全部マッチすることがわかっているなら2行目は要りません。↩︎

  2. ここも同様に全部マッチすることがわかっているなら2行目は要りません。↩︎

  3. ここもややこしい点ですが、category_mappingはA→食品、B→衣料品のように対応関係が含まれているものの、値は”食品”や”衣料品”の方に該当します。データフレームのような感じで、“A”や”B”は列名、“食品”や”衣料品”は値、というイメージを持っていただければと思います。↩︎