MENU

【成功の秘訣】特徴量エンジニアリングの手順と方法を解説(コピペで使えるPythonサンプルコード付き)

本記事は「【成功の秘訣】現場で使えるデータ分析手順を体系的に解説」で紹介した特徴量エンジニアリングの具体的な手順とPythonのサンプルコードを紹介しています。

Pythonのサンプルコードは利用者がコピペして利用することを前提に関数化していますので、是非参考にしてください。

目次

特徴量エンジニアリングとは

特徴量エンジニアリングとは、機械学習モデルの予測精度を向上させるための入力データの加工手法です。具体的には、データの複雑性や偏りを補正し、機械学習アルゴリズムが適切にモデル化できる表現形式へ変換する操作を指します。

  • 特徴量の選択
  • 特徴量のスケーリング
  • 新しい特徴量の生成

特徴量とは、モデルにとって意味のあるデータの属性(項目名)を指します。
例えば、特定の生産設備に対する不良率を予測する場合、「温度」、「湿度」、「時間」、「設備の設定値」は特徴量となります。
一方で、「生産設備ID」や「製品ID」は生産設備や製品を一意に識別するためのものであり、不良率の予測には直接的な影響を与えないと考えられます。
ただし、複数の生産設備や製品を比較して不良発生傾向の違いを分析したい場合には、生産設備IDや製品IDが特徴量となる場合もあります。

特徴量エンジニアリングの手順

特徴量の選択

機械学習モデルは、データの特徴量と呼ばれる情報に基づいて予測を行います。しかし、多くの場合、データには膨大な数の特徴量が含まれ、その全てがモデルにとって有用とは限りません。
不要な特徴量を含むことは、以下のような悪影響を及ぼす可能性があります。

  • 過学習
    モデルが訓練データに過剰に適合し、新しいデータに対して十分な汎化性能を発揮できなくなる。
  • 計算コストの増加
    モデルの学習や推論に時間がかかり、処理速度が低下する。
  • モデルの解釈可能性の低下
    モデルがどのように予測を行うのか理解しにくくなる。

これらの問題を解決するために、次のポイントを踏まえて特徴量を選択します。

目的変数と高い相関関係を持つ特徴量を優先的に選択する

目的変数(ターゲット変数)と高い相関を持つ特徴量は、予測に有用である可能性が高いため、優先的に選択します。これは、ピアソン相関係数やスピアマン相関係数などの統計指標を用いて評価します。

import pandas as pd

# サンプルデータ
data = {'feat1': [1, 2, 3, 4, 5],'feat2': [2, 4, 6, 8, 10],'target': [10, 20, 30, 40, 50]}
df = pd.DataFrame(data)

# 相関行列の計算
correlation_matrix = df.corr()
print(correlation_matrix['target'].sort_values(ascending=False))

多重共線性(説明変数の間で高い相関関係)がある場合は、いずれか1つだけを選択する

説明変数(特徴量)同士が高い相関を持つ場合、「多重共線性」と呼ばれる問題が発生します。この状態では、回帰係数の推定値が不安定になり、変数ごとの影響の度合いを解釈するのが難しくなります。多重共線性があると、モデルの性能や予測精度にも悪影響を与える可能性があります。

この問題を解決するためには、相関の高い説明変数の中から重要なものを1つ選択し、他の冗長な説明変数を除去することが有効です。これにより、モデルの複雑さが減少し、過学習のリスクを低減できます。

import seaborn as sns
import matplotlib.pyplot as plt

# 相関行列の作成
sns.heatmap(df.corr(), annot=True, cmap='coolwarm')
plt.show()

学習結果で重要度や寄与度が高い特徴量を優先的に選択する

モデルの学習結果から得られる特徴量の重要度(例えば、決定木やランダムフォレストのfeature_importances_属性)や寄与度を基に、重要な特徴量を選択します。これにより、モデルの性能に大きく貢献する特徴量の見逃しが防げます。

重要度の高い特徴量を優先的に活用し、不要な特徴量を削減することで、モデルの性能向上と過学習の防止が期待できます。

from sklearn.ensemble import RandomForestRegressor

