よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

【Pandas】カテゴリカルデータのダミー変数化(one-hot)する pandas.get_dummies()

Pandasを使って文字列のカテゴリーデータを「ダミー変数化」または「one-hotエンコーディング」と呼ばれる0か1に変換する方法。
pandas.get_dummies()を使います。簡単。

はじめに

前回は、sklearnに付属するアヤメの分類データを使って、アヤメの種類の正解ラベルが文字列表記されたカテゴリーデータを数値化する方法をやりました。超簡単便利。応用でいろいろ使えそうです。
【Pandas】文字列のラベルを自動で数値化するpd.factorize(文字列配列) - よちよちpython



そのデータのアヤメの種類は3種類で、sklearn付属のものはそれぞれ0、1、2と番号で割り振ってある。数値は文字列のカテゴリカルデータを便宜上数字に置き換えているだけであり、本来は数字の大小は意味しないのですが、機械学習分類モデルによっては数値の大小が分類精度に関わる場合がある。

そこで、前処理として、カテゴリーデータを0か1だけで表現する方法が今回のダミー変数化です。

実行環境

  • Androidスマホ
  • Termux
  • Jupyter Notebook6.4.0
  • Python3.9.6
  • 外部ライブラリ
    • Pandas



データの表示

sklearn付属のアヤメの分類データで、正解ラベル(アヤメの種類)は既に0,1,2と数値化されていたと思います。
今回使うデータはネットからダウンロードしたもので、文字列で表記されております。表示します。

import pandas as pd

# アヤメのデータ (ネットからダウンロードしたもの
fname = "iris.csv"

# csvを開く
df = pd.read_csv(fname)
df
sepal.length sepal.width petal.length petal.width variety
0 5.1 3.5 1.4 0.2 Setosa
1 4.9 3.0 1.4 0.2 Setosa
2 4.7 3.2 1.3 0.2 Setosa
3 4.6 3.1 1.5 0.2 Setosa
4 5.0 3.6 1.4 0.2 Setosa
... ... ... ... ... ...
145 6.7 3.0 5.2 2.3 Virginica
146 6.3 2.5 5.0 1.9 Virginica
147 6.5 3.0 5.2 2.0 Virginica
148 6.2 3.4 5.4 2.3 Virginica
149 5.9 3.0 5.1 1.8 Virginica

150 rows × 5 columns

一番右の列「variety」はアヤメの種類名が文字列で入っている。1列で表されています。

種類名を確認しておきます。

# variety列のユニーク(アヤメの種類名
print(df["variety"].unique())

# variety列のユニーク数
print(df["variety"].nunique())
['Setosa' 'Versicolor' 'Virginica']
3

3種類。文字列。



カテゴリカルデータのダミー変数化(one-hot エンコーディング)

分類の正解ラベル(目的変数)となる「variety」列は1列です。これをダミー変数化すると、種類と同じ数の列に置き換えられます。つまり3列になる。
pd.get_dummies()を使います。



その前に、簡単な例で練習。

# リスト(適当
arr = "卵 牛乳 小麦粉 砂糖".split()

# データフレームで表示
pd.DataFrame(arr)
0
0
1 牛乳
2 小麦粉
3 砂糖

一列です。ダミー変数化すると、↓のように増えます。

# ダミー変数化
pd.get_dummies(arr)
小麦粉 牛乳 砂糖
0 1 0 0 0
1 0 0 1 0
2 0 1 0 0
3 0 0 0 1

0か1で表された。その代わり、列が増えた。4種類あるので4列です。
1になっている時はその列のカラム名が指す種類であることを示しています。

しかし、もし卵以外が0なら確実に卵は1になると分かりますので、列を1つ減らせる。pd.get_dummies()の引数でdrop_first=Trueを指定すると出来る。

# ダミー変数化
pd.get_dummies(arr, drop_first=True)
小麦粉 牛乳 砂糖
0 0 0 0
1 0 1 0
2 1 0 0
3 0 0 1

「卵」列が消えてしまった。だが卵である場合の表現はこれだけで出来る。
「小麦粉」「牛乳」「砂糖」が0なら、残る「卵」が確実に1だと分かる。

では本番、ダウンロードしたアヤメのデータでやります。

# ダミー変数化
pd.get_dummies(df)
sepal.length sepal.width petal.length petal.width variety_Setosa variety_Versicolor variety_Virginica
0 5.1 3.5 1.4 0.2 1 0 0
1 4.9 3.0 1.4 0.2 1 0 0
2 4.7 3.2 1.3 0.2 1 0 0
3 4.6 3.1 1.5 0.2 1 0 0
4 5.0 3.6 1.4 0.2 1 0 0
... ... ... ... ... ... ... ...
145 6.7 3.0 5.2 2.3 0 0 1
146 6.3 2.5 5.0 1.9 0 0 1
147 6.5 3.0 5.2 2.0 0 0 1
148 6.2 3.4 5.4 2.3 0 0 1
149 5.9 3.0 5.1 1.8 0 0 1

150 rows × 7 columns

pd.get_dummies()の引数にデータフレーム全体を渡しました。
元々数値化された列はそのままで、「variety」1列だけが「varietyナンチャラ」の3列に変わった。

上でやったようにdrop_first=Trueで1つ次元を減らします。

# ダミー変数化
pd.get_dummies(df, drop_first=True)
sepal.length sepal.width petal.length petal.width variety_Versicolor variety_Virginica
0 5.1 3.5 1.4 0.2 0 0
1 4.9 3.0 1.4 0.2 0 0
2 4.7 3.2 1.3 0.2 0 0
3 4.6 3.1 1.5 0.2 0 0
4 5.0 3.6 1.4 0.2 0 0
... ... ... ... ... ... ...
145 6.7 3.0 5.2 2.3 0 1
146 6.3 2.5 5.0 1.9 0 1
147 6.5 3.0 5.2 2.0 0 1
148 6.2 3.4 5.4 2.3 0 1
149 5.9 3.0 5.1 1.8 0 1

150 rows × 6 columns

「variety_Setona」が消え、3種類が2列で表現された。簡単でした。



おわりに

使用したデータは「variety」列だけが文字列の、しかもたった3種類のカテゴリカルデータだったので、ダミー変数化しても列はそれほど増えませんでした。
しかし、もしカテゴリーの数がもっと多く、さらに説明変数にもカテゴリカルデータが含まれその種類も多いとなれば、その分だけ計算量が爆発的に増加する。

たとえは、タイタニックの乗客の生存率を予測する時に使うデータでは、「性別」「客室のグレード」「客室の場所」「出身地」などの文字列カテゴリーデータを含みます。これらは体脂肪率や避難の優先度、身体能力、避難のしやすさ、などに関わる と考えられる。
このような要素とカテゴリー数が増えれば増えるほど特徴量も爆増し、計算量も増える。

果たしてそのデータは予測モデルの精度を上げる為に必要か、計算量をどうしたら削減できるか、といったことを考えるのが「特徴量エンジニアリング」というもののようです。機械学習アルゴリズムの深い理解と共にデータ内容のドメイン知識や分析目的の理解も要求されるようで非常に難解。読んでもわからん ( ;∀;)



燃料や電気代の値上がりの話がありますけど、コロナの分析みたいな 「不毛」とクラスタリングされた分野のデータ分析にコンピューターパワーを使えなくなってくるのかも…と思ったり。

以上です。