データの前処理

使う列と値の意味を確認し、逆転項目やダミー変数を作る。欠測を含む例で処理前後の人数を確かめる
公開

2026-09-26

最終更新

2026-10-05

1 目的

このページでは、データの前処理を練習します。データの前処理とは、分析の目的に合わせてデータを整える作業です。成人1,000人の生活や仕事についての架空の回答を使い、次の4つの作業を行います。

  • 分析に使う質問の列を選ぶ。
  • 範囲外の値や欠測(回答が記録されていない箇所)を含む行を除く。
  • 逆転項目(他の質問と意味の向きが逆になっている質問)の回答の向きをそろえる。
  • ある条件にあてはまる人を区別する変数を作る。

作業は、次の順に進めます。

  1. どの列を使い、どのような変数を作るかを決める。
  2. 決めた内容をAIに伝えて、Rコードを作ってもらう。
  3. コードを実行し、結果が決めた内容どおりかを確かめる。

最後に、欠測を含む小さな例で、どの人が分析から外れるかも確認します。

2 準備

ここでは、模擬調査データを使います。CSVとコードブックを授業用フォルダに保存してください。コードブックには、変数名、質問文、回答の選択肢が書かれています。

このページでは、tidyverseに含まれるreadrとdplyrを使います。tidyverseをまだインストールしていない場合は、RとPositronのセットアップの「パッケージの導入」で手順を確認してください。

  1. mock_survey.csvをダウンロードし、ファイル名を変えずに保存してください。
  2. Positronで授業用フォルダを開き、Rスクリプトを作成してください。操作はRとPositronのセットアップで確認できます。
  3. 次のコードをRスクリプトに書いて実行し、CSVを読み込んでください。読み込んだデータは survey に保存されます。
survey <- readr::read_csv("mock_survey.csv", show_col_types = FALSE)

続いて、行数と列数を調べる dim() を実行してください。

dim(survey)
[1] 1000   25

出力の1つ目の数字が行数、2つ目が列数です。1,000人分の回答が25列に入っています。

このCSVには欠測がありません。欠測の扱いは、第8節(欠測を含む例)で別の小さな架空データを使って練習します。

3 分析の仕様を言葉にする

どの列を選び、どの変数を作るかは、分析で何を調べたいかで決まります。ここでは、次の問いを調べる準備をする場合を考えてみましょう。

働いている人と働いていない人とで、頼れる人がいると感じる程度は違うか。

この問いに答えるには、データを次の2点で整える必要があります。

  1. 社会的サポートの回答の向きをそろえる。質問によって、点数が高いほど「頼れる人がいる」を表す場合と、「頼れる人がいない」を表す場合があります。向きが混ざったままでは、質問どうしを比べたり、平均して1つの得点にまとめたりできません。
  2. 働いているかどうかを0と1で表す。就業区分の列 employment_status には4種類の値がありますが、今回の問いでは「働いている」と「働いていない」の2グループに分けられれば十分です。回帰分析では、このような0/1の列を使って2グループの平均を比べます。

このページで行うのは、比較の準備としてデータを整えるところまでです。0/1の列を使って2つのグループの平均を比べる方法は、単回帰モデルの「2群の平均差とダミー変数」で説明しています。そのページでは別の実験データを使いますが、2つのグループを0と1で表す考え方は同じです。

取り出す列

CSVの25列のうち、問いに必要な次の4列だけを取り出します。列を絞ると、処理前後の出力を見比べやすくなります。

列名 取り出す理由
id 回答者番号。処理後の行が元データのどの人かを照合するために残す
employment_status 就業区分。0/1の列を作る元になる
support_1 社会的サポートの1番の質問。向きがそろった質問の例
support_5 社会的サポートの5番の質問。逆転項目の例

社会的サポートの質問は5つありますが、逆転処理の練習には、向きがそろった質問と逆転項目が1つずつあれば足ります。実際に社会的サポートの得点を求めるときは、コードブックのとおり5つの質問すべてを使います。

