[素人エンジニア]がscikit-learningのEncodingを勉強した

Pythonデータ分析認定試験の合格を目指し
公式テキストを元に学習しているが表題の部分で詰まった

**この記事でやってること**
・データフレームをOneHotEncodingしたよ
・上記のエンコード済のデータをデータフレーム型に戻してカラム名を表記したよ

**環境**
python : 3.9.4
scikit-learn : 0.24.2
numpy : 1.20.2

**使用教本**
<a href="https://www.amazon.co.jp/Python%E3%81%AB%E3%82%88%E3%82%8B%E3%81%82%E3%81%9F%E3%82%89%E3%81%97%E3%81%84%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-AI-TECHNOLOGY-%E5%AF%BA%E7%94%B0-%E5%AD%A6/dp/4798158348/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=20KZ1WXN21BH6&dchild=1&keywords=python%E3%81%AB%E3%82%88%E3%82%8B%E3%81%82%E3%81%9F%E3%82%89%E3%81%97%E3%81%84%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8&qid=1620305670&sprefix=python%E3%81%AB%E3%82%88%E3%82%8B%2Caps%2C254&sr=8-1">Pythonによる新しいデータ分析の教科書</a>

**エラーの経緯**
<a href="https://www.amazon.co.jp/Python%E3%81%AB%E3%82%88%E3%82%8B%E3%81%82%E3%81%9F%E3%82%89%E3%81%97%E3%81%84%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-AI-TECHNOLOGY-%E5%AF%BA%E7%94%B0-%E5%AD%A6/dp/4798158348/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=20KZ1WXN21BH6&dchild=1&keywords=python%E3%81%AB%E3%82%88%E3%82%8B%E3%81%82%E3%81%9F%E3%82%89%E3%81%97%E3%81%84%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8&qid=1620305670&sprefix=python%E3%81%AB%E3%82%88%E3%82%8B%2Caps%2C254&sr=8-1">教本</a>p219を参考に以下のデータフレームを作成

```python
import pandas as pd
import numpy as np
df = pd.DataFrame({'A': np.arange(1,6),'B': ['a','b','c','b','c']})
df
```

sklearnを使って、B列のa,b,c,d,eでOneHotEncodeする
(文字列変数を数値データに変換したい)

```python
#データフレームのカテゴリ変数を数値化したい
from sklearn.preprocessing import LabelEncoder,OneHotEncoder

#defaultでdeep=trueなので、深い複製
df_ohe = df.copy()
#ラベルエンコーダーをインスタンス化
le = LabelEncoder()
#B列の値を数値化
df_ohe['B']=le.fit_transform(df_ohe['B'])

ohe = OneHotEncoder(categorical_features=[1])
ohe.fit_transform(df_ohe.toarray())
```
以下のエラーが発生

```python
TypeError: __init__() got an unexpected keyword argument 'ColumnTransformer'
```

**先生、LabelEncodingとOneHotEncodingの違いからわからないです。。。**
ということでまとめました。
<a href="https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.LabelEncoder.html">エンコーダーの公式ドキュメントも確認してね</a>


###**Labelエンコーダー**###
文字列の項目を数値に変換


**イメージ**

```python
#LabelEncoding
#①このようなモデルを作って
ラベル : [りんご,ごりら,らっぱ]
ラベルID : [1,2,3]
#②この配列を作る
[ごりら,ごりら,らっぱ]
#①ラベルを適用してLabelEncoding
[2,2,3]
```

###**OneHotエンコーダー**###
文字列の項目の有無を0,1で新しい列を作成

```python
#OneHotEncoding
#①このようなモデルを作る
A:[0,1,2,3,4]
B:[a,b,c,d,e]
#②このモデルをOneHotencoding
A:[0,1,2,3,4]
B_a:[1,0,0,0,0]
B_b:[0,1,0,0,0]
B_c:[0,0,1,0,0]
B_d:[0,0,0,1,0]
B_e:[0,0,0,0,1]
#列の項目のカテゴリ別に0,1の配列が作成される
#このように0が多い行列を疎行列という(<>密行列)
```

**本題**
######このエラーはなんだったのか#####

```python
#エラー
TypeError: __init__() got an unexpected keyword argument 'ColumnTransformer'
```

**原因**
教本の環境が今のバージョンと異なっており、OneHotEncoderの仕様が変わり
categorical_featuresはバージョン0.22で排除済だった

```python
#教本
scikit-learn===0.19.1
#使用する環境
scikit-learn===0.24.2
```

よって<a href="https://scikit-learn.org/stable/modules/preprocessing.html#preprocessing-categorical-features">公式例</a>を参考にして以下でOneHotEncodingを実践しました

```python
from sklearn.preprocessing import OneHotEncoder
import pandas as pd
#データフレーム作成
import numpy as np
df = pd.DataFrame({
    'A': np.arange(1,6),
    'B': ['a','b','c','b','c']
})

df_ohe = df.copy()
#特に引数はいらないみたい
ohe = OneHotEncoder()
ohe.fit_transform(df_ohe).toarray()
```

結果はscipy.sparse型の行列なので人間の私にはわかりにくい
*ちなみにOneHotEncodingのインスタンス時に'sparse = False'にするとNumpy.ndarrayの一次元配列になる*

```python
array([[1., 0., 0., 0., 0., 1., 0., 0.],
       [0., 1., 0., 0., 0., 0., 1., 0.],
       [0., 0., 1., 0., 0., 0., 0., 1.],
       [0., 0., 0., 1., 0., 0., 1., 0.],
       [0., 0., 0., 0., 1., 0., 0., 1.]])

```

####**カラム名のつけたデータフレーム型に変換して表示してみた**###
OnehotEncode型のデータを複数のカテゴリ名を持つデータフレームに変換する仕方がわからなかったので、ここではカテゴリが一つの配列をOneHotEncodingした疎行列データをデータフレームに変換します。

```python
#データの準備
from sklearn.preprocessing import OneHotEncoder
import pandas as pd
import numpy as np

df = pd.DataFrame({
    'A': np.arange(1,6),
    'B': ['a','b','c','b','c']
})
#OneHotEncoderのインスタンス化
ohe = OneHotEncoder()
#yにデータフレームのB列のndarray型の配列を代入
y = df.B.values
#yを5行1列にしたものをOneHotEncoding
#OneHotEncodingは二次元以上の配列しかできないので元々1次元のyを変換する必要があった
ohe.fit(y.reshape(-1,1))

#OneHotEncodingしたoheインスタンスをtransformでコミットしたcsr.csr_matrix型のデータをy_dataに代入
y_data = ohe.transform(y.reshape(-1,1))

#DataFrame型で再定義
#引数のデータにはy_dataをndarray型に変換したもの
#引数のカラム名はOneHotEncoder型のデータoheがCategories_として保持しているもの
y_df = pd.DataFrame(y_data.toarray(),columns=ohe.categories_)
y_df


```

**結果**
なんとかOneHotEncodeしたデータをカラム名をつけて表現できた。

![スクリーンショット 2021-05-07 22.48.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684559/885b2d8c-6a6d-b724-9d9a-9fd9b285d016.png)

####**今後調べること**####
①
疎行列で(5,1)の構造であるcsr.csr_matrix型のデータをtoarray()関数でndarray型にしたら、(5,3)の構造になったのは何故か

②
エンコード方法は調べただけでも沢山存在しているらしく、他にはどんなエンコードがどんな状況で使われるのか