Ma.03.「前処理」等復習用(Tidyverse的)

このページは、演習で活用した前処理に必要なRのTIPS(技)をまとめました。
分析のワークフローに沿って、各ステップの「目的」と「コピーして使えるコード」を紹介しています。
演習で使った資料を参考に生成AIの助けを得ながら公開しました。

1. 【準備】分析環境のセットアップ

分析を始める前の「おまじない」です。過去の作業内容をクリアにし、必要な道具(パッケージ)を読み込みます。

目的

  • 過去に実行した変数(オブジェクト)をRのメモリからすべて削除し、クリーンな状態で作業を開始する。
  • tidyverse をはじめとする、データハンドリングや可視化に必要なパッケージを読み込む。

コピー用コード

# --- 環境のリセット --- 警告:現在Rのメモリ上にあるものがすべて消えます
rm(list=ls())

# --- 基本パッケージの読み込み ---
library(tidyverse) 
library(readxl) #エクセルを読み込む
library(summarytools) # データの要約(記述統計)を素早く確認する


library(janitor) # 必要時のみ、変数名を自動でクリーンにするため (例: "Q1. 氏名" -> "q1_shimei")

library(naniar) # 必要時のみ、欠損値(NA)を視覚化するため


# --- RStudioのTIPS:セクション管理 ---

# 【 Ctrl + Shift + R  】で、目次作成&スクリプトを折り畳める
# 【 Ctrl + Shift + C  】で、スクリプト内のコメントをコメント化

2. 【読込】データのインポートと「健康診断」

データをRに読み込み、その「第一印象」と構造を確認します。

目的

  • ExcelやCSVなどのファイルをRのデータフレーム(df)として正しく読み込む。
  • データが期待通りに読み込めているか(文字化け、型の違いなど)を素早く確認する。
  • Rで扱いにくい変数名(日本語、スペース、記号など)を、扱いやすい形式に自動変換する。

コピー用コード

# --- Excelファイルの読み込み ---(基本はReadrを"右上"から扱うことを推奨しています)
# ※パス(/data/...)やシート名(YYYY)、スキップ行数(AA)は適宜変更
df <- read_excel("/data/XXXXXXXXX.xls", 
                 sheet = "YYYY",     # シート名を指定
                 skip = 10,          # 最初の10行を読み飛ばす
                 col_names = TRUE)   # 読み込んだ範囲の1行目を変数名とする

# --- データの「第一印象」を確認 ---
head(df) # 最初の6行を表示
tail(df) # 最後の6行を表示

# --- データの「構造(型)」を確認 ---
glimpse(df) # 変数名、型、値の例を一覧

# --- 変数名をクリーンにする (janitor) ---
df_clean <- clean_names(df)

# --- 難解な変数名を一覧表示(コピー用) ---
# 変数名が長い、日本語で入力が面倒なときは、names() で一覧を表示し、コンソールから変数名をコピーして使います
names(df) 

3. 【把握】欠損値(NA)の確認

本格的な前処理の前に、データの「クセ」(特に欠損値)を掴みます。

目的

  • データ全体にどの程度欠損値(NA)があるかを視覚的に把握する。
  • 「欠損値が特に多い回答者(行)」や「欠損値が特に多い質問項目(列)」を特定する。

コピー用コード

# --- 欠損値の視覚化 (naniar) ---
# データが巨大な場合、vis_miss() は時間がかかるため、
# 5%程度をランダムサンプリングして傾向を掴みます
df_sample <- df %>% 
  slice_sample(prop = 0.05)

vis_miss(df_sample)

# --- 欠損値の多い「回答者(行)」を特定 ---
# pct_miss(欠損率)が高い順に並べ替えて上位を表示
miss_case_summary(df) %>% 
  arrange(desc(pct_miss)) %>% 
  head()

4. 【処理】データの前処理と変数作成

分析の目的に合わせてデータを加工する、最も重要なステップです。dplyr パッケージの mutate() 関数が主役です。

A. 値の変換と欠損値処理

回答の選択肢(例: 1=そう思う, 2=そう思わない)を、分析しやすい数値(例: 1, 0)に変換したり、特定の回答(例: 8=わからない)を欠損値(NA)として扱ったりします。