逆転項目をそろえる

support_1 と support_5 の質問文を読み比べてください。

列名 質問文
support_1 困ったときに相談に乗ってくれる人がいる。
support_5 悩みがあっても、頼れる人がいない。

どちらも1が「まったくあてはまらない」、5が「とてもよくあてはまる」です。同じ5という回答でも、2つの質問では意味が反対になります。

  • support_1 に5と答えた人は、頼れる人がいると感じています。
  • support_5 に5と答えた人は、頼れる人がいないと感じています。

support_5 のように、他の質問と意味の向きが逆になっている質問を逆転項目と呼びます。向きをそろえるには、support_5 の1、2、3、4、5を、それぞれ5、4、3、2、1に置き換えます。この処理を逆転処理と呼びます。今回は次のように処理します。

  • 6 - support_5 を計算し、点数が高いほど頼れる人がいると感じる向きにそろえる。
  • 計算結果は新しい列 support_5_r に入れ、元の support_5 も残す。

逆転処理では、1を5に、2を4に、3を3に、4を2に、5を1に置き換えます。元の回答と逆転後の値を並べると、どの組も合計が6になります。

元の回答 1 2 3 4 5
逆転後の値 5 4 3 2 1
合計 6 6 6 6 6

そのため、逆転後の値は6から元の回答を引けば求まります。6は、選択肢の最小値1と最大値5を足した数です。選択肢が変われば、引く数も変わります。

  • 1〜7の7段階なら、8から引く。
  • 0〜4の5段階なら、4から引く。

5 - support_5 と書くと、値は4〜0になります。順序は逆になりますが、他の質問の1〜5と範囲がずれるため、平均すると得点が全体に低くなります。

0/1の列を作る

ある条件にあてはまるときに1、あてはまらないときに0をとる変数を、ダミー変数と呼びます。今回は、就業区分から次の employed を作ります。

employment_status の値 employed
regular(正規雇用) 1
nonregular(非正規雇用) 1
self_employed(自営業等) 1
not_employed(非就業) 0

1と0に何を対応させるかは、変数を作る前に決めておきます。

残す行

変数を作る前に、使う回答が有効な値かも確認します。範囲外の値や欠測が混ざったまま計算すると、逆転処理や0/1の列が意味のない値になるためです。今回は、support_1 と support_5 がともに1〜5で、就業区分が上の表の4種類のいずれかである人だけを残します。

Rでは、このような条件を条件式で書きます。AIが出したコードの条件を読むときは、次の折りたたみを参照してください。

条件式は、各行について条件にあてはまれば TRUE、あてはまらなければ FALSE を返します。行を絞り込む filter() は、TRUE になった行だけを残します。

書き方 意味 例
== 等しい employment_status == "regular"
!= 等しくない item_a != 9
>=、<= 以上、以下 support_1 >= 4
>、< より大きい、より小さい support_1 > 3
%in% 右側に挙げた値のどれかにあてはまる support_1 %in% 1:5
& 両方にあてはまる support_1 >= 4 & support_5 >= 4
| どちらか一方でもあてはまる support_1 >= 4 | support_5 >= 4
! あてはまらない !(employment_status == "regular")

等しいかどうかを調べるときは、= を2つ重ねた == を使います。= が1つだけだと、関数に値を渡す書き方と区別できません。filter() の中でカンマで区切った条件は、& でつないだときと同じ意味になります。

欠測の NA には注意が必要です。== や >= で NA を調べると、結果は TRUE でも FALSE でもない NA になります。一方、%in% は NA に FALSE を返します。

x <- c(1, 9, NA)
x >= 1 & x <= 5
[1]  TRUE FALSE    NA
x %in% 1:5
[1]  TRUE FALSE FALSE

filter() は、条件式が NA になった行も残しません。このページでは、結果が TRUE か FALSE のどちらかになり読み取りやすいため、%in% を使っています。

仕様の一覧