# ランダムフォレストモデルの訓練
model = RandomForestRegressor()
model.fit(df[['feature1', 'feature2']], df['target'])

# 特徴量の重要度
importances = model.feature_importances_
print(importances)

分散が大きい特徴量を優先的に選択する

分散が極端に小さい特徴量は、情報量が少なく、モデルのパフォーマンスに貢献しない可能性があります。そのため、分散が大きい特徴量を優先的に選択します。この際、分散のしきい値を設定して特徴量を選別する方法が有効です。

具体的には、分散の大きさを基準にして特徴量を選別することで、情報量が豊富な特徴量を効果的に取り入れることができます。これにより、モデルの予測性能や解釈性を向上させることが期待できます。

from sklearn.feature_selection import VarianceThreshold

# 分散しきい値を設定して特徴量を選択
selector = VarianceThreshold(threshold=0.1)
X_high_variance = selector.fit_transform(X)
print(X_high_variance )

特徴量のスケーリング(特徴量の尺度を揃える)

特徴量のスケーリング(正規化)行うことで、異なる特徴量の値の尺度(範囲)を統一し、モデルの学習を安定させることができます。

  • 収束の速度向上
    勾配降下法を用いるモデル(例:線形回帰、ロジスティック回帰、ニューラルネットワーク)は、特徴量のスケーリングがされていないと、学習が遅くなる可能性があります。
  • 同一の重要度
    特徴量の値の範囲が異なると、モデルは値の大きい特徴量を重要視する傾向があります。スケーリングにより、全ての特徴量が同じ尺度で評価されます。
  • 過学習の抑制
    一部の特徴量が極端に大きいと、モデルがそれに過度に適応し、過学習のリスクが高まります。

標準化(Standardization)

標準化は、データの平均を0、分散を1に変換する手法です。異なるスケールの特徴量を同じスケールで扱うことが可能になります。データが正規分布に従っている場合に特に有効です。

from sklearn.preprocessing import StandardScaler
import pandas as pd

# サンプルデータ
data = {'age': [23, 45, 31, 35, 27],'salary': [60000, 80000, 50000, 70000, 65000]}
df = pd.DataFrame(data)

# 標準化
scaler = StandardScaler()
scaled_df = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)
print(scaled_df)

最小値-最大値スケーリング(Min-Max Scaling)

最小値-最大値スケーリングは、データを指定した範囲(通常は0から1)に変換する手法です。データが一様に分布している場合に有効です。

from sklearn.preprocessing import MinMaxScaler

# 最小値-最大値スケーリング
scaler = MinMaxScaler()
scaled_df = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)
print(scaled_df)

ロバストスケーリング(Robust Scaling)

ロバストスケーリングは、データの中央値と四分位範囲に基づいてスケーリングする手法です。外れ値に対して頑健なスケーリングが可能です。

from sklearn.preprocessing import RobustScaler

# ロバストスケーリング
scaler = RobustScaler()
scaled_df = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)
print(scaled_df)

正規化(Normalization)

正規化は、各データポイントのL2ノルム(ユークリッド距離)が1になるようにスケーリングする手法です。主にテキストデータの処理やクラスタリングに使用され、異常値の影響を抑えたり、モデルの学習を安定化させる効果があります。

from sklearn.preprocessing import Normalizer

# 正規化
scaler = Normalizer()
scaled_df = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)

print(scaled_df)

分布の調整・非線形変換

分布の調整や非線形変換を行うことで、データの性質を整え、モデルの学習や予測精度を向上させることができます。

  • 過学習の抑制
    一部の特徴量が極端に大きいと、モデルがそれに過度に適応し、一般化性能が低下するリスクがあります。適切な変換を施せば、よりロバスト(堅牢)な予測が可能になります。
  • モデルの前提を満たしやすくなる
    多くの統計モデルは、データが正規分布に近いほうが適切に機能します。例えば、対数変換やBox-Cox変換を使えば、分布の歪みを補正し、モデルの信頼性を高められます。
  • 学習の効率化
    勾配降下法を使うモデル(線形回帰・ロジスティック回帰・ニューラルネットワークなど)は、特徴量のスケールが異なると学習が遅くなることがあります。適切な変換を行うことで、より速く収束する可能性があります。
  • 特徴量のバランス調整
    モデルは値の大きい特徴量を優先しがちですが、スケーリングを行うことで全ての特徴量を同じ尺度で扱い、モデルが偏りなく学習できるようになります。

