こんにちはヤク学長です。
本記事の目的は、「簡単にKaggleを始める」ことを目的としています。
【本記事のもくじ】
まず、「Kaggle」に真剣に取り組むための概要を解説します。
下記の方法で、簡単に概要を抑えることができます。
- Kaggleはアジャイル型が基本
-
分析プロセスの作成
- 特徴量エンジニアリングの進め方
- 2.データ前処理(詳細)
- 3.特徴量生成
それでは、上から順番に見ていきます。
なお、本上記の方法を抑えれば成果が出ます。
・Kaggleを使って、必要な基礎スキルをスムーズに身につけ効率的に学ぶための記事です。
記事の内容は「転載 & 引用OK」問題ありません。
Kaggleはアジャイル型が基本
Kaggleはデータ分析のコンペティションプラットフォームであり、参加者が短期間で最高の結果を出すことを目的としています。そのため、開発手法としてアジャイル型が基本となっています。つまり、小さなステップで実装を進め、短期間で実装と検証を繰り返し、最終的な成果を目指すという開発手法が求められます。このようなアジャイル型の開発手法により、迅速なアイデアの検証や実装の修正が可能となり、最終的な成果の向上につながると考えられます。
分析プロセスの作成
分析プロセスとタスクのマトリックスの基本構成を記します
分析プロセス | タスク |
---|---|
分析設計 | – 目的の定義 |
– 問題の理解 | |
– メソッドの選択 | |
– 評価指標の決定 | |
データ前処理 | – 欠損値処理 |
– カテゴリ変数のエンコーディング | |
– データ正規化/標準化 | |
特徴量生成 | – 特徴エンジニアリング |
– 特徴選択 | |
データセット作成 | – 訓練データ/テストデータ(および検証データ)の分割 |
バリデーション設計 | – ホールドアウト法 |
– k-分割交差検証 | |
– 層化k分割交差検証 | |
– 時系列交差検証 | |
モデル学習 | – モデル構築 |
– ハイパーパラメータチューニング | |
– アンサンブル学習 | |
モデル推論 | – 予測値の生成 |
– 結果の解釈 | |
– モデル性能評価 |
このマトリックスは、機械学習やデータ分析プロジェクトを進める際に、各プロセスで行うべきタスクを整理し、進捗管理を容易にするために使用できます。
このマトリックスを3人で進める前提で進めていきます。
- ①ベースライン作成担当
- ②特徴量エンジニアリング
- ③モデルチューニング
今回は
②特徴量エンジニアリング担当
の工程を見ていきます。
特徴量エンジニアリングの進め方
特徴量エンジニアリングの進め方については、ベースライン工程担当者との関係性が非常に重要です。
ベースライン工程担当者は、データの基本的な前処理やモデルの基本的な構築を担当しており、特徴量エンジニアリングの前段階にあたります。そのため、特徴量エンジニアリングを行う際には、ベースライン工程担当者が作成したモデルや前処理に対して、どのような特徴量が有効かを検討する必要があります。
特徴量エンジニアリングの評価の例
例えば、Kaggleのタイタニックコンペティションにおいて、以下のように特徴量エンジニアリングを行った場合を考えてみます。
ベースラインモデルでは、Pclass、Sex、Ageの3つの特徴量を使用していました。そこで、Fareという特徴量を追加し、モデルの評価を行いました。
追加した特徴量の分布を確認したところ、外れ値が多数存在していることがわかりました。そこで、外れ値を除外した場合のモデル精度を測定することで、追加した特徴量の有用性を評価することができます。
また、Fareという特徴量は、Pclassと密接に関連していることがわかりました。そこで、PclassごとにFareの分布を比較し、それぞれのPclassにおけるFareの重要度を評価することもできます。
さらに、Fareという特徴量が不均衡な分布を持っていることがわかった場合、対数変換を行って分布を整え、その効果を評価することもできます。
以上のように、特徴量エンジニアリングの評価には、追加した特徴量の分布や重要度、他の特徴量との関係性、分布の整合性などを考慮して、精度向上のために評価を行うことが重要です。
Pythonのコード例です。説明変数として”Embarked”という列を追加しています。
import pandas as pd
# データの読み込み
train = pd.read_csv('train.csv')
# Embarked列の欠損値を最頻値で補完
train['Embarked'].fillna(train['Embarked'].mode()[0], inplace=True)
# Embarked列をOne-hotエンコーディング
embarked_onehot = pd.get_dummies(train['Embarked'], prefix='Embarked')
train = pd.concat([train, embarked_onehot], axis=1)
# モデルの学習や検証
# ...
このコードでは、”Embarked”列の欠損値を最頻値で補完し、One-hotエンコーディングを行っています。これにより、”Embarked”列の情報をモデルに取り込むことができます。
2.データ前処理(詳細)
①要約統計量の一括確認:Pandas関数describe()
Pandas関数のdescribe()
を使用することで、データセットの要約統計量を一括して確認することができます。以下は、サンプルデータセットの要約統計量を出力する例です。
import pandas as pd
# データの読み込み
df = pd.read_csv('sample_data.csv')
# 要約統計量の確認
summary = df.describe()
print(summary)
このように、describe()
関数を使用することで、データセットの各カラムの要約統計量を一括して確認することができます。
.TはPandasのDataFrameオブジェクトを転置するための属性で、行と列を入れ替えた新しいDataFrameを返します。
# 転置して表示 print(df.describe().T)
このように、describe()関数で表示される統計量をT属性で転置することで、カラム名が行名に、統計量がカラム名になった新しいDataFrameを表示することができます。
②指定した要約統計量の確認:Pandas関数agg()
Pandasのagg()関数を使用すると、指定した要約統計量を計算することができます。例えば、以下のようにして平均と標準偏差を計算することができます。
import pandas as pd
# データセットを読み込む
df = pd.read_csv('dataset.csv')
# 平均と標準偏差を計算する
result = df.agg(['mean', 'std'])
# 結果を表示する
print(result)
このようにすると、データセットの平均と標準偏差が計算され、以下のように表示されます。
col1 col2 col3
mean 10.000000 0.500000 0.100000
std 5.612486 0.534522 0.316228
③種類ごとの件数確認:Pandas関数value_counts()
Pandas関数value_counts()を用いると、カテゴリ変数について、それぞれの種類が何件ずつ存在するかを確認できます。以下は、例としてカラム名が「sex」であるデータフレームdfについて、値の種類ごとの件数を確認するコードです。
df['sex'].value_counts()
このコードを実行すると、性別が「male」と「female」の2種類である場合には、それぞれの件数が表示されます。
便利な標準ライブラリ pandas_profiling
pandas_profilingは、pandasデータフレームのプロファイリングレポートを生成するライブラリです。データフレームの各列についての統計量や分布、欠損値、相関関係などを可視化し、データの特徴を理解するのに役立ちます。また、プロファイリングレポートの出力も簡単で、HTML形式で出力できます。pandas_profilingを使うことで、データの概要を手軽に把握することができます。
import pandas as pd
import pandas_profiling
# データを読み込む
df = pd.read_csv("train.csv")
# プロファイルを作成する
profile = pandas_profiling.ProfileReport(df)
# レポートを出力する
profile.to_file("train_report.html")
このコードでは、pandas_profilingを使用して、train.csvのデータセットのプロファイルを作成し、train_report.htmlという名前のHTMLファイルとして出力しています。このファイルには、各変数の要約統計量、欠損値の数、相関関係、カテゴリ変数の分布などが含まれています。
欠損値の把握と補間
欠損値の把握と補間に関して、最初は何もしないことが有効な場合があります。欠損値が多すぎる場合や、欠損しているデータがあまりにもランダムである場合は、単に欠損値があるレコードを削除するか、欠損値を含むカラムを除外することが適切かもしれません。ただし、データ数が減ることによる情報の損失については注意が必要です。
また、欠損値を埋める場合は、そのデータの性質や欠損している理由に応じて、適切な方法で補完する必要があります。一般的な方法としては、欠損値をそのカラムの平均値や中央値、最頻値で補完する方法や、欠損値を含むデータと相関の高い別のカラムの値を使って予測値を求める方法があります。ただし、補完によって偏りが生じてしまう可能性があるため、注意が必要です。
①欠損値の確認方法
欠損値の確認方法は、Pandasのisnull()関数を使うことが一般的です。以下は具体的な例です。
import pandas as pd
# CSVファイルからデータを読み込む
df = pd.read_csv('data.csv')
# 欠損値の確認
print(df.isnull().sum())
上記のコードでは、isnull()関数によって各要素が欠損値かどうかを判定し、sum()関数によって欠損値の総数を算出しています。このようにして、各特徴量に含まれる欠損値の数を一度に確認することができます。
②欠損値の補間方法(数値)
欠損値の補間方法にはいくつかの種類があります。以下に代表的な方法を示します。
- 平均値・中央値・最頻値補間
- 数値データに対して、欠損値を平均値・中央値・最頻値で補間する方法。
- 連続値の線形補間
- 時系列データの場合、前後の値を元に欠損値を線形補間する方法。
- 時系列データの直前値補間
- 時系列データの場合、直前の値で欠損値を補間する方法。
- 他の変数からの補間
- 欠損値のある変数と強く相関がある別の変数から、欠損値を補間する方法。
- 回帰分析などの予測モデルを用いた補間
- 欠損値がある変数と、欠損値のない変数から予測モデルを構築し、欠損値を補間する方法。
どの補間方法を選ぶかは、データの性質や欠損の発生原因によって異なります。
0埋めと平均値補間
pandas
ライブラリを用いて、欠損値の補間をする例です。まずは、0埋めの場合の例を示します。
import pandas as pd
import numpy as np
# データの作成
df = pd.DataFrame({'A': [1, 2, np.nan, 4],
'B': [5, np.nan, 7, 8],
'C': [9, 10, 11, 12]})
# 欠損値を0で埋める
df_fillna = df.fillna(0)
# 結果の表示
print(df_fillna)
上記コードを実行すると、以下のように欠損値が0で埋まったデータフレームが表示されます。
A B C
0 1.0 5.0 9
1 2.0 0.0 10
2 0.0 7.0 11
3 4.0 8.0 12
次に、平均値補間の場合の例を示します。
import pandas as pd
import numpy as np
# データの作成
df = pd.DataFrame({'A': [1, 2, np.nan, 4],
'B': [5, np.nan, 7, 8],
'C': [9, 10, 11, 12]})
# 欠損値を平均値で補間する
df_fillna = df.fillna(df.mean())
# 結果の表示
print(df_fillna)
上記コードを実行すると、以下のように欠損値が平均値で補間されたデータフレームが表示されます。
A B C
0 1.0 5.0 9
1 2.0 6.0 10
2 2.333333 7.0 11
3 4.0 8.0 12
③欠損値の補間方法(カテゴリ)
カテゴリ変数における欠損値の補間方法には以下のような手法があります。
- 最頻値補間(Mode imputation):カテゴリ変数の中で最も頻度の高い値を欠損値に代入する方法。
- 欠損値を一意なカテゴリ値として扱う:欠損値を一意なカテゴリ値として扱い、新たなカテゴリ値としてモデルに組み込む方法。
- 重回帰分析などを用いた予測モデルによる補間:欠損値を含まない他の特徴量を用いて、重回帰分析などの予測モデルを作成し、欠損値を予測値で補完する方法。
これらの方法は、データの特性や問題によって最適な方法が異なります。データの内容や目的に合わせて、適切な方法を選択する必要があります。
空白埋めと最頻値補間
カテゴリ変数に対する欠損値の補間方法として、空白埋めや最頻値補間などがあります。以下にPythonでの具体例を示します。
空白埋めによる補間例:
import pandas as pd
# データ読み込み
df = pd.read_csv('data.csv')
# カテゴリ変数に空白を含む場合、'unknown'で補間
df['category_col'] = df['category_col'].fillna('unknown')
最頻値補間による補間例:
import pandas as pd
# データ読み込み
df = pd.read_csv('data.csv')
# カテゴリ変数の最頻値で補間
most_frequent_value = df['category_col'].mode().values[0]
df['category_col'] = df['category_col'].fillna(most_frequent_value)
空白埋めは、欠損値がランダムに発生する場合や欠損値の割合が少ない場合に有効です。一方、最頻値補間は欠損値が特定の値で発生する場合や欠損値の割合が多い場合に有効です。
外れ値の検出・補正
①一般的な知識やドメイン知識による外れ値の判定
外れ値を判定する方法にはいくつかありますが、一般的には以下のような方法があります。
- 箱ひげ図(box plot)による判定:箱ひげ図を用いて、中央値や四分位数から外れる値を外れ値として判定する方法です。
- ヒストグラムによる判定:分布から外れる値を外れ値として判定する方法です。例えば、正規分布に従う場合、平均値±3σの範囲を外れ値として判定することがあります。
Pythonで最小値と最大値を用いた外れ値の判定の例です。
import numpy as np
# データの作成
data = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 1000])
# 最小値と最大値の算出
min_val = np.min(data)
max_val = np.max(data)
# 外れ値の判定
for d in data:
if d < min_val or d > max_val:
print('外れ値があります:', d)
以下は、Pythonでhistを用いた外れ値の判定の例です。
import numpy as np
import matplotlib.pyplot as plt
# データの作成
data = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 1000])
# ヒストグラムの作成
plt.hist(data, bins=10)
# グラフの表示
plt.show()
外れ値は、上記の例では1000がそれに当たります。
②分布を推定して外れ値を判定する方法
分布を推定して外れ値を判定する方法には、主に以下のようなものがあります。
- 3σ法:平均±3倍の標準偏差よりも外側にあるデータを外れ値とする方法。
- Tukeyの箱ひげ図法:四分位数を用いて、箱の外側にあるデータを外れ値とする方法。
- カーネル密度推定法:カーネル密度関数を用いて、ピークから離れた箇所にあるデータを外れ値とする方法。
四分位範囲を利用して外れ値を判定する方法は以下の通りです。
- 第1四分位数(Q1)と第3四分位数(Q3)を求める。
- 四分位範囲(IQR)を求める。IQR = Q3 – Q1。
- 下限値をQ1 – 1.5 * IQRとし、上限値をQ3 + 1.5 * IQRとする。
- データ点が下限値よりも小さく、または上限値よりも大きい場合は外れ値とみなす。
Pythonでの具体例は以下のようになります。
import pandas as pd
# データを読み込む
df = pd.read_csv('data.csv')
# 第1四分位数、第3四分位数、四分位範囲を求める
Q1 = df.quantile(0.25)
Q3 = df.quantile(0.75)
IQR = Q3 - Q1
# 下限値と上限値を設定する
lower_limit = Q1 - 1.5 * IQR
upper_limit = Q3 + 1.5 * IQR
# 下限値より小さい、または上限値より大きいデータ点を外れ値とする
outliers = df[(df < lower_limit) | (df > upper_limit)].dropna(how='all')
このようにすることで、四分位範囲を利用して外れ値を判定することができます。
③外れ値の補正方法
データによっては、外れ値を除外することで情報の損失が生じる可能性があるため、迷ったら何もしないを選択することも考えましょう。
外れ値の補正方法はいくつかありますが、一般的には以下の方法があります。
- 外れ値を除外する方法:外れ値とされるデータをデータセットから除外します。ただし、データセット自体が小さい場合は、除外すると有意な情報が失われる可能性があるため、慎重に判断する必要があります。
- 外れ値をクリッピングする方法:外れ値を一定の範囲内に収めます。たとえば、外れ値を平均値+/-3倍の標準偏差に収める方法があります。
- 欠損値補完のように、外れ値を補完する方法:代表値(たとえば、中央値)で外れ値を補完します。
以上の方法は一般的な方法であり、データの性質や目的に応じて、適切な方法を選択する必要があります。
外れ値を欠損値に変換
外れ値を欠損値に変換する理由として、外れ値が予測モデルに与える影響を最小限にするため、または外れ値が人為的なミスである可能性があるため、モデルのパフォーマンスを損なうことなく取り扱いやすくするためなどが挙げられます。
具体的なコード例としては、PandasのDataFrameを操作する際に、条件を指定して外れ値を欠損値に変換することができます。例えば、以下のようなコードで、数値列である “age” 列の外れ値を欠損値に変換することができます。
import pandas as pd
# データ読み込み
df = pd.read_csv('train.csv')
# 外れ値を欠損値に変換
q1 = df['age'].quantile(0.25)
q3 = df['age'].quantile(0.75)
iqr = q3 - q1
outlier_min = q1 - 1.5 * iqr
outlier_max = q3 + 1.5 * iqr
df.loc[(df['age'] < outlier_min) | (df['age'] > outlier_max), 'age'] = None
# 欠損値の確認
print(df.isnull().sum())
このようにして、”age” 列の外れ値を欠損値に変換し、isnull().sum()
を用いて欠損値の数を確認することができます。
データの標準化・正規化
データの標準化と正規化は、機械学習において重要な前処理の一つです。主に、特徴量間のスケールの違いを解消するために行います。
標準化とは、データを平均が0、分散が1となるように変換することです。標準化を行うことで、各特徴量が平均値からどの程度離れているかを単位が統一された形で比較できるようになります。主に、線形回帰やロジスティック回帰、SVMなどで使用されます。
正規化とは、データを一定範囲内に収めるように変換することです。主に、KNN、ニューラルネットワーク、クラスタリングなどで使用されます。正規化は、値のスケールが重要な意味を持つ場合に役立ちます。
具体的な実装方法は、scikit-learnライブラリを使って以下のように行います。
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# データを読み込む
X = ...
# 標準化を行う
scaler = StandardScaler()
X_std = scaler.fit_transform(X)
# 正規化を行う
scaler = MinMaxScaler()
X_norm = scaler.fit_transform(X)
上記の例では、StandardScalerを使って標準化を行っています。MinMaxScalerを使うことで、正規化を行うことができます。
3.特徴量生成
特徴量生成とは、与えられたデータに対して、人工的に新しい特徴量を追加することを指します。データが持っている特性をよりよく反映し、モデルの性能を向上させるために、特徴量生成は非常に重要な前処理手法の一つとされています。特徴量生成には、ドメイン知識を使って手動で特徴量を作成する方法や、機械学習アルゴリズムを用いて自動で特徴量を生成する方法があります。
①仮説ベースの特徴量生成
仮説ベースの特徴量生成は、ドメイン知識や問題の理解に基づいて手動で特徴量を生成する方法です。機械的な特徴量生成は、自動的に特徴量を生成する方法です。
例えば、仮説ベースの特徴量生成の場合、不動産価格予測問題では、住宅の面積、駅からの距離、犯罪発生率などのドメイン知識に基づく仮説から、特徴量を生成することができます。
②機械的な特徴量生成
→基本的に効率が良いのは①の方。
以下に特徴量生成リストの例を示します。
タイプ | 利用する変数 |
---|---|
単変数 | 数値 |
カテゴリ | |
2変数組み合わせ | 数値 × 数値 |
カテゴリ変数 × カテゴリ変数 | |
数値 × カテゴリ変数 | |
時系列データ | 時間データ |
テキストデータ | テキストデータ |
特徴量生成リスト
特徴量生成リスト
手法 | 説明 |
---|---|
One-hot encoding | カテゴリカルデータを数値データに変換 |
Label encoding | カテゴリカルデータを連続値に変換 |
Frequency encoding | カテゴリカルデータを出現頻度に変換 |
Count encoding | カテゴリカルデータを出現数に変換 |
Target encoding | カテゴリカルデータを目的変数の平均値に変換 |
Mean encoding | カテゴリカルデータをターゲット変数の平均値に変換 |
Statistical aggregations | 集計統計量の追加 |
Bin numerical data | 数値データをビン分割 |
Log transformation | 数値データの対数変換 |
Square transformation | 数値データの二乗変換 |
Square root transformation | 数値データの平方根変換 |
Cubic root transformation | 数値データの三乗根変換 |
Interaction features | 特徴量の交互作用項の追加 |
Polynomial features | 特徴量の高次多項式の追加 |
Datetime features | 日時からの特徴量生成 |
Text features | 自然言語処理による特徴量生成 |
Image features | 画像処理による特徴量生成 |
Geospatial features | 地理空間データからの特徴量生成 |
特徴エンジニアリング
単変数:数値
①対数変換
対数変換は、正規分布に近似するためによく用いられます。以下はPythonでの具体例です。
import numpy as np
# 0から1までの一様乱数を生成
data = np.random.rand(1000)
# 対数変換
log_data = np.log(data)
# ヒストグラムを作成
import matplotlib.pyplot as plt
plt.hist(log_data, bins=50)
plt.show()
この例では、NumPyを使用して0から1までの一様乱数を生成しています。その後、np.log
を使用して対数変換を行い、matplotlibを使用してヒストグラムを作成しています。
②累乗、指数関数、逆数
累乗、指数関数、逆数の変換は、特に右に裾の長い分布を左に引っ張って正規分布に近づけるのに役立ちます。
- 累乗変換:データをある数値(例えば2や3など)の累乗で割ることで行われます。対数変換と同様に、小さい値を大きくし、大きい値を小さくします。
- 指数関数変換:指数関数変換は、データをある値の指数関数で乗算することによって行われます。右に裾の長い分布を左に引っ張るために使われます。
- 逆数変換:逆数変換は、データを1で割ることによって行われます。右に裾の長い分布を左に引っ張って正規分布に近づけるのに役立ちます。
以下はPythonでの具体例です。
累乗変換の例:
import numpy as np
import pandas as pd
# データセットの作成
data = pd.DataFrame({'x': np.random.normal(0, 1, 1000)})
# 累乗変換
data['x_pow2'] = data['x']**2
指数関数変換の例:
import numpy as np
import pandas as pd
# データセットの作成
data = pd.DataFrame({'x': np.random.normal(0, 1, 1000)})
# 指数関数変換
data['x_exp'] = np.exp(data['x'])
逆数変換の例:
import numpy as np
import pandas as pd
# データセットの作成
data = pd.DataFrame({'x': np.random.normal(0, 1, 1000)})
# 逆数変換
data['x_inv'] = 1 / data['x']
③離散化
離散化とは、連続値を離散値に変換することを指します。一般的に、離散化することでデータの扱いやすさが向上する場合があります。離散化の手法には、等幅分割や等頻度分割、k-means法などがあります。
等幅分割は、最小値から最大値までを指定された数だけ幅で分割する方法です。等頻度分割は、データを分位数で分割し、各分割間の値の数を等しくする方法です。k-means法は、クラスタリング手法の一つであり、各データをk個のクラスタに分割することで、離散化を行います。
以下は、Pythonでの等幅分割の具体例です。数値データを5つの区間に分割し、新しい離散変数を作成します。
import pandas as pd
# データの作成
data = pd.DataFrame({'value': [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]})
# 等幅分割
data['discretization'] = pd.cut(data['value'], 5, labels=False)
# 結果の表示
print(data)
出力結果:
value discretization
0 10 0
1 20 0
2 30 1
3 40 2
4 50 2
5 60 3
6 70 3
7 80 4
8 90 4
9 100 4
このように、等幅分割により、元の数値データが5つの区間に分割され、それぞれに0から4のラベルが割り当てられた離散変数が生成されました。
④欠損かどうかで0/1に変換
欠損値かどうかを0/1で表す場合、以下のような方法が考えられます。
- pandasのisnull()関数を用いる方法
import pandas as pd
# DataFrameの作成
df = pd.DataFrame({'A': [1, 2, None], 'B': [None, 4, 5]})
# isnull()関数で欠損値の箇所をTrue、非欠損値の箇所をFalseで表すDataFrameを作成する
isnull_df = df.isnull().astype(int)
print(isnull_df)
単変数:カテゴリ変数
①One Hot Encording
One Hot Encodingとは、カテゴリ変数を数値化する手法の一つで、カテゴリ変数を0と1のバイナリ表現に変換する方法です。カテゴリ変数がn個の場合、n個の変数を用意し、そのうち1つのみが1で他は0になるように表現します。例えば、色のカテゴリ変数が「赤」「青」「緑」の3つの場合、それぞれ「赤」は[1,0,0]、「青」は[0,1,0]、「緑」は[0,0,1]と表現されます。One Hot Encodingによって、カテゴリ変数の順序に意味がない場合や、機械学習アルゴリズムにカテゴリ変数をそのまま適用することができない場合に有用です。
Pythonでの実装例は以下の通りです。
import pandas as pd
# カテゴリ変数を含むデータセットを用意する
df = pd.DataFrame({'color': ['red', 'blue', 'green', 'red', 'green']})
# One Hot Encodingを実行する
ohe_df = pd.get_dummies(df, columns=['color'])
print(ohe_df)
出力結果は以下のようになります。
color_blue color_green color_red
0 0 0 1
1 1 0 0
2 0 1 0
3 0 0 1
4 0 1 0
②Count Encording
Count Encodingは、各カテゴリの出現回数をカテゴリの新しい値にエンコードする手法です。例えば、カテゴリ変数が「A, B, C, A, B, A」という値を持っている場合、「A=3, B=2, C=1」というように、各カテゴリの出現回数をカテゴリの新しい値としてエンコードします。
Pythonの例としては、以下のようにCountEncoderというクラスを作成して、fit_transformメソッドで変換を行います。
import pandas as pd
import category_encoders as ce
# データの準備
df = pd.DataFrame({'性別': ['男', '女', '男', '男', '女', 'その他', '女', '男']})
# カウントエンコーディングの実行
encoder = ce.CountEncoder(cols=['性別'])
df_encoded = encoder.fit_transform(df)
# 結果の表示
print(df_encoded)
実行結果は以下のようになります。
性別
0 4
1 3
2 4
3 4
4 3
5 1
6 3
7 4
カウントエンコーディングでは、カテゴリ変数の出現頻度に基づいて新しい特徴量が生成されるため、そのカテゴリ変数がどの程度頻繁に出現するかという情報が反映されます。しかし、カテゴリ数が多い場合や、同じ頻度の場合は区別できないという欠点があります。
③Label Encording
Label Encodingは、カテゴリ変数を数値に変換する方法の1つで、カテゴリ変数の各要素に一意の整数を割り当てます。
具体的には、例えばカラムに”red”、”blue”、”green”という3つのカテゴリがある場合、”red”を0、”blue”を1、”green”を2などのように、カテゴリの出現順に数値を割り当てます。
以下は、Pythonのscikit-learnライブラリを使って、Label Encodingを実行する例です。
from sklearn.preprocessing import LabelEncoder
# サンプルのカテゴリ変数
color = ["red", "blue", "green", "green", "red"]
# Label Encoderを定義
le = LabelEncoder()
# カテゴリ変数を数値に変換
encoded_color = le.fit_transform(color)
print(encoded_color)
実行結果:
[0 1 2 2 0]
上記の例では、”red”が0、”blue”が1、”green”が2に変換されています。
2変数の組み合わせ
数値×数値
数値×数値の組み合わせによる特徴量生成方法は、以下のようなものがあります。
-
積特徴量:2つの数値変数を掛け合わせることで生成される特徴量です。例えば、身長と体重の積を特徴量として追加することができます。
-
商特徴量:2つの数値変数を割り算することで生成される特徴量です。例えば、身長を体重で割ったBMI(Body Mass Index)を特徴量として追加することができます。
-
差分特徴量:2つの数値変数の差分を計算することで生成される特徴量です。例えば、前年度との売上高の差分を特徴量として追加することができます。
-
平均特徴量:2つの数値変数の平均を計算することで生成される特徴量です。例えば、家賃と光熱費の平均を特徴量として追加することができます。
これらの方法によって、2つの数値変数から新しい特徴量を生成することができます。ただし、注意すべき点として、2つの変数の相関が高い場合は、過学習のリスクがあるため、注意が必要です。
身長と体重からBMIという新しい特徴量を作成する例です。
import pandas as pd
# データフレームの作成
data = {
'height': [165, 170, 155, 180, 160],
'weight': [52, 65, 48, 70, 55]
}
df = pd.DataFrame(data)
# BMIの計算
df['bmi'] = df['weight'] / ((df['height'] / 100) ** 2)
print(df)
出力結果:
height weight bmi
0 165 52 19.100092
1 170 65 22.491349
2 155 48 19.934640
3 180 70 21.604938
4 160 55 21.484375
この例では、身長と体重からBMIという新しい特徴量を作成しました。身長はcm、体重はkgで表され、BMIは体重(kg) / (身長(m) * 身長(m))で計算されます。このように、2つの既存の特徴量から新しい特徴量を作成することができます。
数値 × カテゴリ変数
数値 × カテゴリ変数の特徴量生成の例として、以下のようなものがあります。
例えば、ある建物の面積を表す数値変数と、その建物の用途を表すカテゴリ変数があった場合、それらの組み合わせで新しい特徴量を作成することができます。具体的には、建物の面積がその用途に適しているかどうかを表す指標を作成することができます。例えば、以下のような指標が考えられます。
- 面積/部屋数:建物全体の面積を部屋数で割った値。部屋の広さが適切かどうかを判定する指標となります。
- 面積/人数:建物全体の面積を利用者数で割った値。居住空間として十分な広さを確保しているかどうかを判定する指標となります。
これらの指標を新しい特徴量としてデータセットに加えることで、より良い予測モデルを作成することができる場合があります。
例えば、以下のようなデータがあるとします。
ID | Age | Gender |
---|---|---|
1 | 25 | Male |
2 | 30 | Female |
3 | 22 | Male |
4 | 35 | Female |
AgeとGenderの組み合わせに基づく新しい特徴量を作成するには、pandasのapply関数を使って次のようにします。
import pandas as pd
df = pd.DataFrame({'ID': [1, 2, 3, 4],
'Age': [25, 30, 22, 35],
'Gender': ['Male', 'Female', 'Male', 'Female']})
df['Age_Gender'] = df.apply(lambda x: str(x['Age']) + '_' + x['Gender'], axis=1)
print(df)
実行結果:
ID Age Gender Age_Gender
0 1 25 Male 25_Male
1 2 30 Female 30_Female
2 3 22 Male 22_Male
3 4 35 Female 35_Female
このように、AgeとGenderの組み合わせに基づく新しい特徴量 Age_Gender が追加されました。
カテゴリ変数 × カテゴリ変数
①出現回数
カテゴリ変数 × カテゴリ変数の場合、出現回数などの統計量を算出する方法があります。
具体的には、Pandasのcrosstab
関数やmelt
関数を使う方法があります。
例えば、以下のようなデータがあったとします。
gender car_type
0 female compact
1 male compact
2 female suv
3 male suv
4 male suv
これをgender
とcar_type
の組み合わせごとにカウントしたい場合、crosstab
関数を使って以下のようにして計算できます。
import pandas as pd
data = pd.DataFrame({
'gender': ['female', 'male', 'female', 'male', 'male'],
'car_type': ['compact', 'compact', 'suv', 'suv', 'suv']
})
result = pd.crosstab(index=data['gender'], columns=data['car_type'])
print(result)
出力結果は以下のようになります。
car_type compact suv
gender
female 1 1
male 1 2
また、melt
関数を使うと、行と列を入れ替えることで、出現回数のような統計量を縦に並べることができます。以下は上記のデータに対してmelt
関数を適用した例です。
import pandas as pd
data = pd.DataFrame({
'gender': ['female', 'male', 'female', 'male', 'male'],
'car_type': ['compact', 'compact', 'suv', 'suv', 'suv']
})
result = data.melt().value_counts().reset_index()
result.columns = ['combination', 'count']
print(result)
出力結果は以下のようになります。
combination count
0 (male, suv) 2
1 (female, suv) 1
2 (female, compact) 1
3 (male, compact) 1
②出現割合
一方の変数を母集団としたときのもう片方の出現割合を計算する方法
指定するカテゴリ変数を列名に持つデータフレーム df
に対して、以下のように処理することで、一方の変数を母集団として、もう片方の変数の出現割合を計算することができます。
# カテゴリ変数1を母集団としたときのカテゴリ変数2の出現割合を計算する場合
cross_tab = pd.crosstab(df['カテゴリ変数1'], df['カテゴリ変数2'], normalize='index')
cross_tab_percentage = cross_tab.apply(lambda x: x/x.sum(), axis=1)
ここでは pd.crosstab
でカテゴリ変数1とカテゴリ変数2のクロス集計を行い、その結果を apply
メソッドを使って行ごとに正規化することで、一方の変数を母集団としたときのもう片方の変数の出現割合を求めています。
normalize='index'
を指定すれば、pd.crosstab
の結果を行ごとに正規化することができますが、この場合はカテゴリ変数1とカテゴリ変数2の出現回数の合計が1になるため、一方の変数を母集団としたときの出現割合を計算することができません。
③条件式を用いた変換
カテゴリ変数同士の組み合わせについて、条件に応じて新しいカテゴリ変数を生成する方法として、numpy
のwhere
関数を使うことができます。例えば、以下のようなデータがあるとします。
import pandas as pd
df = pd.DataFrame({
'gender': ['male', 'female', 'female', 'male', 'male'],
'age': [20, 35, 45, 30, 50]
})
このデータにおいて、genderとageの組み合わせによって、新しいカテゴリ変数”age_group”を作成したい場合を考えます。ここで、ageが30歳以下であれば”young”、31歳以上40歳以下であれば”middle”、41歳以上であれば”old”というカテゴリ変数を作成するとします。以下のようにwhere
関数を使うことで、ageの値に応じてage_groupを生成することができます。
import numpy as np
df['age_group'] = np.where(df['age'] <= 30, 'young',
np.where(df['age'] <= 40, 'middle', 'old'))
このように、where
関数を用いることで、複雑な条件式を簡潔に記述することができます。
時間データ
①ラグ特徴量
ラグ特徴量とは、時間的な変化に対してモデルが反応するように、過去の値と現在の値との差分を特徴量として使用する方法です。例えば、過去数時間の平均値、過去数日間の最小値、過去数週間の標準偏差などが考えられます。ラグ特徴量を使用することで、時間的な変化に対するモデルの反応性が向上し、予測精度の向上が期待できます。
ラグ特徴量の具体例として、タイタニック号のデータセットを使って説明します。
まず、pandasのDataFrameからラグ特徴量を生成する例を示します。以下のコードは、タイタニック号のデータセットから、乗客のID、年齢、および生存状況を読み込みます。
import pandas as pd
df = pd.read_csv('titanic.csv', usecols=['PassengerId', 'Age', 'Survived'])
df.head()
次に、shift
関数を使ってラグ特徴量を生成します。ここでは、年齢に対して1つ前の行の年齢をラグ特徴量として生成する例を示します。shift(1)
とすることで、前の行の値を取得しています。
df['Age_lag1'] = df['Age'].shift(1)
df.head()
このようにして、pandasのshift
関数を使ってラグ特徴量を生成することができます。ここでは1つ前の行の値を取得しましたが、shift
関数の引数を変更することで、2つ以上前の行の値を取得することも可能です。また、複数のラグ特徴量を同時に生成することもできます。
method=bfil、ffil
method
パラメーターは、欠損値を補間する際に使用する補間方法を指定するために使用されます。以下は、2つの一般的な方法です。
ffill
(またはpad
):前方埋め込み。前の有効な観測値が使用され、欠損値がそれで埋められます。bfill
(またはbackfill
):後方埋め込み。次の有効な観測値が使用され、欠損値がそれで埋められます。
例えば、以下はbfill
メソッドを使用して欠損値を補間する例です。
import pandas as pd
# 欠損値を含むDataFrameを作成
df = pd.DataFrame({'A': [1, 2, np.nan, 4, np.nan], 'B': [6, np.nan, np.nan, 9, 10], 'C': [11, 12, 13, np.nan, np.nan]})
# 欠損値を補間
df_interpolated = df.interpolate(method='bfill')
print(df_interpolated)
出力結果:
A B C
0 1.0 6.0 11.0
1 2.0 9.5 12.0
2 4.0 9.5 13.0
3 4.0 9.5 NaN
4 NaN 10.0 NaN
IDごとに1行シフト
IDごとに1行シフトする例です。例えば、以下のようなDataFrame df
があったとします。
ID date value
0 A 1/1/1 3
1 A 1/2/1 4
2 A 1/4/1 2
3 A 1/5/1 6
4 B 1/1/1 1
5 B 1/3/1 5
6 B 1/5/1 3
7 C 1/2/1 2
8 C 1/5/1 9
9 C 1/6/1 1
IDごとに1行シフトするには、groupby()
メソッドを使ってIDごとにグループ分けし、shift()
メソッドを使ってシフトします。この例では、date
列を日付型に変換してソートしてからシフトします。
df['date'] = pd.to_datetime(df['date'])
df = df.sort_values(by=['ID', 'date'])
df['shifted_value'] = df.groupby('ID')['value'].shift()
この結果、以下のようになります。
ID date value shifted_value
0 A 2001-01-01 3 NaN
1 A 2001-01-02 4 3.0
2 A 2001-01-04 2 4.0
3 A 2001-01-05 6 2.0
4 B 2001-01-01 1 NaN
5 B 2001-01-03 5 1.0
6 B 2001-01-05 3 5.0
7 C 2001-01-02 2 NaN
8 C 2001-01-05 9 2.0
9 C 2001-01-06 1 9.0
②ウィンドウ特徴量
ウィンドウ特徴量とは、時系列データを扱う際に、ある時間枠内のデータを集計して特徴量を生成する手法です。ウィンドウサイズと呼ばれる時間枠を設定し、その中での最大値や平均値などを特徴量として抽出します。
例えば、株価の時系列データにおいて、1日の株価変動に注目する場合、その日の始値、高値、安値、終値などがあるわけですが、それらをウィンドウサイズを1日に設定して集計することで、その日の値動きを表す特徴量を生成することができます。
ウィンドウサイズはデータに合わせて調整する必要があります。ウィンドウサイズが小さい場合、細かい変動を捉えることができますが、ノイズも含まれやすくなります。一方、ウィンドウサイズが大きすぎる場合、データの特徴を捉えきれず、情報の損失が生じる可能性があります。
ウィンドウ特徴量の抽出には、Pandasのrolling関数を使うと簡単に実装することができます。以下に、移動平均を計算する例を示します。
import pandas as pd
# 時系列データを読み込む
df = pd.read_csv('data.csv', parse_dates=['datetime'])
# datetime列をインデックスに設定する
df = df.set_index('datetime')
# ウィンドウサイズを7日に設定して移動平均を計算する
rolling_mean = df.rolling(window=7).mean()
この例では、window
引数に7を指定しています。これにより、7日間の移動平均が計算されます。計算結果は、rolling_mean
変数に格納されます。
③累積特徴量
累積特徴量とは、ある時点での過去の値の合計や平均など、累積的な値を表す特徴量のことを指します。例えば、ある商品の売上データがあった場合、その商品の過去の売上の累計や、過去何日間の平均売上などが累積特徴量になります。
累積特徴量は、時系列データやパネルデータの分析でよく使われます。過去の情報を使って将来の予測を行う際に有用な情報を提供することができます。
累積特徴量の生成には、pandasのrollingやexpanding関数を用いることが一般的です。rolling関数は、指定したウィンドウサイズに基づいて移動平均や移動合計を計算することができます。一方、expanding関数は、開始点から現在までの全ての値の合計や平均などを計算することができます。また、累積特徴量の生成には、GroupByやwindow関数を使用することもできます。
累積和と累積積を計算する具体例を示します。
まずは、以下のようなデータフレームを考えます。
import pandas as pd
import numpy as np
df = pd.DataFrame({'A': [1, 3, 5, 7, 9], 'B': [2, 4, 6, 8, 10]})
これは、2つの列AとBを持つ5行のデータフレームです。
累積和は、各列の前からの累積和を計算することで得られます。pandasのcumsum
関数を用いることで計算できます。
cumsum = df.cumsum()
累積積は、各列の前からの累積積を計算することで得られます。pandasのcumprod
関数を用いることで計算できます。
cumprod = df.cumprod()
これらのコードを実行することで、累積和と累積積のデータフレームが得られます。
テキストデータ
①単語の出現回数(BoW:Bag of Words)
BoW(Bag of Words)とは、テキストデータから特徴量を生成する手法の一つで、単語の出現回数を特徴量として扱う方法です。以下はPythonでBoWを実装する例です。
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
# テキストデータの用意
text = ['This is a pen', 'That is a book', 'This is a book']
# CountVectorizerのインスタンスを生成
vectorizer = CountVectorizer()
# 単語の出現回数をカウント
X = vectorizer.fit_transform(text)
# 特徴量名を取得
feature_names = vectorizer.get_feature_names()
# 特徴量をDataFrame形式で表示
df = pd.DataFrame(X.toarray(), columns=feature_names)
print(df)
出力結果:
book is pen that this
0 0 1 1 0 1
1 1 1 0 1 0
2 1 1 0 0 1
ここでは、CountVectorizer()
を用いて、text
内の単語の出現回数をカウントしています。fit_transform()
でベクトル化した特徴量を得て、get_feature_names()
で特徴量名を取得し、DataFrame
に変換しています。特徴量は単語ごとにカラムになり、各行においての単語の出現回数が値として入っています。
MeCabは、形態素解析を行うためのツールで、日本語の文章を形態素(言葉の意味を持つ最小単位)に分割して、それぞれの品詞や活用形、読み仮名を判別することができます。
Kaggle環境でMeCabを使用するためには、以下の手順を実行します。
- 「Japanese Tokenizer」をインストールする。
以下のコードを実行します。
!pip install janome
- 「MeCab Python3」をインストールする。
以下のコードを実行します。
!pip install mecab-python3
- 形態素解析を行うコードを作成する。
以下のコードは、MeCabを使用して文章の形態素解析を行う例です。
import MeCab
tagger = MeCab.Tagger('-d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd')
text = 'すもももももももものうち'
result = tagger.parse(text)
print(result)
これで、Kaggle環境でMeCabを使用することができます。
特徴選択
①フィルター法
フィルター法とは、あらかじめ決められた基準に従って、特徴量を選択する方法の一つです。主に、個々の特徴量を評価して、それらをランキングし、上位にランクされた特徴量のみを採用する手法です。
フィルター法では、主に以下のような手法が使われます。
- 相関係数による選択
- 分散による選択
- 統計検定による選択
相関係数による選択は、目的変数と各特徴量の相関係数を算出し、その値が高い特徴量を選択します。分散による選択は、特徴量の分散が小さいものを削除し、分散が大きいものだけを選択します。統計検定による選択は、t検定やANOVAなどの統計検定を用いて、特徴量が目的変数に有意に影響を与えるかどうかを検定し、有意であるものだけを選択します。
これらの手法を組み合わせて使用することもあります。ただし、フィルター法は特徴量同士の相関を考慮せずに選択するため、他の手法に比べて精度が低いという欠点があります。
②ラッパー法(おすすめ)
ラッパー法とは、モデルを学習するための最適な特徴量のサブセットを見つけるために、モデル自体を使って特徴量の組み合わせを評価する方法です。
ラッパー法は、特徴量の数が多い場合に有効であり、特徴量間の相互作用を考慮した特徴量選択が可能ですが、計算量が膨大になるというデメリットがあります。
一般的なラッパー法の手順は以下の通りです。
- 特徴量のサブセットをランダムに選択する。
- ランダムに選択した特徴量を用いてモデルを学習し、評価指標を計算する。
- すべての可能な特徴量の組み合わせについて1,2を繰り返す。
- 評価指標が最も良い特徴量のサブセットを採用する。
- 上記の手順を繰り返し、最良の特徴量サブセットを見つける。
代表的なラッパー法には、Recursive Feature Elimination (RFE)やForward Selectionなどがあります。これらはScikit-learnなどの機械学習ライブラリで実装されています。
③組み込み方式
組み込み方式とは、モデル学習の過程で特徴量選択を行う手法のことを指します。具体的には、決定木やランダムフォレストなどのアルゴリズムを用いて、特徴量の重要度を算出し、重要度の高い特徴量のみを選択する方法です。この手法は、モデル学習と特徴量選択を同時に行うため、特徴量選択にかかる時間を短縮できるというメリットがあります。ただし、選択された特徴量が最適なものであるとは限らないため、他の手法と併用することが推奨されます。
というわけで、今回は以上です。大変お疲れ様でした。
引き続きで、徐々に発信していきます。
コメントや感想を受け付けています。ちょっとした感想でもいいので嬉しいです。
それでは、以上です。