ここまでに決めたことを表にまとめます。第4節(AIへの指示例)では、この表をもとにAIへの指示を書きます。

項目 今回の仕様
元データ survey。変更せずに残す
取り出す列 回答者番号 id、employment_status、support_1、support_5
残す行 2つの回答がともに1〜5で、就業区分が下記4種類のいずれかである行
就業区分の値 regular、nonregular、self_employed、not_employed
逆転処理 support_5_r = 6 - support_5。1〜5を5〜1に対応させる
就業の指標 employed。前の3区分なら1、not_employed なら0
保存先 新しいデータフレーム prepared。元の4列と追加した2列を残す
確認する出力 処理前後の人数、逆転前後の対応、就業区分と0/1の対応

このデータでは全員が条件を満たすので、処理後も1,000人が残るはずです。人数が減った場合は、次の2点を確かめてください。

  • AIが余分な条件を付けていないか。
  • 読み込んだデータが配布したCSVと同じか。

4 AIへの指示例

AIには、ここまでに決めた処理のRコードを書いてもらいます。CSVや回答者ごとの値は渡さず、次の内容を伝えてください。

  • 使う列と、その値の意味
  • 残す行の条件
  • 作る変数
  • 確認したい出力

「社会的サポートのデータをきれいにして」だけでは、どの列を使い、どの行を残すかが伝わりません。

ヒントAIへの指示例
RでCSVをsurveyというデータフレームに読み込み済みです。
データ本体は渡しません。次の仕様で前処理するコードを書いてください。

surveyを変更せず、id、employment_status、support_1、support_5を選んでください。
idは回答者番号です。support_1とsupport_5は数値で、有効な回答は1〜5です。
employment_statusは文字列で、regular、nonregular、self_employed、not_employedの4種類です。
2つの回答がともに1〜5で、就業区分がこの4種類に含まれる行だけを残してください。

support_5は逆転項目なので、6から引いた値をsupport_5_rに入れてください。
regular、nonregular、self_employedなら1、not_employedなら0となるemployedを作ってください。
元の列を残し、結果をpreparedという新しいデータフレームに保存してください。

処理前後の人数、support_5とsupport_5_rの対応、就業区分とemployedの対応を表示してください。
preparedのidに重複がないか、surveyにないidが含まれていないかを確認するコードも書いてください。
dplyrの関数とパイプ |> を使い、列選択・行の絞り込み・変数作成を段階に分けて説明してください。

AIが出したコードは、CSVを読み込むコードの後に貼り付け、順番に実行してください。第5節(参照コードと出力)のコードと書き方が違っても、仕様どおりに処理できていれば構いません。

5 参照コードと出力

自分で実行してから、次のコードと出力を開いて照合してください。

使う列を取り出す

selected <- survey |>
  dplyr::select(id, employment_status, support_1, support_5)

select() は列を選ぶ関数です。ここでは survey から4列を取り出し、selected に保存しています。|> は、左側のデータを右側の関数に渡すパイプです。

値と人数を確認する

selected |> dplyr::count(support_1)
# A tibble: 5 × 2
  support_1     n
      <dbl> <int>
1         1   112
2         2   241
3         3   317
4         4   230
5         5   100
selected |> dplyr::count(support_5)
# A tibble: 5 × 2
  support_5     n
      <dbl> <int>
1         1   111
2         2   215
3         3   320
4         4   238
5         5   116
selected |> dplyr::count(employment_status)
# A tibble: 4 × 2
  employment_status     n
  <chr>             <int>
1 nonregular          175
2 not_employed        326
3 regular             361
4 self_employed       138

count() は、同じ値の行を数える関数です。出力の n が、その値をとる人数です。欠測があれば、NA の行も表示されます。

条件に合う行を残す

valid <- selected |>
  dplyr::filter(
    support_1 %in% 1:5,
    support_5 %in% 1:5,
    employment_status %in% c(
      "regular", "nonregular", "self_employed", "not_employed"
    )
  )