対数変換(Log Transformation)

対数変換は、データの値が大きくなるほど変動も大きくなる場合に適用されます。大きな値の影響を抑え、小さな値の変化を強調することで、分布を正規分布に近づける効果があります。

import numpy as np

# 対数変換
df_log = np.log(df + 1)  # ゼロ値対策で1を加算
print(df_log)

平方根変換(Square Root Transformation)

平方根変換は、特徴量の分布を調整し、大きな値の影響を和らげます。対数変換ほど強い影響はありませんが、急激な変化を緩和し、モデルの安定性を向上させる効果があります。

import numpy as np

# 平方根変換
df_sqrt = np.sqrt(df)
print(df_sqrt)

Box-Cox変換、Yeo-Johnson変換

Box-Cox変換はデータの歪みを修正し、正規分布に近づけることを目的とした変換手法です。Yeo-Johnson変換は負の値にも対応可能で、幅広い種類の連続値データに適用できます。

from sklearn.preprocessing import PowerTransformer

# Box-Cox変換(正の値のみ)
scaler_boxcox = PowerTransformer(method='box-cox')
df_boxcox = scaler_boxcox.fit_transform(df[df > 0])  # Box-Coxは正の値のみ適用可能

# Yeo-Johnson変換(負の値も対応)
scaler_yeo = PowerTransformer(method='yeo-johnson')
df_yeo = scaler_yeo.fit_transform(df)

print(df_boxcox)
print(df_yeo)

新しい特徴量の生成(単一)

既存の特徴量から情報を抽出し、新しい特徴量を作成することで、モデルの予測性能を向上させることができます。

新しい特徴量の生成は、データの情報量を増やし、モデルの表現力を向上させることができます。ただし、過剰な特徴量は過学習を引き起こす可能性があるため、慎重に生成する必要があります。

手法名説明効果適用例
統計量平均、中央値、分散、標準偏差、最大値、最小値など、データセット全体の統計的な特性を捉えます。データの全体的な傾向、ばらつき、分布の形状などを数値で表現し、モデルの理解を助けます。数値データ全般、EDA(探索的データ分析)
移動平均過去の一定期間のデータの平均値を順次計算します。急激なノイズ変動を平滑化し、データの長期的なトレンドや周期性を捉えやすくします。異常値の検出にも利用できます。株価データ、気温データ、センサーデータなどの時系列データ
累積和データの開始時点からの累計値を計算します。時間経過に伴う累積的な変化を可視化し、長期的なトレンドや特定の時点での異常な増減を捉えるのに役立ちます。売上データ、エネルギー消費量、感染者数などの時系列データ
日付・時間特徴量年、月、日、曜日、時間、祝日フラグ、季節など、日付や時間に関する情報を抽出します。時系列データの周期性(日次、週次、月次、年次)、季節変動、曜日による影響などをモデルに組み込むことができます。売上予測、アクセスログ分析、イベント予測などの時系列データ
ラグ特徴量 (遅延特徴量)過去の時点のデータの値を現在の特徴量として追加します。時系列データにおける過去の依存関係(自己相関)をモデルに明示的に組み込むことで、予測精度を向上させることができます。株価予測、需要予測、センサーデータの異常検知などの時系列データ
周波数領域の特徴量時系列データをフーリエ変換などを用いて周波数成分に分解し、特定の周波数の強さなどを特徴量とします。データに潜む周期的なパターンやノイズの特性を捉えることができます。音声データ解析、振動解析、心電図データなどの周期性を持つ時系列データ
自己相関特徴量時系列データ自身の過去のデータとの相関の強さを計算します。データの時間的な依存構造を把握し、将来の値を予測する手がかりや、異常なパターンを検出するのに役立ちます。金融時系列データ、センサーデータなどの自己相関が強い時系列データ
エンベロープ信号の振幅の変動を滑らかに繋いだ曲線を抽出します。振動データや音声データにおいて、信号全体のエネルギーの変化や特徴的なパターンを捉えることができます。機械の故障診断、音声認識、音楽解析などの振動・音響データ
多項式特徴量既存の数値特徴量を2乗、3乗したり、複数の特徴量を掛け合わせたりして新たな特徴量を生成します。線形モデルに非線形な関係性を学習させる能力を与え、より複雑なデータパターンを捉えることができます。回帰分析、分類分析など、数値データを用いる幅広いタスク
ヒストグラム特徴量数値データの分布をヒストグラムとして表現し、その各ビンの値を特徴量として利用します。データの分布形状をモデルに伝えることができ、外れ値の影響を受けにくいロバストなモデル構築に役立つことがあります。数値データ全般、特に分布の形状が重要な情報を持つ場合
カテゴリカル特徴量のエンコーディング文字列などのカテゴリカルデータを、数値表現に変換します(例:One-Hot Encoding, Label Encodingなど)。機械学習モデルは一般的に数値を入力として扱うため、カテゴリカルデータをモデルに入力できるようにします。名義変数、順序変数などのカテゴリカルデータ
テキスト特徴量の変換テキストデータを単語の出現頻度ベクトル(Bag-of-Words, TF-IDFなど)や、より高度な埋め込み表現(Word Embeddingsなど)に変換します。テキストデータを機械学習モデルが処理できる数値ベクトル形式に変換し、自然言語処理タスクを可能にします。テキスト分類、感情分析、情報検索などのテキストデータ

