# カテゴリデータ
- 参考
  - [機械学習のための特徴量エンジニアリング――その原理とPythonによる実践](https://www.oreilly.co.jp/books/9784873118680/)
  - [5.3.4. Encoding categorical features](https://scikit-learn.org/stable/modules/preprocessing.html#encoding-categorical-features)
  - [Category Encoders](https://contrib.scikit-learn.org/category_encoders/)

---
## 達成目標
- （同じデータセットであったとしても、タスク毎に適切な特徴量は異なることを理解する。）
- カテゴリデータに対する前処理の意義を理解する。
- 前処理のいくつかの手法を適用し、特徴空間の可視化による比較や、学習結果の比較から前処理の妥当性について検討することができる。

---
## カテゴリカルデータと主な問題
- カテゴリデータとは？
  - 下記例のように、カテゴリとして表現できるデータのこと。
    - 出身地は？
    - 利用しているOSは？
    - 好きな映画のジャンルは？
- カテゴリデータがあるとどういう問題がある？
  - 数値データであれば、[ユークリッド距離](https://ja.wikipedia.org/wiki/ユークリッド距離)等を用いることで距離を計測することができる。距離がわかるなら、各サンプルがどれだけ近いのか（≒似ているのか）を判断することができる。距離（距離空間）を利用したいからこそ、特徴ベクトルを数値データで記述している。
  - これに対してカテゴリデータの場合、例えばニュース記事のジャンルとして「政治」と「スポーツ」があったとき、それらの距離はどう測ればよいだろうか？
    - より具体的な状況としては、データセットとして「1つ目の記事（サンプル）は政治に関する記事である」「2つ目の記事はスポーツに関する記事である」という関連情報をタグとして用意しておき、タグを対応表で表現することが多い。例えば政治を1、スポーツを2としておくといったように。この場合、データセット上ではあたかも数値であるようにみえるが、「政治とスポーツの距離は1」というのはどのぐらい妥当だろうか？
    - 上記例のようにな「便宜上の数値」は、実際にはカテゴリとして使っているだけであり、そのまま距離空間として利用するのは不適切である。

---
## 基本的な変換方法

(one-hot-encoding)=
### One-Hot表現（One-Hot encoding）。
- 例えば3つのカテゴリがあるならば、それぞれのカテゴリに属しているか否かを 0 or 1 で記述するために、3つの特徴（3次元の特徴）を用意しよう。その上で、実際に属しているカテゴリのみ1とし、それ以外を 0 とする。
  - One-Hot表現を拡張した表現方法として、[ダミーコーディング（dummy coding）](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.get_dummies.html)や[Effectコーディング（Effect coding）](https://stats.idre.ucla.edu/other/mult-pkg/faq/general/faqwhat-is-effect-coding/)、[バイナリコーディング(Binary docing)](https://contrib.scikit-learn.org/category_encoders/binary.html)があり、特徴は異なるものの基本的な考え方は一緒。
- 利点
  - カテゴリの違いを明示的に表現できる。
- 欠点
  - 全てのカテゴリ間距離が等距離にあることを仮定している。他にも類似コーディング方法があるが、基本的には同じ特徴を有する。（問題にならないことも勿論ある。タスク次第。）
  - カテゴリ数が膨大な場合、それだけ特徴ベクトルの次元数が増加してしまう。

---
### 特徴量ハッシング（Fature hashing）
- [ハッシュ関数](https://en.wikipedia.org/wiki/Hash_function)とは、任意種類のデータ（メモリが許す限り無限種類のデータ）を、指定サイズに収納するためのマップ関数。良くも悪くもハッシュ関数とテーブルサイズ次第で傾向が大きく変わる。
  - 利点
    - どれだけ膨大なカテゴリ数であったとしても、特徴量を特定次元数に圧縮することが可能。
  - 欠点
    - 一つの特徴に複数のカテゴリが割り当てられるため、その特徴に関する解釈が困難になる。

---
### BaseNエンコーディング
- [BaseNエンコーディング](http://www.willmcginnis.com/2016/12/18/basen-encoding-grid-search-category_encoders/)
  - N進数表記へ変換。一種の特徴量ハッシングともいえる。利点欠点も同一。
    - カテゴリ数が10で、base=2なら、各カテゴリに0000〜1010を割り当てる。
  - base=1のときは、One-Hot コーディングと一緒。
  - base=2のときは、バイナリコーディングと一緒。
  - base=3のときは、0〜2でコーディング。

---
### Weight of Evidence coding
- [Weight of Evidence coding](https://www.listendata.com/2015/03/weight-of-evidence-woe-and-information.html)
- カテゴリ情報をエビデンスに基づいた統計量に置き換える。一般的には、2値化されたターゲット変数から、WOE（Weight of Evidence）を求める。これは条件付き確率ともみなせる。
  - 利点
    - カテゴリをエビデンスに基づいた1次元の連続値として扱えるため、次元数の観点からも距離の観点からも扱いやすい。
  - 欠点
    - エビデンスを「モデルの出力（予測したい結果）」として設定せざるを得ないことが多く、その場合には結果を教えている（情報のリーク）ことになり、未知データに対する予測が困難（劣化しやすい傾向）となる。
      - [What is Data Leakage](https://www.kaggle.com/dansbecker/data-leakage)
      - エビデンス集計データ、学習データ、テストデータをそれぞれ分けてしまうことである程度リークを防ぐことも可能。
    - 全く異なるカテゴリがたまたたま同じ値となることがゼロではないため、その特徴に関する解釈が困難になることがある。

---
### カテゴリ情報を数値評価して利用する
これまでに紹介したアプローチは、基本的にはカテゴリ情報を直接処理対象としているため、必然的に過度な制約が課されていることが多い。例えばone-hotエンコードでは「あらゆる単語を等間隔で配置する」という大前提の元でベクトル化される。これはあまりにも強い制約であり、例えば *犬*, *動物*, *車* は全て等距離となるように配置される。これに対して、犬は動物の一種であるという点では ``distance(犬,動物) < distance(犬,車)`` となるように配置されて欲しいはずだ。つまり等距離空間ではなく、適度に潜在的意味を考慮した空間で表現したいはずだ。

WOEは使い方次第では潜在的意味を加味した空間に写像できるが、一方でエビデンスをモデルの出力に頼る場合にはリークになり得る。逆に、モデル出力に頼らないエビデンスを用いてWOEを使うことができれば、それはリークにはならない適切な利用となる。しかし、それはWOEの前提と矛盾している。これを避ける一つのアプローチとして、カテゴリ情報を他の外部データや印象評価等に基づき数値として表現する方法がある。ただし画一的なアプローチではないため例を上げて検討する形で示すこととする。

例えば気象庁から[那覇市の2021年4月の気象情報](http://www.data.jma.go.jp/obd/stats/etrn/view/daily_s1.php?prec_no=91&block_no=47936&year=2021&month=4&day=&view=p1)を参照すると、カテゴリ情報は「風向」と「天気概況」の2項目がある。

風向については、[数値データで出てきた相対的かつ周期的な値として取り上げた方角情報](https://ie.u-ryukyu.ac.jp/~tnal/2021/dm/static/3-feature-engineering/preprocess-number.html#id7)である。このため、北を基準とした角度で表現した後に $cos(\theta)$ で表現すると良いだろう。

天気概況については文章にも見えるが、素直にテキストをカテゴリ名と解釈することもできるし、「曇」「晴」「雷」「時々」「伴う」といったテキスト構成要素をカテゴリ名と解釈することもできるだろう。後者の場合には次のように表現できるだろう。これだけでも前者の「テキストをカテゴリ名と解釈」とした場合と比べると、複数カテゴリの組み合わせで表現しているため「似ている天候」を汲み取りやすくなっている。

| 日 | 曇 | 雨 | 晴 | 雷 | 時々 | 伴う |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| 1 | 1 | 1 | 0 | 1 | 1 | 1 |
| 2 | 1 | 1 | 1 | 1 | 0 | 1 |
| 3 | 1 | 1 | 0 | 0 | 0 | 0 |
| 4 | 1 | 0 | 0 | 0 | 0 | 0 |

別例として「小売店への入店客数」を推定したい状況を考えてみよう。過去数年分の入店客数、POSデータといった直接小売店が保有する独自データに加えて、先程用いた気象データも用いるとしよう。気象データを用いようと考えたのは、天候の良し悪しが外出に影響を与えるという経験則に基づいているからだ。ここで経験則から「晴れや曇りの日を基準とすると、雨・雷の日は70%ぐらいに落ちるかな」といった仮設を立て、それを元に数値化しよう。そうすると1次元特徴量（スカラー）として表現でき、かつ、自身の想定する距離を意図的に盛り込むことが可能となる。主観的すぎることが気がかりならば、目的に合致したユーザに対してアンケート調査を実施しそこから数値化するのも良いだろう。これが「カテゴリ情報を数値評価して利用する」アプローチだ。

```{tip}
数値に置き換えることができれば、それをクラスタリング等を通した **ベクトル量子化（vector quantization）** により新たな特徴量として表現することも可能である。
- 参考
  - [ベクトル量子化](http://ibisforest.org/index.php?ベクトル量子化)
  - [ソフテックだより > 第１６５号（2012年7月4日発行） 技術レポート「ベクトル量子化を用いた情報圧縮」](https://www.softech.co.jp/mm_120704_pc.htm)
  - [Pythonで単語分散表現のクラスタリング](https://hironsan.hatenablog.com/entry/clustering-word-vectors)
```

---
### カテゴリデータに対する前処理コード例
- [preprocess_categorical.ipynb](./preprocess_categorical.ipynb)

---
## 実データにおけるよくある状況
- レアなカテゴリの存在。
  - 対応策1：[バックオフ（back-off）](https://lucasxlu.github.io/blog/2018/08/20/ml-feml/#What-about-rare-categories)
    - レアなカテゴリ群をまとめて一つのカテゴリとして扱う。まとめすぎることもあるが、該当サンプルを無視せずにまとめて集計利用することで、ある程度の情報を特徴量として活用。
  - 対応策2：特徴量ハッシングやBaseNコーディング等で圧縮する。
    - [Count-min sketch](https://en.wikipedia.org/wiki/Count–min_sketch)等、派生手法も多々。
    - レアカテゴリのみを圧縮するのも手。
- 継続運用に伴い、不要カテゴリの出現や、発散するカテゴリの出現。
  - この文脈における発散とは、爆発的な流行等により同カテゴリの出現回数が際限なく増えていくさまを指している。要因切り分けした対応が必要となることがほとんど。
  - 対応例
    - 該当カテゴリだけに特化したモデルを別に用意する。
    - [数値データの前処理](./preprocess-number.md)のように、出現回数を前処理してしまう。
    - 1日〜数時間等、短いスパンで学習し直したモデルを利用する。（様々な自動化が必須）

---
## 演習
- 課題レポート1で取り上げたデータセットについて、以下のことに取り組め。
  - Level 1. [preprocess_categorical.ipynb](./preprocess_categorical.ipynb)を参考に、何か2つ以上の特徴に対して前処理を施せ。なお、選択理由についても検討すること。
    - 例えば、one-hotコーディングとbinaryコーディングを選んだのであれば、その理由は何故か？
  - Level 2. 2種類のコーディング方法で、どのように変わっているか、確認しやすいように出力せよ。出力手法は問わない。
  - Level 3. 2種類のコーディングで分類タスクを実行せよ。結果を比較し、考察せよ。