filter() は、条件に合う行を残す関数です。ここでは、カンマで区切った3つの条件をすべて満たす行を残します。

  • 1:5 は、1から5までの整数を表します。
  • %in% は、左側の値が右側に挙げた値のどれかにあてはまるかを調べます。例えば support_1 %in% 1:5 は、support_1 の回答が1〜5のいずれかであるという条件です。

この条件なら、0や9が混ざっていても有効な回答としては残りません。ただし、実際の調査では、値の意味をコードブックで確認してから条件を決めます。ほかの条件式の書き方は、残す行の折りたたみで説明しています。

変数を追加する

reversed <- valid |>
  dplyr::mutate(support_5_r = 6 - support_5)

mutate() は、列を追加したり、既存の列を書き換えたりする関数です。ここでは 6 - support_5 の計算結果を新しい列 support_5_r に入れ、列を追加したデータを reversed に保存しています。新しい列名を指定したので、元の support_5 は残ります。

prepared <- reversed |>
  dplyr::mutate(
    employed = dplyr::if_else(
      employment_status %in% c("regular", "nonregular", "self_employed"),
      1L, 0L
    )
  )

if_else() には、条件、条件が成り立つ場合の値、成り立たない場合の値を順に書きます。1L と 0L は整数の1と0です。前の段階で就業区分を4種類に限定したので、このコードで0になるのは非就業の人だけです。0/1の値は新しい列 employed に入り、2つの列を追加したデータが最終的な保存先 prepared になります。

処理前後を照合する

まず、処理の各段階で人数が変わっていないかを確認します。nrow() は行数を求める関数です。

data.frame(
  stage = c("元データ", "列選択後", "条件確認後", "変数作成後"),
  n = c(nrow(survey), nrow(selected), nrow(valid), nrow(prepared))
)
       stage    n
1   元データ 1000
2   列選択後 1000
3 条件確認後 1000
4 変数作成後 1000

次に、逆転前後の値と、就業区分と0/1の値の組み合わせを数えます。2つの列を指定した count() は、同じ組み合わせの人数を数えます。

prepared |> dplyr::count(support_5, support_5_r)
# A tibble: 5 × 3
  support_5 support_5_r     n
      <dbl>       <dbl> <int>
1         1           5   111
2         2           4   215
3         3           3   320
4         4           2   238
5         5           1   116
prepared |> dplyr::count(employment_status, employed)
# A tibble: 4 × 3
  employment_status employed     n
  <chr>                <int> <int>
1 nonregular               1   175
2 not_employed             0   326
3 regular                  1   361
4 self_employed            1   138

id の重複と、元データにない id の有無も確かめます。1行目は重複している id の数で、0なら重複はありません。2行目は、すべての id が survey にあれば TRUE になります。

sum(duplicated(prepared$id))
[1] 0
all(prepared$id %in% survey$id)
[1] TRUE

最後に、先頭6人分を表示します。

head(prepared)
# A tibble: 6 × 6
     id employment_status support_1 support_5 support_5_r employed
  <dbl> <chr>                 <dbl>     <dbl>       <dbl>    <int>
1     1 regular                   3         5           1        1
2     2 nonregular                3         5           1        1
3     3 regular                   3         4           2        1
4     4 nonregular                4         2           4        1
5     5 nonregular                4         2           4        1
6     6 not_employed              1         3           3        0

列名に加えて、同じ人の元の回答と計算結果が対応しているかを確認してください。

6 検証チェックリスト

重要検証チェックリスト

コードが最後まで動いても、条件が正しいとは限りません。人数に加えて、変換前後の値の組み合わせを確認しましょう。例えば 5 - support_5 と書いてもエラーは出ませんが、結果は0〜4になり、今回の仕様から外れます。

7 結果の解釈