# --- 1. 単純な計算 (例: 1〜5点 -> 0〜4点に) ---
df_new <- df %>% 
  mutate(q1_1 = q1_1 - 1)

# --- 2. 複数の変数を一括変換 (across) ---
# "q3s" から始まるすべての変数(q3s1, q3s2...)を対象に、一括で「-1」する
df_new <- df %>% 
  mutate(across(starts_with("q3s"),
                ~ .x - 1)) # .x は「その変数自身」を指す

# --- 3. 逆転項目の処理 (across) ---
# 5点満点(1〜5)の項目を逆転させる & 0に意味をもたせる(5点→0点にしたい & 1点→4点にしたい )
# (逆転の処理は、ほぼ、【最大値+1 -.x】だと思いますが、今回みたいに違うケースもあります)
# ので、今回は・・・と毎回考える、(今回:最大 - 元の値 → 5 - .x)
df_new <- df %>% 
  mutate(across(starts_with("q40s"),
                ~ 5 - .x))

# --- 4. 特定の値を欠損値(NA)に変換 (na_if) ---
# 質問項目n_q36で「8 = わからない」と回答した人を NA にする
df_new <- df %>%
  mutate(n_q36 = na_if(n_q36, 8))

B. 新しい変数の作成(合計点など)

複数の質問項目を足し合わせて、合計点(尺度得点)などを作ります。

# --- 合計点の作成 (rowSums + across) ---
# "q3s" から始まるすべての変数の「行ごと(row)」の合計(Sums)を計算し、
# 新しい変数 `q3` を作成する
# na.rm = TRUE は、計算途中にNAがあってもそれを除外して合計するオプション
df_new <- df %>% 
  mutate(q3 = rowSums(across(starts_with("q3s")), na.rm = TRUE))

C. 型の変換 (as.numeric)

数値として扱いたい変数が、文字型 (character) になっている場合に修正します。

# 'work' 変数を強制的に数値型(numeric)に変換
df_new <- df %>% 
  mutate(work = as.numeric(q15s1))

D. カテゴリ変数の作成 (Factor化)

分析(特に ggplotaov)で必須の作業です。数値(1, 2)に「男性, 女性」といったラベルを付けたり、順序を持たせたりします。

# --- 1. 単純なFactor化 (factor) ---
# sex変数の「1」に "male"、「2」に "female" というラベルを付ける
df_new <- df %>% 
  mutate(sex = factor(sex,
                    levels = c(1, 2),
                    labels = c("male", "female")))

# --- 2. 順序付きFactor化 (ordered) ---
# nensyu変数(1〜7)が「順序」を持つこと(1 < 2 < ... < 7)をRに教える
df_new <- df %>% 
  mutate(nensyu = ordered(n_q36,
                        levels = 1:7)) # 1:7 は c(1,2,3,4,5,6,7) と同じ

E. 条件分岐による変数作成 (if_else, case_when)

最もよく使う「技」です。ある条件に基づいて新しい変数を作成します。

# --- 2分岐 (if_else) ---
# 「もし kessler6 が 13以上 なら 1 を、 そうでなければ 0 を」
# 新しい変数 k6_h (high群) を作成
df_new <- df %>%
  mutate(k6_h = if_else(kessler6 >= 13, 1, 0))

# --- 2分岐 + Factor化 (if_else + factor) ---
# if_else で 0/1 に分けた後、すぐに factor() でラベル付けするコンボ技
df_new <- df %>%
  mutate(
    k6_h = if_else(kessler6 >= 13, 1, 0),
    k6_hf = factor(k6_h,
                   levels = c(0, 1),
                   labels = c("low", "high"))
  )

# ---  多分岐 (case_when) ---
# 複数の「もし〜なら」を上から順に判定する
# 「条件式 ~ 結果」 のペアで書く
df_new <- df %>%
  mutate(
    age_g = case_when(
      age_num >= 65 ~ 3,      # 65歳以上なら 3
      age_num >= 40 ~ 2,      # (65歳未満で) 40歳以上なら 2
      age_num <= 39 ~ 1,      # (40歳未満で) 39歳以下なら 1
      TRUE ~ NA_real_         # 上記すべてに当てはまらない場合 (念のため)
    ),
    age_g = factor(age_g,     # その変数ごとFactor化
                   levels = c(1, 2, 3),
                   labels = c("若年層", "中年層", "高齢層")) 
  )

