- はじめに:機械学習とデータ前処理の重要な関係
- データの前処理って何?なぜ必要なの?
- Pandasとは? データ分析の頼れる相棒
- Pandasを使った基本的なデータ前処理ステップ
- 1. ライブラリのインポートとデータの準備
- pd.DataFrame() 関数の解説
- 2. まずはデータを確認しよう
- 3. 欠損値の処理
- isnull() 関数の解説
- sum() 関数の解説 (DataFrame/Seriesに対して)
- dropna() 関数の解説
- fillna() 関数の解説
- median() 関数の解説 (Seriesに対して)
- mode() 関数の解説 (Seriesに対して)
- 4. 外れ値の処理 (今回は簡単な例として削除)
- drop() 関数の解説 (DataFrameに対して)
- 5. 表記ゆれの修正
- replace() 関数の解説 (Seriesに対して)
- unique() 関数の解説 (Seriesに対して)
- 6. カテゴリ変数の数値化 (One-Hotエンコーディング)
- pd.get_dummies() 関数の解説
- まとめ:データ前処理は機械学習成功の鍵!
はじめに:機械学習とデータ前処理の重要な関係
こんにちは!これから機械学習、特に「教師あり学習」について学んでいきたいと考えている皆さん。このブログへようこそ!
機械学習と聞くと、なんだか難しそうな数式やプログラムがたくさん出てくるイメージがあるかもしれませんね。確かにそういう側面もありますが、実は機械学習のプロジェクトを成功させる上で、非常に重要でありながら、最初に取り組むべき基本的なステップがあります。それが今回ご紹介する「データの前処理」です。
教師あり学習は、簡単に言うと「過去のデータ(正解付きのデータ)からパターンを学習し、新しいデータに対して未来を予測する」技術です。例えば、過去の顧客データから、新しく来たお客さんが商品を買ってくれるかどうかを予測したり、過去の気温や天気データから明日の気温を予測したりします。
この「予測」の精度を高めるためには、機械学習モデル(予測を行うコンピュータープログラムのようなもの)に、質の高い、きれいなデータを学習させることが不可欠です。コンピューターの世界には「Garbage In, Garbage Out(ゴミを入力すれば、ゴミしか出てこない)」という有名な言葉があります。これは、いくら高性能な機械学習モデルを使っても、元となるデータが汚れていたり、整理されていなかったりすると、良い予測結果は得られない、という意味です。
そこで登場するのが「データの前処理」。これは、いわば料理でいう「下ごしらえ」のようなものです。美味しい料理を作るためには、野菜を洗ったり、皮をむいたり、適切な大きさに切ったりする必要がありますよね?データ分析や機械学習でも同様に、生のデータをモデルが理解しやすく、学習しやすい形に整える作業が必要なのです。
この記事では、データ分析の世界で非常に広く使われているPythonライブラリ「Pandas」を使いながら、データの前処理とは何か、なぜ重要なのか、そして具体的な手法について、初心者の方にも分かりやすく解説していきます。
この記事を読み終える頃には、あなたもデータの前処理の第一歩を踏み出し、Pandasを使って簡単なデータ操作ができるようになっているはずです!
データの前処理って何?なぜ必要なの?
データの前処理とは?
データの前処理とは、収集した生のデータを、機械学習モデルでの分析や学習に適した形式に変換・整形する一連の作業のことです。生のデータは、そのままでは機械学習モデルがうまく扱えないことが多いため、この「下ごしらえ」が必要になります。
なぜデータの前処理が必要なの?
大きく分けて、以下の3つの理由があります。
- 現実世界のデータは「汚い」ことが多いから:
私たちが手に入れるデータは、残念ながら最初から完璧に整っていることは稀です。例えば、アンケート調査のデータでは、回答が抜けている「欠損値」があったり、年齢に「999歳」のような明らかに間違った値(外れ値)が含まれていたり、同じ意味なのに「男性」「男」「M」のように表記がバラバラ(表記ゆれ)だったりします。このような「汚い」データをそのまま使うと、分析結果が歪んだり、モデルがうまく学習できなかったりします。
- 機械学習モデルには「好み」があるから:
多くの機械学習モデルは、数値データを扱うことを前提としています。そのため、「男性」「女性」のような文字列データ(カテゴリデータ)は、そのままでは扱えません。また、モデルによっては、データの尺度がバラバラだと(例えば、年齢は「歳」、収入は「万円」)、うまく学習できないこともあります。モデルが理解しやすい形式にデータを変換してあげる必要があるのです。
- モデルの予測精度を「向上」させるため:
不要な情報を取り除き、重要な情報を強調し、データを整理することで、機械学習モデルはデータの中にあるパターンをより効率的に、そして正確に学習できるようになります。結果として、予測精度が向上する可能性が高まります。
汚いデータの具体例:架空の顧客データ
言葉だけだとイメージしにくいかもしれませんので、簡単な架空の顧客データを見てみましょう。
顧客ID | 名前 | 年齢 | 性別 | 居住地 | 購入金額(円) | 最終購入日 |
---|---|---|---|---|---|---|
1 | 佐藤太郎 | 35 | 男性 | 東京都 | 5000 | 2023-10-20 |
2 | 鈴木花子 | 28 | 女性 | 大阪府 | 12000 | 2023-11-05 |
3 | 高橋一郎 | 42 | 男 | 8000 | 2023-09-15 | |
4 | 田中さち | 999 | 女 | 神奈川県 | 3000 | 2023-11-01 |
5 | 伊藤健太 | 31 | 男性 | 東京都 | 2023-08-30 |
このデータには、以下のような「前処理」が必要そうな点があります。
- 欠損値: 顧客ID=3の「居住地」、顧客ID=5の「購入金額(円)」が空欄になっています。
- 外れ値: 顧客ID=4の「年齢」が999歳になっています。これは入力ミスなどの可能性が高いです。
- 表記ゆれ: 「性別」列に「男性」「女性」「男」「女」が混在しています。
- 不要な情報: もし「購入金額を予測する」という目的の場合、「顧客ID」や「名前」は直接的な予測には使わないかもしれません。
- データ型: 「最終購入日」は日付ですが、文字列として扱われている可能性があります。また、「性別」は文字列です。
このような問題を一つ一つ解決していくのが、データの前処理です。そして、この作業を効率的に行うための強力なツールが「Pandas」なのです。
Pandasとは? データ分析の頼れる相棒
Pandas(パンダス)は、Pythonプログラミング言語で使用される、データ分析を支援するための非常に人気のあるライブラリ(便利な機能をまとめたもの)です。特に、Excelの表のような「表形式データ」を扱うのが得意です。
Pandasを使うと、以下のようなことができます。
- CSVファイルやExcelファイルなど、様々な形式のデータを簡単に読み込める。
- データの確認、集計、並び替え、絞り込みなどが容易に行える。
- 欠損値の処理やデータ型の変換など、データの前処理を効率的に実行できる。
- 複数のデータを結合したり、変形したりできる。
Pandasの中心的な役割を担うのが「DataFrame(データフレーム)」というデータ構造です。これは、まさに行と列からなるExcelのシートのようなものです。各列は「Series(シリーズ)」という一次元のデータ構造で構成されています。
これからの説明では、このPandasを使って、先ほどの架空の顧客データのような問題に対処していく方法を見ていきましょう。
Pandasを使った基本的なデータ前処理ステップ
それでは、実際にPandasを使ってデータの前処理を行ってみましょう。ここでは、先ほどの架空の顧客データを少し簡略化したサンプルデータを使います。
1. ライブラリのインポートとデータの準備
まず、Pandasライブラリを使えるように読み込みます。import pandas as pd
と書くのが一般的です(pd
という短い名前でPandasの機能を使えるようにするおまじないだと思ってください)。
そして、サンプルデータを作成します。ここではPythonの辞書を使ってデータを作り、それをPandasのDataFrameに変換します。
import pandas as pd import numpy as np # numpyも数値計算でよく使うライブラリなのでインポートしておきます # サンプルデータの作成 (辞書形式) data = { 'Age': [35, 28, 42, 999, 31, np.nan], # np.nan は欠損値を表します 'Gender': ['男性', '女性', '男', '女', '男性', '女性'], 'Prefecture': ['東京都', '大阪府', None, '神奈川県', '東京都', '大阪府'], # None も欠損値です 'PurchaseAmount': [5000, 12000, 8000, 3000, np.nan, 7500] } # 辞書からDataFrameを作成 df = pd.DataFrame(data) print("元のデータ:") print(df)
pd.DataFrame() 関数の解説
主な引数:
data
: DataFrameの元になるデータ。辞書、リストのリスト、NumPy配列などを指定できます。辞書の場合、キーが列名になり、値(リストなど)がその列のデータになります。
戻り値:
作成されたDataFrameオブジェクト。
動作:
引数で与えられたデータ構造をもとに、表形式のDataFrameを作成します。
上記のコードを実行すると、以下のようなDataFrameが表示されるはずです。
元のデータ: Age Gender Prefecture PurchaseAmount 0 35.0 男性 東京都 5000.0 1 28.0 女性 大阪府 12000.0 2 42.0 男 None 8000.0 3 999.0 女 神奈川県 3000.0 4 31.0 男性 東京都 NaN 5 NaN 女性 大阪府 7500.0
NaN
は “Not a Number” の略で、欠損値を表します。
2. まずはデータを確認しよう
データが手に入ったら、いきなり処理を始めるのではなく、まずどんなデータなのかを確認することが大切です。
head(): 最初の数行を表示
データの全体像をざっくり掴むのに便利です。デフォルトでは最初の5行が表示されます。
print("\nデータの最初の5行:") print(df.head())
info(): データ型の概要と欠損値の確認
各列の名前、非欠損値の数、データ型などを一覧表示してくれます。データ型が意図したものになっているか、どの列に欠損値が多いかなどを確認できます。
print("\nデータの情報:") df.info()
実行結果(一部):
RangeIndex: 6 entries, 0 to 5 Data columns (total 4 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Age 5 non-null float64 # 年齢: 5つが非欠損、データ型はfloat64 (浮動小数点数) 1 Gender 6 non-null object # 性別: 6つが非欠損、データ型はobject (主に文字列) 2 Prefecture 5 non-null object # 居住地: 5つが非欠損、データ型はobject 3 PurchaseAmount 5 non-null float64 # 購入金額: 5つが非欠損、データ型はfloat64 dtypes: float64(2), object(2) memory usage: 320.0+ bytes
Non-Null Count
が全体の行数(ここでは6)より少ない列には、欠損値があることがわかります (Age
, Prefecture
, PurchaseAmount
)。 Dtype
はデータ型を示します。float64
は小数点を含む数値、object
は主に文字列を表します。
describe(): 数値データの基本的な統計量の表示
数値データが含まれる列について、個数(count)、平均値(mean)、標準偏差(std)、最小値(min)、四分位数(25%, 50%, 75%)、最大値(max)などの基本的な統計量を計算して表示します。データのばらつき具合や、極端な値(外れ値)の存在を確認するのに役立ちます。
print("\n数値データの基本統計量:") print(df.describe())
実行結果:
数値データの基本統計量: Age PurchaseAmount count 5.000000 5.000000 mean 227.000000 7100.000000 std 433.206650 3507.135583 min 28.000000 3000.000000 25% 31.000000 5000.000000 50% 35.000000 7500.000000 # 中央値 (Median) 75% 42.000000 8000.000000 max 999.000000 12000.000000
Age
列を見ると、max
が999になっており、平均値(mean
)が227と非常に大きくなっています。これは明らかに外れ値の影響を受けていることが推測できますね。
3. 欠損値の処理
データを確認した結果、いくつかの列に欠損値 (NaN
や None
) があることがわかりました。欠損値は計算エラーの原因になったり、分析結果を歪めたりするため、対処が必要です。
欠損値の数を確認
まずは、どの列にいくつ欠損値があるかを確認しましょう。
print("\n各列の欠損値の数:") print(df.isnull().sum())
isnull() 関数の解説
引数:
なし
戻り値:
DataFrameの各要素が欠損値(NaN
, None
など)かどうかを示す、同じ形状の真偽値(True/False)のDataFrame。
動作:
要素が欠損値であればTrue、そうでなければFalseを返します。
sum() 関数の解説 (DataFrame/Seriesに対して)
引数:
axis
: 集計する軸を指定します。0
または'index'
(デフォルト) は列ごとに集計、1
または'columns'
は行ごとに集計します。
戻り値:
集計結果 (Seriesまたは数値)。
動作:
isnull()
の結果 (True/FalseのDataFrame) に対して sum()
を適用すると、Trueを1、Falseを0として列ごとに合計します。これにより、各列の欠損値(True)の数が計算されます。
実行結果:
各列の欠損値の数: Age 1 Gender 0 Prefecture 1 PurchaseAmount 1 dtype: int64
Age
, Prefecture
, PurchaseAmount
にそれぞれ1つずつ欠損値があることが確認できました。
欠損値の対処法
主な対処法は「削除」と「補完」の2つです。
対処法1: 削除 (dropna())
欠損値を含む行、または列全体を削除する方法です。データが大量にあり、欠損値のあるデータが比較的少ない場合に有効です。ただし、貴重な情報を失う可能性もあります。
# 欠損値を含む行を削除 (axis=0) df_dropped_row = df.dropna(axis=0) print("\n欠損値を含む行を削除したデータ:") print(df_dropped_row) # 欠損値を含む列を削除 (axis=1) # df_dropped_col = df.dropna(axis=1) # print("\n欠損値を含む列を削除したデータ:") # print(df_dropped_col)
dropna() 関数の解説
主な引数:
axis
:0
または'index'
(デフォルト) は欠損値を含む行を削除、1
または'columns'
は欠損値を含む列を削除します。how
:'any'
(デフォルト) は一つでも欠損値があれば削除、'all'
はすべての値が欠損値の場合に削除します。thresh
: 整数を指定すると、非欠損値がその数未満である行/列を削除します。subset
: 欠損値をチェックする列/行のラベルを指定します。inplace
:True
にすると、元のDataFrameを直接変更します (注意して使用)。デフォルトはFalse
で、新しいDataFrameを返します。
戻り値:
欠損値が削除されたDataFrame (inplace=Falseの場合)。
動作:
指定された条件に基づいて、欠損値を含む行または列を削除します。
対処法2: 補完 (fillna())
欠損値を何らかの値で埋める方法です。データ量を減らさずに済みますが、どのような値で埋めるかが重要になります。
- 数値データの場合:
- 平均値 (
mean()
): データ全体の平均的な値で埋める。外れ値の影響を受けやすい。 - 中央値 (
median()
): データを小さい順に並べたときの中央の値で埋める。外れ値の影響を受けにくい。 - 最頻値 (
mode()
): 最も頻繁に出現する値で埋める。 - 固定値: 0などの特定の値で埋める。
- 平均値 (
- カテゴリデータの場合:
- 最頻値 (
mode()
): 最もよく出現するカテゴリで埋める。 - 固定のカテゴリ: 「不明」などの新しいカテゴリで埋める。
- 最頻値 (
今回は、Age
と PurchaseAmount
は中央値で、Prefecture
は最頻値で補完してみましょう。
# Age の欠損値を中央値で補完 age_median = df['Age'].median() print(f"\nAgeの中央値: {age_median}") df['Age'].fillna(age_median, inplace=True) # inplace=True で元のDataFrameを直接変更 # PurchaseAmount の欠損値を中央値で補完 purchase_median = df['PurchaseAmount'].median() print(f"PurchaseAmountの中央値: {purchase_median}") df['PurchaseAmount'].fillna(purchase_median, inplace=True) # Prefecture の欠損値を最頻値で補完 pref_mode = df['Prefecture'].mode()[0] # mode()は最頻値が複数ある場合Seriesを返すため[0]で最初の値を取得 print(f"Prefectureの最頻値: {pref_mode}") df['Prefecture'].fillna(pref_mode, inplace=True) print("\n欠損値を補完した後のデータ:") print(df) print("\n再度、欠損値の数を確認:") print(df.isnull().sum())
fillna() 関数の解説
主な引数:
value
: 欠損値を埋めるための値(スカラー値、辞書、Series、DataFrameなど)。method
: 補完方法を指定します。'ffill'
(forward fill) は前の値で、'bfill'
(backward fill) は後の値で埋めます。axis
: 補完を行う軸 (0
or1
)。inplace
:True
にすると、元のDataFrame/Seriesを直接変更します。デフォルトはFalse
。
戻り値:
欠損値が補完されたDataFrame/Series (inplace=Falseの場合)。
動作:
欠損値(NaN
)を指定された値や方法で置き換えます。
median() 関数の解説 (Seriesに対して)
引数:
skipna
:True
(デフォルト) の場合、欠損値を無視して計算します。
戻り値:
計算された中央値 (数値)。
動作:
Series内の中央値を計算します。
mode() 関数の解説 (Seriesに対して)
引数:
dropna
:True
(デフォルト) の場合、欠損値を無視して計算します。
戻り値:
最頻値を含むSeries (最頻値が複数存在する場合があるため)。
動作:
Series内で最も頻繁に出現する値を計算します。
実行後、欠損値がすべて0になっていることが確認できます。
4. 外れ値の処理 (今回は簡単な例として削除)
describe()
の結果から、Age
列に999という外れ値があることがわかっています。外れ値の処理方法は様々ですが(例: 適切な値で置き換える、別の値に丸めるなど)、今回は単純にこの外れ値を含む行を削除してみましょう。
# Age が現実的でない値 (例: 100より大きい) の行を特定 outlier_index = df[df['Age'] > 100].index print(f"\nAgeの外れ値(>100)が含まれる行のインデックス: {outlier_index.tolist()}") # 外れ値を含む行を削除 df.drop(outlier_index, inplace=True) print("\nAgeの外れ値を削除した後のデータ:") print(df) print("\n再度、数値データの基本統計量を確認:") print(df.describe())
drop() 関数の解説 (DataFrameに対して)
主な引数:
labels
: 削除する行または列のラベル(単一ラベルまたはリスト)。axis
:0
または'index'
(デフォルト) は行を削除、1
または'columns'
は列を削除します。index
:axis=0
のエイリアス。削除する行ラベルを指定。columns
:axis=1
のエイリアス。削除する列ラベルを指定。inplace
:True
にすると、元のDataFrameを直接変更します。デフォルトはFalse
。
戻り値:
指定された行/列が削除されたDataFrame (inplace=Falseの場合)。
動作:
指定されたラベルを持つ行または列を削除します。
外れ値の行が削除され、Age
のmax
やmean
が現実的な値になっていることが確認できます。
5. 表記ゆれの修正
Gender
列には「男性」「女性」「男」「女」が混在しています。これを統一しましょう。例えば、「男」を「男性」に、「女」を「女性」に置き換えます。
# 表記ゆれを修正 replace_map = {'男': '男性', '女': '女性'} df['Gender'] = df['Gender'].replace(replace_map) print("\nGenderの表記ゆれを修正した後のデータ:") print(df) print("\nGender列のユニークな値を確認:") print(df['Gender'].unique())
replace() 関数の解説 (Seriesに対して)
主な引数:
to_replace
: 置き換えたい値(単一の値、リスト、辞書など)。value
:to_replace
を置き換える先の値。to_replace
が辞書の場合、この引数は不要。inplace
:True
にすると、元のSeriesを直接変更します。デフォルトはFalse
。
戻り値:
値が置き換えられたSeries (inplace=Falseの場合)。
動作:
Series内の値を指定されたルールに基づいて置き換えます。辞書を使うと、複数の値を一度に効率よく置き換えることができます。
unique() 関数の解説 (Seriesに対して)
引数:
なし
戻り値:
Series内のユニークな値(重複を除いた値)を格納したNumPy配列。
動作:
Seriesに含まれる値の種類を確認するのに便利です。
実行後、Gender
列の値が「男性」と「女性」に統一されていることが確認できます。
6. カテゴリ変数の数値化 (One-Hotエンコーディング)
機械学習モデルの多くは数値データしか扱えません。そのため、「男性」「女性」のようなカテゴリ変数や、「東京都」「大阪府」のような地域名も数値に変換する必要があります。
よく使われる手法に「One-Hotエンコーディング」があります。これは、カテゴリの各値に対して新しい列を作成し、該当するカテゴリの列には1を、それ以外の列には0を入れる方法です。
Pandasのget_dummies()
関数を使うと簡単に実現できます。
# カテゴリ変数をOne-Hotエンコーディング df_encoded = pd.get_dummies(df, columns=['Gender', 'Prefecture'], drop_first=True) print("\nOne-Hotエンコーディング後のデータ:") print(df_encoded)
pd.get_dummies() 関数の解説
主な引数:
data
: One-Hotエンコーディングを適用するDataFrameまたはSeries。columns
: エンコーディング対象とする列名のリスト。指定しない場合、数値型や日付型以外のすべての列が対象になる可能性があります。prefix
: 新しく作成される列名の接頭辞を指定できます。prefix_sep
: 接頭辞と元のカテゴリ値を区切る文字(デフォルトは_
)。dummy_na
:True
にすると、欠損値(NaN
)に対しても列を作成します。drop_first
:True
にすると、各カテゴリの最初のレベル(例: ‘男性’と’女性’なら’男性’)の列を削除します。これは、多重共線性(列同士が強い相関を持つこと)を防ぐために行われることがあります。例えば、「Gender_女性」が0なら自動的に男性だとわかるため、片方の列は不要という考え方です。
戻り値:
One-Hotエンコーディングが適用されたDataFrame。
動作:
指定されたカテゴリ列を、そのカテゴリ値に対応する0と1の数値列(ダミー変数)に変換します。
実行結果を見ると、Gender
列がGender_女性
列に、Prefecture
列がPrefecture_東京都
とPrefecture_神奈川県
列に変換されていることがわかります。drop_first=True
を指定したので、Gender_男性
列とPrefecture_大阪府
列は作成されていません(他のダミー列が0なら、それが該当カテゴリだとわかるため)。
これで、すべてのデータが数値になり、多くの機械学習モデルで扱える形式になりました!
まとめ:データ前処理は機械学習成功の鍵!
今回は、機械学習プロジェクトにおけるデータの前処理の重要性と、Pandasを使った基本的な前処理手法について解説しました。
- データの前処理はなぜ必要か?
- 生のデータは欠損値、外れ値、表記ゆれなどで「汚れている」ことが多い。
- 機械学習モデルが扱いやすい形式(主に数値)に変換する必要がある。
- モデルの予測精度を高めるため。
- Pandasを使った基本的な前処理ステップ
- データの読み込みと確認 (
pd.DataFrame()
,head()
,info()
,describe()
) - 欠損値の処理(削除
dropna()
または 補完fillna()
,median()
,mode()
) - 外れ値の処理(今回は削除
drop()
) - 表記ゆれの修正 (
replace()
) - カテゴリ変数の数値化 (
pd.get_dummies()
)
- データの読み込みと確認 (
今回ご紹介したのは、データ前処理のほんの一部です。実際のプロジェクトでは、データの特性や目的に応じて、さらに多くの手法(例えば、特徴量の尺度を揃えるスケーリング、データから新しい特徴を作り出す特徴量エンジニアリングなど)を組み合わせて使うことになります。
しかし、まずは今回学んだ基本的な確認方法や処理方法をマスターすることが、機械学習の第一歩として非常に重要です。Pandasは非常に強力なツールですので、ぜひ実際に手を動かしながら使い方に慣れていってください。
きれいなデータは、良い予測モデルを作るための基礎となります。データ前処理のスキルを身につけて、機械学習プロジェクトを成功に導きましょう!