今回の処理では、4列を選び、2列を追加しました。全員が条件を満たしたので、人数は1,000人のままです。追加した2列は、次のように読みます。

  • support_5_r:高いほど、頼れる人がいると感じていることを表します。例えば、元の質問「悩みがあっても、頼れる人がいない」に2と答えた人は4になります。1つの質問の点数であり、5つの質問をまとめた尺度得点ではありません。
  • employed:1は、正規雇用、非正規雇用、自営業等のいずれかであることを表します。正規雇用だけを表す変数ではありません。

この模擬データには、非就業でも年収がある人がいます。年収が0かどうかで就業を判定すると、ここで決めた定義とは別の変数になります。

8 欠測を含む例

ここからは、欠測や特殊なコードを含むデータの処理を、6人分の小さな架空データで練習します。先ほどの survey とは別のデータです。

2つの質問 item_a と item_b の値は、次の意味だと決めておきます。

  • 1〜5:有効な回答
  • 9:「わからない」
  • NA:回答が記録されていない(NA はRで欠測を表す値)

9は数値として保存されています。意味を知らずに平均を計算すると、9が有効な点数に混ざってしまいます。

まず、次のコードを実行して、6人分のデータ example を作ってください。

example <- data.frame(
  id = 1:6,
  item_a = c(1, 2, 9, 4, NA, 5),
  item_b = c(5, NA, 3, 2, 1, 9)
)
example
  id item_a item_b
1  1      1      5
2  2      2     NA
3  3      9      3
4  4      4      2
5  5     NA      1
6  6      5      9

今回は、2つの回答がともに1〜5の人だけを残します。AIにコードを頼むときは、有効な値に加えて、9と NA がそれぞれ何を表すかも伝えてください。

ヒントAIへの指示例
Rにexampleというデータフレームがあります。データ本体は渡しません。
列はid、item_a、item_bの3つで、item_aとitem_bは数値です。
item_aとitem_bの有効な回答は1〜5です。
9は「わからない」、NAは回答が記録されていないことを表します。

exampleを変更せず、item_aとitem_bがともに1〜5の行だけを残して、
example_validという新しいデータフレームに保存してください。
処理前後の人数と、除外した人数を表示してください。
dplyrの関数とパイプ |> を使ってください。

有効な値の範囲を伝えずに「欠測を除いて」とだけ頼むと、NA だけを除き、9を残すコードが返ってくることがあります。1〜5の回答だけを使うことを必ず伝えましょう。

指示例をAIに送り、返ってきたコードを実行する前に、先ほど表示した example の表を見て、残る人の id を予想してください。実行した後は、次の参照コードと出力で確認します。

example_valid <- example |>
  dplyr::filter(item_a %in% 1:5, item_b %in% 1:5)
example_valid
  id item_a item_b
1  1      1      5
2  4      4      2

残るのはIDが1と4の2人です。除外された4人の理由は次のとおりです。

  • IDが3と6の人:どちらかの回答が9
  • IDが2と5の人:どちらかの回答が NA
data.frame(
  before = nrow(example),
  after = nrow(example_valid),
  removed = nrow(example) - nrow(example_valid)
)
  before after removed
1      6     2       4

残す行の条件を書くときに、起こりやすい誤りが2つあります。

  • 一部の列にしか条件を付けない。例えば item_a %in% 1:5 だけを条件にすると、item_b が NA のID 2と、9のID 6が残ってしまいます。
  • 使わない列の欠測まで、除外の理由にする。例えば、列を指定せずに「欠測のある行を除いて」とAIに頼むと、どこか1つの列でも NA がある行をすべて除くコードが返ってくることがあります。実際の調査データには多くの列があるため、今回の分析で使わない質問に答えていないだけの人まで除かれてしまいます。

どちらの誤りも、どの列について、どの値を有効とするかを指定すれば防げます。

なお、除外した人数を数えるのは、コードが決めたとおりに動いたかを確かめるためです。そもそも除外してよいかどうかは別の問題で、第9節(練習問題)で考えます。

9 練習問題

別の質問で処理する

ストレスの質問を使って、ここまでと同じ処理をしてみましょう。使う2つの列と質問文は、次のとおりです。

