大規模特徴量エンジニアリング(実践編)

[大規模特徴量エンジニアリング](https://qiita.com/taka_yayoi/items/ad7b119d995fb178e2de)で紹介されているノートブックを実際にウォークスルーした内容です。

ノートブックの日本語訳はこちらからアクセスできます。

https://github.com/taka-yayoi/public_repo/tree/main/feature_engineering_at_scale

# ノートブックの構成

[サンプルノートブック\(DBC形式\)](https://databricks.com/notebooks/feature_engineering_at_scale.dbc)をDatbricksワークスペースにインポートすると以下のフォルダ構成となります。

:::note info
**注意**
ノートブックのインポート方法に関しては、[こちら](https://qiita.com/taka_yayoi/items/c306161906d6d34e8bd5#%E3%83%8E%E3%83%BC%E3%83%88%E3%83%96%E3%83%83%E3%82%AF%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88)を参照ください。
:::

![Screen Shot 2022-06-02 at 12.41.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/37771c02-2221-13b4-dbbd-d3dc6f0b0cab.png)

# データの準備

最初にノートブック`tpcds_datagen`を用いてTPC-DSデータを準備します。

このノートブックは`park-sql-perf`ライブラリ(https://github.com/databricks/spark-sql-perf )を用いてTPC-DSデータを生成します。

このライブラリのパッケージング済みのバージョンは https://github.com/BlueGranite/tpc-ds-dataset-generator/tree/master/lib から取得できます。

:::note info
**注意**
上のパッケージング済みのバージョン(`spark-sql-perf_2.12-0.5.1-SNAPSHOT.jar`)をクラスターライブラリとしてインストールしてください。
![Screen Shot 2022-06-02 at 12.45.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/33b71af9-a188-a698-64ae-4a56a8c4347c.png)
:::

Cmd5のファイル格納場所、Cmd6のデータベース名を指定します。

```scala:Scala
// TPC-DSデータがダウンロードされるベースディレクトリ
val base_dir = "/tmp/takaaki.yayoi@databricks.com/blog"
```

```scala:Scala
val databaseName = "taka_jumpstart_db" // 明示的に指定
```

ノートブックを実行していくことで、TCP-DSのデータベースが作成されます。

Cmd20以降でDeltaファイルに書き込みます。

```scala:Scala
// Deltaテーブルが書き込まれるパス
// これはデモ用ノートブックのソースデータとして使用するdeltaパスとなります
val store_sales_delta_path = "/tmp/takaaki.yayoi@databricks.com/sales_store_tpcds"
```

最後にZ-orderingによる最適化を行います。

```sql:SQL
%sql
-- Cmd20の値でパスを変更してください
optimize delta.`/tmp/takaaki.yayoi@databricks.com/sales_store_tpcds`
zorder by d_date, i_category
```

これでデータの準備ができました。以下のようなテーブルが作成されます。
![Screen Shot 2022-06-02 at 16.07.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/1987b2c5-2f83-623d-7e62-1af592211455.png)


# 特徴量エンジニアリング

:::note info
**注意**
MinHash計算にす要する`datasketch`をクラスターライブラリとしてインストールしてください。
![Screen Shot 2022-06-02 at 15.59.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b667f168-caf4-cb69-31c4-379fe00a1297.png)
:::

こちらでは、`core_feature_factory/demo`のノートブックを使用します。なお、`feature_store_integration`ノートブックは、`core_feature_factory/demo`で使用しているプロセスを経て生成した特徴量をDatabricks Feature Storeに格納する流れを説明しています。

## 関連クラス・関数の宣言

特徴量の元データである共通項を管理する`CommonFeatures`クラス、それから派生させた`StoreSales`クラスなどを宣言します。これによって特徴量がモジュール化されます。各自で独自の特徴量計算ロジックを実装するのではなく、これらのクラスに対して操作を加えることで特徴量を計算することになるので、計算ロジックの散逸を防ぐことができ、全ての人が共通のフレームワークで計算ロジックを実装することになります。

```
%run ./feature_dict
```

計算し増幅した特徴量をベースのデータフレームに追加する`append_features`を宣言します。

```
%run ./factory
```

平均や標準偏差を計算するヘルパー関数を宣言します。

```
%run ./functions
```

## TPC-DSデータの準備

前のステップで準備したTPC-DSデータを読み込みます。

```py:Python
# tpcds_datagenノートブックを用いて生成したdeltaテーブル/格納場所
store_sales_delta_path = "/tmp/takaaki.yayoi@databricks.com/sales_store_tpcds"
src_df = spark.table(f"delta.`{store_sales_delta_path}`")
display(src_df)
```

![Screen Shot 2022-06-02 at 16.13.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d0d5c823-bb23-8231-5502-c469aa2dfed5.png)

## 特徴量の操作

ここでは、商品カテゴリー`i_category`の`"Music", "Home", "Shoes"`と`month_id`の`200012, 200011, 200010`を掛け合わせた特徴量を計算します。

```py:Python
features = StoreSales()
# total_sales に i_category と month_id を掛け合わせて特徴量を増幅
fv_months = features.total_sales.multiply("i_category", ["Music", "Home", "Shoes"]).multiply("month_id", [200012, 200011, 200010])
# ベースのデータフレームに追加
# 以下の例ではcustomer_idでグルーピングしています
df = append_features(src_df, [features.collector], fv_months)
```

結果として、特定商品カテゴリーごと、月毎の売り上げからなる特徴量が生成されます。

![Screen Shot 2022-06-02 at 16.17.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/1f3f37ad-653b-8aa2-66ca-46cf0105d14d.png)

### One hotエンコーディング

One hotエンコーディングに関しても同様の手順で操作を行うことができます。

```py:Python
src_df = spark.createDataFrame([(1, "iphone"), (2, "samsung"), (3, "htc"), (4, "vivo")], ["user_id", "device_type"])
encode = Feature(_name="device_type_encode", _base_col=f.lit(1), _negative_value=0)
onehot_encoder = encode.multiply("device_type", ["iphone", "samsung", "htc", "vivo"])
df = append_features(src_df, ["device_type"], onehot_encoder)
```

![Screen Shot 2022-06-02 at 16.18.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/683e1add-dff5-4294-5c61-864b7a3abecb.png)

### MinHash

冒頭の[ノートブック](https://github.com/taka-yayoi/public_repo/blob/main/feature_engineering_at_scale/core_feature_factory/demo.py)にサンプルが記載されています。

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)