ドメイン知識を活用

業界特有の知識を用いて新しい特徴量を作成します。例えば、生産ラインごとの週毎の稼働パターンやシフトの組み合わせ、作業員のスキルレベル、機械ごとの故障回数などが考えられます。

統計的な特徴量

平均、中央値、分散、最大値、最小値などの統計量を新たに計算して特徴量として追加します。

import pandas as pd

# サンプルデータ
data = {'product_id': [1, 2, 3, 4, 5],'production': [100, 150, 120, 180, 200]}
df = pd.DataFrame(data)

# 統計的な特徴量の追加
df['mean_production'] = df['production'].mean()  # 平均
df['median_production'] = df['production'].median()  # 中央値
df['variance_production'] = df['production'].var()  # 分散
df['max_production'] = df['production'].max()  # 最大値
df['min_production'] = df['production'].min()  # 最小値

print(df)

移動平均による特徴量生成

時系列データに対して、過去の値の平均を計算することで、急激な変動を滑らかしに、トレンドを捉えることができます。また、短期的なノイズの除去や異常値(移動平均から外れた急激な変動)を際立たせるという効果もあります。

import pandas as pd

# サンプルデータ
data = {'date': pd.date_range(start='2023-01-01', periods=10),
        'value': [100, 102, 101, 105, 108, 107, 110, 115, 113, 118]}
df = pd.DataFrame(data)

# 移動平均の計算(3日間の移動平均)
df['moving_average_3'] = df['value'].rolling(window=3).mean()

print(df[['date', 'value', 'moving_average_3']])

累積和による特徴量生成

累積和は、時系列データの過去から現在までの値を順次足し合わせることで計算されます。この特徴量を使用すると、データの累積的な変動を視覚化し、長期的なトレンドや異常を捉えることができます。異常検知では、累積的な変化が突然大きくなる部分が異常として検知されることがあります。

import pandas as pd

# サンプルデータ
data = {'date': pd.date_range(start='2023-01-01', periods=10),
        'value': [100, 102, 101, 105, 108, 107, 110, 115, 113, 118]}
df = pd.DataFrame(data)

# 累積和の計算
df['cumulative_sum'] = df['value'].cumsum()

print(df[['date', 'value', 'cumulative_sum']])

日付・時間の特徴量

日時データから年、月、日、曜日を取り出して新たな特徴量にする、春夏秋冬や朝昼夜などの期間でサマリして特徴量とすることが考えられます。

ラグ特徴量 (遅延特徴量)

時系列データからラグ特徴量を生成することで、時系列パターンをモデルに取り入れます。

import pandas as pd