列名 質問文
stress_1 やるべきことに追われていると感じる。
stress_5 気持ちに余裕を持って過ごせている。

どちらも、1が「まったくあてはまらない」、5が「とてもよくあてはまる」を表します。

survey から id、stress_1、stress_5 の3列を選び、次の処理を行ってください。まず仕様を言葉にし、AIにコードを依頼してから実行します。

  1. 2つの回答がともに1〜5の行を残す。
  2. 逆転項目 stress_5 を6から引き、stress_5_r を追加する。
  3. stress_1 が4または5なら1、1〜3なら0をとる stress_1_high を追加する。
  4. 結果を stress_prepared に保存し、行数・列数、逆転前後と0/1の対応を表示する。

処理結果を説明する

前の問題で作った stress_prepared と、欠測を含む例について、次の問いに答えてください。

  1. stress_1_high = 1 の人は何人ですか。stress_1 の回答ごとの人数と照らし合わせて確かめてください。
  2. stress_1 の5段階を0と1にまとめると、区別できなくなる回答があります。どの回答とどの回答か、例を挙げて説明してください。
  3. 欠測を含む例では、6人から2人に減りました。このことを「データの質が改善した」と説明してよいでしょうか。

AIが出したコードを点検する

欠測を含む例で、2つの回答がともに1〜5の人を残したいと伝えたところ、次のコードが返ってきました。このコードでは誰が残りますか。仕様との違いを説明し、修正してください。

example |>
  dplyr::filter(item_a %in% 1:5 | item_b %in% 1:5)
stress_prepared <- survey |>
  dplyr::select(id, stress_1, stress_5) |>
  dplyr::filter(stress_1 %in% 1:5, stress_5 %in% 1:5) |>
  dplyr::mutate(
    stress_5_r = 6 - stress_5,
    stress_1_high = dplyr::if_else(stress_1 %in% c(4, 5), 1L, 0L)
  )
dim(stress_prepared)
[1] 1000    5
stress_prepared |> dplyr::count(stress_5, stress_5_r)
# A tibble: 5 × 3
  stress_5 stress_5_r     n
     <dbl>      <dbl> <int>
1        1          5   107
2        2          4   226
3        3          3   316
4        4          2   237
5        5          1   114
stress_prepared |> dplyr::count(stress_1, stress_1_high)
# A tibble: 5 × 3
  stress_1 stress_1_high     n
     <dbl>         <int> <int>
1        1             0   102
2        2             0   232
3        3             0   327
4        4             1   218
5        5             1   121

結果は1,000行・5列です。逆転処理の対応と、4と5の回答だけが1になっていることを確認します。

処理結果の説明は、次のとおりです。

  1. stress_1_high = 1 は339人です。stress_1 に4と答えた218人と、5と答えた121人の合計と一致します。
  2. 4と答えた人と5と答えた人は、どちらも1になり区別できません。1と答えた人と3と答えた人も、どちらも0になります。一方、3と4は1段階しか違わないのに、0と1に分かれます。どこで区切るかによって、誰が1になるかも変わります。
  3. そうは説明できません。人数が減ったことから分かるのは、決めたとおりに処理できたことだけです。除外した人がどのような人だったかによっては、残ったデータが偏ることがあります。例えば、item_a と item_b がストレスについての質問で、ストレスを強く感じている人ほど「わからない」と答えやすかったとします。この場合、9と答えた人を除くと、残った人にはストレスをあまり感じていない人が多くなります。そのデータで平均を求めると、本来よりストレスが低い結果になるかもしれません。除外するときは、何人除いたかに加えて、どのような人を除いたかも確かめましょう。

誤りのあるコードの | は「または」を表します。片方だけ有効な人も残るため、この例では6人全員が残ります。「両方」を指定するには、条件をカンマで区切るか、& でつなぎます。

example |>
  dplyr::filter(item_a %in% 1:5, item_b %in% 1:5)
  id item_a item_b
1  1      1      5
2  4      4      2

最終更新: 2026-10-05