# ---  多分岐 + %in% (case_when) ---
# %in% は「c(...) のどれかに当てはまるなら」という便利な記法
df_new <- df %>%
  mutate(
    work = as.numeric(q15s1), # 先に数値化
    job_group = case_when(
      work %in% c(1, 3, 4) ~ 1, # 正規・役員・自営
      work %in% c(2, 5)    ~ 2, # 非正規・パート
      work %in% c(6, 7)    ~ 3, # 学生・専業主婦
      work %in% c(8, 9)    ~ 4, # 無職・その他
      TRUE ~ NA_real_
    ),
    job_group = factor(job_group,
                       levels = c(1, 2, 3, 4),
                       labels = c("正規", "非正規", "学生主婦", "無職"))
  )

F. 変数名の変更と選択 rename & select

扱いにくい変数名を変更したり、特定の変数群だけを抜き出したりします。

# --- 1. 変数名の変更 (rename) ---
# rename(新しい名前 = "古い名前")
# ※ `dplyr::rename` と明記すると他パッケージとの衝突を防げます
df_new <- df %>% 
  dplyr::rename(jisatu = 'I910803_自殺率(人口10万対)【‐】')
df_new <- df_new %>% 
  dplyr::rename(area_code = `地域コード`) # ` ` で囲む

# --- 特定の変数群を文字列で作成 (paste0) ---
# "q3s1_1", "q3s2_1", ..., "q3s11_1" という変数名のリストを自動作成
vars <- paste0("q3s", 1:11, "_1")

# --- 上で 作成したリストで変数を抽出 (select + all_of) ---
# vars リストに含まれる変数「すべて(all_of)」を抜き出した新dfを作成
df_selected <- df %>%
  select(all_of(vars))

G. 行のフィルタリング (filter)

分析に不要な行(例: 全国平均の行)を除外します。

# --- 特定の条件で行を絞り込む (filter) ---
# area_code が "R00000"(全国平均)「ではない」行だけを残す
※ dplyr::filter と明記しているのは、僕のR環境ではdplyrを明示しないと働いてくれないからです。(原因模索中)
df_filtered <- df %>% 
  dplyr::filter(area_code != "R00000")

H. 行・列の削除 (逆filter、逆Select、逆Slice)

Gと同様ではありますが、「これを選ぶ」よりも、「これ以外を選ぶ」方が効率的な場面がよくあります。

1. 逆セレクト (特定の列を「除く」)

select() で変数(列)名の前に - (マイナス記号) を付けると、その列以外をすべて選択できます。
分析に使わないID列や自由記述欄など、特定の列だけを一時的に除外したい。

# --- 1. 特定の1列を除く ---
# 'free_comment' 列「以外」をすべて選択
df_new <- df %>% 
  select( - free_comment)

# --- 2. 複数の列を除く ---
# 'id' と 'timestamp' の2列「以外」をすべて選択
df_new <- df %>% 
  select(-c(id, timestamp))

# --- 3. 条件で除く (starts_withなど) ---
# "q3s" から始まるすべての変数「以外」を選択
# ※ヘルパー関数の場合は `!` を使う
df_new <- df %>% 
  select(!starts_with("q3s"))

2. 逆フィルター (特定の行を「除く」)

filter() で条件式の全体を !() で囲むか、判定の前に ! を付けると、その条件に当てはまらない行(=それ以外)を抽出できる。
特定の条件(例: NA、特定のグループ、外れ値)に当てはまる行以外を抽出するときに利用できます。

# --- 1. 特定の値「以外」 ( != と同じ) ---
# area_code が "R00000"(全国平均)「ではない」行
# これは filter(area_code != "R00000") と全く同じ意味
df_filtered <- df %>% 
  dplyr::filter(!(area_code == "R00000"))