# サンプルデータ
data = {'date': pd.date_range(start='2022-01-01', periods=5),
        'value': [10, 20, 30, 40, 50
df = pd.DataFrame(data)

# ラグ特徴量の生成
df['lag_1'] = df['value'].shift(1)
df['lag_2'] = df['value'].shift(2)

print(df)

周波数領域の特徴量生成

時系列データなどでは、データを周波数領域に変換することで、周期的なパターンやノイズを捉えることができます。フーリエ変換(FFT: Fast Fourier Transform)を使用して、周波数成分を特徴量として抽出することができます。

import numpy as np
import pandas as pd

# サンプルデータ(時系列データ)
data = {'time': np.arange(0, 10, 0.1),
        'value': np.sin(np.arange(0, 10, 0.1) * 2 * np.pi) + np.random.randn(100) * 0.1}
df = pd.DataFrame(data)

# フーリエ変換による周波数特徴量の生成
fft_values = np.fft.fft(df['value'])  # FFTを実行
fft_amplitude = np.abs(fft_values)  # 振幅を計算
fft_phase = np.angle(fft_values)  # 位相を計算

df['fft_amplitude'] = fft_amplitude[:len(df)]  # 振幅特徴量を追加
df['fft_phase'] = fft_phase[:len(df)]  # 位相特徴量を追加

print(df[['value', 'fft_amplitude', 'fft_phase']].head())

自己相関の特徴量生成

自己相関(Autocorrelation)は、時系列データ内のある時点のデータとその過去のデータとの相関を調べます。自己相関が強い場合、過去のデータが現在のデータに影響を与えていることを示唆します。異常検知では、通常の自己相関パターンから外れる異常値を検知できます。

import pandas as pd
import numpy as np

# サンプルデータ(時系列データ)
data = {'date': pd.date_range(start='2022-01-01', periods=100),
        'value': np.sin(np.arange(0, 100) * 0.1) + np.random.randn(100) * 0.1}
df = pd.DataFrame(data)

# 自己相関特徴量の生成(ラグ1)
df['autocorr_1'] = df['value'].rolling(window=2).apply(lambda x: x.autocorr(), raw=False)

print(df[['value', 'autocorr_1']].head())

エンベロープによる特徴量生成

信号の振幅変動を捉えるためにエンベロープを計算する手法です。エンベロープは、信号のピーク値をなぞるように、信号の上限や下限を表します。このエンベロープが一定範囲を超えた場合、その部分を異常として検知できます。特に振動データや音声データの解析に有効です。

import numpy as np
import pandas as pd
from scipy.signal import hilbert

# サンプルデータ(振動データを想定)
data = {'time': np.linspace(0, 1, 500), 'signal': np.sin(2 * np.pi * 5 * np.linspace(0, 1, 500))}
df = pd.DataFrame(data)

# ヒルベルト変換を使用してエンベロープを計算
analytic_signal = hilbert(df['signal'])
envelope = np.abs(analytic_signal)

df['envelope'] = envelope

print(df[['time', 'signal', 'envelope']])

ヒストグラム特徴量による特徴量生成

データの分布をヒストグラムとして表現し、その分布の形状を特徴量として扱う手法です。通常のデータは特定の分布に従うことが多く、異常はその分布から外れた箇所に現れる可能性があります。ヒストグラムを使って、データの頻度や分布を視覚化し、異常を検出します。

import pandas as pd
import numpy as np

# サンプルデータ
data = np.random.normal(loc=50, scale=10, size=1000)  # 正規分布に従うデータ
df = pd.DataFrame(data, columns=['value'])

# ヒストグラム特徴量の計算(10個のビンに分割)
hist, bin_edges = np.histogram(df['value'], bins=10)

# ヒストグラムの結果をデータフレームに変換
hist_df = pd.DataFrame({'bin_edges': bin_edges[:-1], 'frequency': hist})

print(hist_df)

多項式特徴量の追加

既存の特徴量から2乗、3乗したり、複数の特徴量を掛け合わせ多項式特徴量を生成することで、非線形関係をモデルに組み込むことができます。

from sklearn.preprocessing import PolynomialFeatures
import pandas as pd

# サンプルデータ
data = {'x': [1, 2, 3, 4, 5]}
df = pd.DataFrame(data)

# 多項式特徴量の追加
poly = PolynomialFeatures(degree=2)
poly_features = poly.fit_transform(df[['x']])
poly_df = pd.DataFrame(poly_features, columns=poly.get_feature_names(['x']))

print(poly_df)

カテゴリカル特徴量のエンコーディング

カテゴリカル特徴量をエンコーディングし、数値特徴量に変換することで、モデルに適用しやすくします。

pythonコードをコピーするfrom sklearn.preprocessing import OneHotEncoder
import pandas as pd

# サンプルデータ
data = {'category': ['A', 'B', 'C', 'A', 'B']}
df = pd.DataFrame(data)

# ワンホットエンコーディング
encoder = OneHotEncoder()
encoded_features = encoder.fit_transform(df[['category']]).toarray()
encoded_df = pd.DataFrame(encoded_features, columns=encoder.get_feature_names_out(['category']))

print(encoded_df)

テキスト特徴量の変換

テキスト特徴量から情報を抽出し、新しい数値特徴量を生成することで、テキストデータをモデルに適用しやすくします。

pythonコードをコピーするfrom sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd

# サンプルデータ
documents = ["Machine learning is great", "Natural language processing with machine learning"]
df = pd.DataFrame({'text': documents})

# TF-IDF特徴量の生成
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(df['text'])
tfidf_df = pd.DataFrame(tfidf_matrix.toarray(), columns=vectorizer.get_feature_names_out())

print(tfidf_df)

新しい特徴量の生成(複数)

相関による特徴量生成

相関は、2つの変数の関係を示す指標です。異常検知では、複数の特徴量の間で強い相関関係がある場合、相関関係が崩れた際に異常が発生しているとみなすことができます。特徴量間の相関を調べることで、冗長な特徴量を削減し、モデルの精度を向上させることも可能です。

import pandas as pd

# サンプルデータ
data = {'feature1': [100, 102, 101, 105, 108],
        'feature2': [10, 20, 30, 40, 50]}
df = pd.DataFrame(data)

# 相関係数の計算
correlation_matrix = df.corr()

print(correlation_matrix)

主成分分析(PCA: Principal Component Analysis)

主成分分析(PCA)は、複数の特徴量を少数の代表的な成分に圧縮する手法です。元のデータの分散をできる限り保持しながら、次元を削減します。同時に、ノイズを減らし、モデルのパフォーマンスを向上させる効果が期待できます。
異常検知では、通常のデータから外れた成分が異常を示す可能性があります。

from sklearn.decomposition import PCA
import pandas as pd

# サンプルデータ
data = {'feature1': [100, 102, 101, 105, 108],
        'feature2': [10, 20, 30, 40, 50],
        'feature3': [200, 210, 215, 220, 225]}
df = pd.DataFrame(data)

# 主成分分析の適用
pca = PCA(n_components=2)  # 2つの主成分に圧縮
pca_result = pca.fit_transform(df)

# 結果をデータフレームに変換
pca_df = pd.DataFrame(pca_result, columns=['PC1', 'PC2'])

print(pca_df)

GPS位置情報からの抽出

一般的に、GPS位置情報は緯度、経度とともに、発生日時が収集されます。この3つから、移動距離や速度、加速度、角度など、様々な特徴量が抽出できます。

下記記事では、GPSと地図のマッピングと合わせて、機械学習で有効な特徴量を抽出する方法について解説しています。

あわせて読みたい
【Python実践】GPS位置情報で車両の軌跡を分析しよう! 工場で使用されるフォークリフトでは、稼働率の把握や経路の最適化を行うために、GPSなどの位置情報を利用することがあります。また、建設や農業で使用される特殊車両で...

まとめ

特徴量エンジニアリングは、機械学習モデルの性能向上に不可欠です。適切な特徴量の選択、変換、生成が行われることで、モデルの予測性能が向上します。

本記事では、特徴量エンジニアリングの手順としては次の3つを内容を、サンプルプログラムを交えて紹介しました。

  1. 特徴量の選択
  2. 特徴量のスケーリング
  3. 新しい特徴量の生成

新しい特徴量の生成は、データの情報量を増やし、モデルの表現力を向上させることができますが、過剰な特徴量は過学習を引き起こす原因にもなりますのでご注意ください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次