# --- 2. NA「以外」を抽出 (is.na) ---
# 'income' が NA「ではない」行だけを残す(=欠損値の完全除外)
df_complete <- df %>%
  dplyr::filter(!is.na(income))
  
# --- 3. グループ「以外」を抽出 (%in%) ---
# 'age_g' が c(1, 3)(若年層と高齢層)「ではない」行(=中年層のみ)を抽出
# %in% の前に ! を付ける
df_middle_age <- df %>%
  dplyr::filter(!age_g %in% c(1, 3))

3. 逆スライス (特定の行番号を「除く」)

slice()で行番号の前に-(マイナス)を付けると、その行番号以外をすべて選択できる。
データの先頭X行(例: 注釈やヘッダーが誤って含まれた行)だけを除外したい。
データの最後の行(例: 合計行など)を除外したい。ときに活用できます。

# --- 1. 最初の5行「以外」をすべて選択 ---
# -c(1:5) は「1行目から5行目まで」を「除く」という意味
df_new <- df %>% 
  slice(-c(1:5))

# --- 2. 特定の1行を除く ---
# 3行目だけを除外
df_new <- df %>% 
  slice(-3)

# --- 3. 最後の1行を除く ---
# n() は「総行数」(つまり最後の行)を指す
df_new <- df %>% 
  slice(-n())

5. 【結合】複数データのマージと集計

複数のデータフレーム(例: 個人データと、都道府県データ)を結合(マージ)したり、グループごと(例: 県ごと)に集計したりします。

A. データの結合 (left_join)

left_join(df_A, df_B, by = "キー変数") は、「df_A(左側)を基準にして、df_B(右側)からキー変数が一致する行の情報をくっつける」という意味です。

# --- 準備:結合される側(jisatu)のキー変数を準備 ---
# 例: `地域コード` (01000) から `tiiki` (01) を作成
jisatu_df <- jisatu_df %>% 
  mutate(tiiki = as.numeric(`地域コード`) * 0.001)

# --- 1. 基本的な結合 (left_join) ---
# ssdse (基準) に jisatu_df (加える) を "tiiki" をキーにして結合
join_df <- left_join(ssdse, jisatu_df,
                     by = "tiiki",
                     suffix = c("_x", "_y")) # 同名変数があった場合の接尾辞

# --- 2. 必要な変数だけ選んで結合 (TIPS) ---
# Bのdf(tfr_df)から必要な変数(tfr, tfr_f)だけをAのdf(naiman)に結合する
# (1) Bのdfから必要な変数だけ抜き出す
tfr_selected <- join_df %>% 
  dplyr::select(tfr, tiiki)

# (2) Aのdfに (1) を結合する
naiman_ketsugo <- left_join(naiman, tfr_selected,
                            by = "tiiki")

B. グループごとの集計 (group_by + summarize)

個人(行)のデータを、特定のグループ(例: 都道府県)ごとに集計し、新しいデータフレームを作成します。

# --- グループ集計 (group_by + summarize) ---
# (1) dfを `pref_name`(都道府県名)でグループ化
# (2) 新しい変数として、incomeの平均値、q3の平均値、N(人数)を計算
df_summary <- df %>%  
  group_by(pref_name) %>% 
  summarise( 
    mean_income = mean(income, na.rm = TRUE), # NAを除外して計算
    mean_q3 = mean(q3, na.rm = TRUE),
    N = n() 
  )

6. 【保存】中間データの保存

時間のかかった前処理の結果を保存し、いつでも作業を再開できるようにします。

目的

  • 前処理済みのクリーンなデータ(df_newなど)をファイルに保存する。
  • 次回以降、read_excel や前処理のステップをすべて飛ばし、分析用データを瞬時に読み込む。

コピー用コード

# --- R専用形式 (.rds) で保存 ---
# .rds は .csv と違い、Factorのラベル情報などもそのまま保存できるため推奨
write_rds(df_new, file = "preprocessed_data.rds")

# --- 保存した .rds ファイルを読み込む ---
# 次回作業時は、この1行だけで前処理済みのデータを読み込める
rm(list=ls()) # 念のため環境をクリアにしてから
df_analysis <- read_rds("preprocessed_data.rds")

次の記事

Ma.04.ggplot2 グラフ作成 復習