Amazon SageMaker AI Data Wranglerでお手軽に特徴量エンジニアリング

## はじめに
データ分析や機械学習において、モデルの精度を向上するためにはデータを理解する探索的なデータ分析とデータの前処理や特徴量エンジニアリングが重要です。
一方で、そのような作業はデータ分析を生業とするプロフェッショナルの高度な技能とPythonのような言語に対する理解も必要だったりします。

## Amazon SageMaker AI Data Wranglerとは
Amazon SageMaker AI(以下、SageMaker)はAWSが提供するデータ分析、機械学習のプラットフォームです。
SageMakerはJupyterLabのようなNotebook形式で分析やモデル訓練が行えるツールを提供していますが、できるだけコードを書かない、所謂ノーコード・ローコードでの分析ツールも提供しています。
SageMaker Data Wranglerはノーコード・ローコードで探索的データ分析やデータの前処理、特徴量エンジニアリングを行えるツールです。
本記事ではSageMaker Data Wranglerを使用してデータ分析や前処理、特徴量エンジニアリングを行ってみます。

### SageMaker Data Wranglerでできるデータ変換の種類
SageMaker Data Wranglerでできる変換を確認しておきます。これらの組み込みデータ変換を使用すると内部的にPySparkコードが生成されます。

https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html

各変換の簡単な説明とドキュメントリンクを記載します。変換名はSageMaker Data Wranglerを使用するときの変換UIに表示されます。使い方を調べるときにご活用ください。

| カテゴリ | 変換名 | 説明 |
|:-:|:-:|:-:|
| Custom  | [Custom formula](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-custom-formula)  | Spark SQLを使用してデータフレーム内のデータをクエリして新しい列を定義する |
| Custom  | [Custom transform](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-custom)  | PySpark、Pandas、PySpark(SQL)を使用してカスタム変換を定義する  |
| Custom  | [Balance data](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-balance-data)  | ランダムオーバーサンプリング、ランダムアンダーサンプリング、SMOTEを使用してバイナリ分類におけるデータバランスをとる |
| Standard  | [Dimensionality Reduction](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-dimensionality-reduction)  | 上位K個の主成分について、ベクトルを低次元空間に射影するようにモデルをトレーニングする |
| Standard  | [Encode categorical](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-cat-encode)  | カテゴリ変数を数値またはベクトル表現に変換する |
| Standard  | [Featurize date/time](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-datetime-embed)  | 日付/時刻を数値およびベクトル表現にエンコードする<br>年、日、週などの日付から特徴を抽出する |
| Standard  | [Featurize text](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-featurize-text)  | 自然言語テキストからベクトル表現を生成する|
| Standard  | [Filter or drop rows](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-filter-data)  | 指定したパターンに一致しない行をフィルターまたは削除する  |
| Standard  | [Format string](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-format-string)  | 標準の文字列フォーマット操作を使用して、文字列をクリーンアップする  |
| Standard  | Group by<br>※ドキュメントなし  | グループ化された新しい列として集計列を追加する |
| Standard  | [Handle missing](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-handle-missing)  | 欠損値を置換、削除したりインジケータを追加する  |
| Standard  | [Handle outliers](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-handle-outlier)  | 外れ値の数値およびカテゴリ値を削除または置換する  |
| Standard  | [Handle structured column](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-flatten-column)  | JSONをフラット化し、構造化データに対して操作を実行する |
| Standard  | [Manage columns](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-manage-columns)  | データセット内の列を移動、削除、複製、名前変更する |
| Standard  | [Manage rows](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-manage-rows)  | 行の並べ替え、順序のシャッフル、重複排除、空行の削除、指定パターンに一致しない行を削除する  |
| Standard  | [Manage vectors](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-manage-vectors)  | ベクトル列を展開または作成する  |
| Standard  | [Parse column as type](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-cast-type)  | 列を新しいデータ型にキャストする |
| Standard  | [Process numeric](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-process-numeric)  | 数値を変換して機械学習モデルのパフォーマンスを向上させる |
| Standard  | [Sampling](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-sampling)  | データセットのサンプルを作成する |
| Standard  | [Search and edit](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-search-edit)  | 文字列の検索、置換、分割などの変換を行う  |
| Standard  | [Split data](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-split-data)  | データフレームを複数のデータフレームに分割する  |
| Standard  | [Time Series](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-time-series)  | 時系列を前処理および操作する |
| Standard  | [Validate string](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-validate-string)  | 標準の文字列関数を使用して文字列の形式を検証する |
| Amazon AI services  | [Transforms for Amazon Personalize](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/data-wrangler-transform.html#data-wrangler-transform-personalize)  | Amazon Personalizeのユースケースに合わせてデータセットを変換する  |

## やってみた
SageMakerドメインおよびプロファイルはあらかじめ作成しておきます。
QuickSetupを使用すると迷うことなくドメインを作成できます。

https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/onboard-quick-start.html

### 事前準備
#### SageMaker Studioの起動
SageMaker Studioを起動します。以下のような画面が立ち上がります。
![001_StartStudio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/7102569d-da62-5c29-21e4-1c00a99fef15.png)

#### SageMaker Canvasの起動
SageMaker Data WranglerはSageMaker Canvasと統合されました。
左ペインの「Data」ー「Data Wrangler」を選択して、「Run in Canvas」を押下することでインスタンスを起動します。

![002_StartCanvas.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/4ace1cef-0cc5-d506-6f94-6e03a296fc1b.png)

起動したら「Open in Canvas」でSageMaker Canvasを起動します。

![003_OpenCanvas.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/f82546ec-be64-a667-d2a4-4e29a20b04c1.png)

### 実践！特徴量エンジニアリング
Kaggleの「Titanic - Machine Learning from Disaster」のサンプルデータを使用して特徴量エンジニアリングを実施してみます。

https://www.kaggle.com/competitions/titanic

#### データのインポート
データはS3やローカルファイルの他に、PostgreSQLやMySQL、DocumentDB、Redshiftなど多種多様なデータソースからインポートできます。今回はS3からインポートします。

左ペインで「Data Wrangler」を選択し、「Import and prepare」を押下します。
CSVファイルを扱うので「Tabuler」としましょう。

![004_Import.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/9e32389c-1593-1bc0-ad78-1337c4a1d8cd.png)

「Select a data source:」からさまざまなデータソースを選択できます。
S3にファイルをアップロードしておき、CSVファイルを選択します。

![005_Import.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/3828c0cb-891a-6af0-41ef-9036c618ebba.png)

ファイルの内容がプレビューされますので、データセット名やサンプリングを設定してインポートします。

![006_Import.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/dfef86e0-3ab1-189d-80bb-9aca1c34020d.png)

#### データ型の変換
CSVファイルを取り込んだばかりのシンプルなデータフローが作成されます。
「Data types」をダブルクリックするとデータ型を変更できます。

![007_DataType.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/85fef20d-7b80-af50-00a6-c2019a834073.png)

「Survived」を「Boolean」に変更してみました。「Preview」を確認したら「Update」で反映します。

![008_DataType.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/8b57f3c3-d2c3-3774-c49a-2812da26d698.png)

#### 探索的データ分析
「Data flow」タブに戻り、「Data types」の横の「＋」ボタンから「Get data insights」を選択します。

![009_Analyze.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/805b1891-9046-3d3a-4223-ad881b2fe99f.png)

生存有無を分類するため「Target column」は「Survived」、「Problem type」は「Classification」として「Create」を押下すると、たった数秒でデータセットの概要レポートを出力してくれます。

![012_Analyze.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/a499445c-5179-f8b8-eeac-d53453c186c2.png)

データセットの統計情報

![010_Analyze.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/06995e52-0afc-159f-0f7f-4f60b9768e1a.png)

特徴のサマリ

![011_Analyze.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/3bddfbe3-b678-34f1-577c-d862a815f0de.png)

Quick Model

![013_Analyze.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/dba0388b-3817-6e8a-4f9c-666e3fcf1636.png)

各特徴の統計量

![014_Analyze.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/919e9a01-3fd7-7f17-991a-37fdb8653f57.png)

その他に、重複行の有無や異常値などを可視化してくれます。

#### データセットの変換
「Titanic competition w/ TensorFlow Decision Forests」のコードを参考に訓練用データセットを変換してみます。

https://www.kaggle.com/code/gusthema/titanic-competition-w-tensorflow-decision-forests

「Data flow」タブに戻り、「Data types」の「＋」を選択して「＋Add transform」を選択します。

![015_Transform.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/3f6b49b0-9b8d-aa81-4e6d-cfba202a879c.png)

「Data」タブに遷移したら「＋Add transform」を押下して変換ステップを追加していきます。

![016_Transform.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/9af30932-5801-d97f-e305-6058a16f7cfb.png)

「Titanic competition w/ TensorFlow Decision Forests」で実装されているデータ変換をSageMaker Data Wranglerで処理してみます。

>1.Tokenize the names. For example, "Braund, Mr. Owen Harris" will become ["Braund", "Mr.", "Owen", "Harris"].

```python:オリジナルコード
    def normalize_name(x):
        return " ".join([v.strip(",()[].\"'") for v in x.split(" ")])

    df["Name"] = df["Name"].apply(normalize_name)
```

「Search and edit」からTransform「Find and replace substring」を選択して、以下の通りInput columnsに`Name`、Patternに`[\,\(\)\[\]\.\\\"\']`、Replacement stringに半角スペースを入力します。

![017_Transform.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/9fdf081e-b411-11a1-1cf7-e4962982f149.png)

>2.Extract any prefix in the ticket. For example ticket "STON/O2. 3101282" will become "STON/O2." and 3101282.

```python:オリジナルコード
    def ticket_number(x):
        return x.split(" ")[-1]

    def ticket_item(x):
        items = x.split(" ")
        if len(items) == 1:
            return "NONE"
        return "_".join(items[0:-1])

    df["Ticket_number"] = df["Ticket"].apply(ticket_number)
    df["Ticket_item"] = df["Ticket"].apply(ticket_item)  
```

この変換は用意された部品だけでの実装が難しかったため「Custom transform」から「Python (Pandas)」を選択してカスタムコード(上と同じコード)を入力しました。

![018_Transform.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/2b3a541e-5b6c-3cd8-cdf3-1b8fcf4a5372.png)

>Let's keep the list of the input features of the model. Notably, we don't want to train our model on the "PassengerId" and "Ticket" features.

```python:オリジナルコード
input_features.remove("Ticket")
input_features.remove("PassengerId")
input_features.remove("Survived")
```

「Manage columns」の「Drop column」で削除する特徴を選択します。
※ `PassengerId`はこの後のデータエクスポートで使用するため戻しておきます。

![019_Transform.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/bee667cd-3576-61be-d457-eba895a2b678.png)

#### データのエクスポート
変換したデータはS3やSageMaker Canvas Datasets、SageMaker Feature Storeなどへエクスポートできます。特徴量をSageMaker Feature Storeへエクスポートしてみます。

SageMaker Feature Storeへエクスポートする際、以下の列が必要になります。

- Record identifier：レコードを一意に識別できるID
- Event time feature：レコードのイベントが発生したときのタイムスタンプ

「Record identifier」には`PassengerId`を使用し、「Event time feature」は以下のようなCustom transformを追加して`event_time`という名前の特徴を作成します。

![020_Export.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/ae796ff1-8357-7480-3fb0-a60457765137.png)

```python
import time
import pandas as pd
current_time_sec = int(round(time.time()))
df['event_time'] = pd.Series([current_time_sec]+df['PassengerId'], dtype="float64")
```

「＋」を選択して「Export」-「Export via Jupyter notebook」-「SageMaker Feature Store」を選択します。ローカルPCへダウンロードしたり任意のS3バケットを選択してNotebookを出力します。

![022_Export.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/a1ee2293-ef5e-7f30-bb8f-2459173f1025.png)

JupyterLabインスタンスを起動してコンソールを開きます。

![021_Export.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/9bd67b9a-0a6f-b534-c353-c4add879b69f.png)

ダウンロードした`.ipynb`ファイルを開き、`record_identifier_feature_name`を`"PassengerId"`に、`event_time_feature_name`を`"event_time"`に、`flow_name`を任意の名前に変更します。

![023_Export.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/607c78db-a745-3410-d0a1-d270fd2f9098.png)

![024_Export.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/f0a7bf42-8360-5e3c-4d0c-6d8b0cfa89d2.png)

準備ができたら画面上部の実行ボタン(または[Shift]+[Enter])を押下して以下の項目が完了するまでセルを実行します。

1. Create Feature Group
　A. Define Feature Group
　B. Configure Feature Group
　C. Initialize & Create Feature Group

SageMaker Feature StoreのFeature Groupが作成されました。

![026_Export.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/d6269e89-eaf0-72a3-63ce-edb04c04027a.png)

最終的にできたデータフローがこちらです。

![028_DataFlow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/0955ca0c-d997-2a1c-e647-8e5ff686ded3.png)

### SageMakerインスタンスの停止
SageMaker Data Wranglerはインスタンスを起動している時間単位で課金されます。
SageMaker Studioの「Running Instances」で起動しているインスタンスを表示できますので使っていないインスタンスは停止しておきましょう。同じく、JupyterLabインスタンスも停止しましょう。

![035_StopInstance.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/6cdc74d8-22cb-8923-63b5-4d31c4f3fc10.png)

## おまけ１：SageMaker CanvasでAmazon Q Developerを使用する
AWS re:Invent 2024において、SageMaker CanvasでAmazon Q Developerを使用できるようになったとのアナウンスがありました。本題から逸れますが、気になったので試してみました。

https://aws.amazon.com/jp/about-aws/whats-new/2024/12/amazon-q-developer-guide-sagemaker-canvas-users-ml-development/

https://aws.amazon.com/jp/blogs/aws/use-amazon-q-developer-to-build-ml-models-in-amazon-sagemaker-canvas/

ユーザープロファイルのアプリケーション設定において、Canvasの設定でAmazon Q Developerを有効化しておきます。

![q_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/0a0d8438-d08f-d121-37d5-68c1f4655654.png)

SageMaker Canvasの左ペインで「Amazon Q」が使えるようになっています。「Start a new conversation」で新しいチャットを始めます。

![029_Q.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/04f1b14e-6bc5-37db-af4b-801fb4ae9ac1.png)

やりたいことを簡潔に伝え、データをアップロードするとデータセットの概要を教えてくれました。

![030_Q.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/b16de424-0cc8-9b74-81e1-033959c7e481.png)

どんなアルゴリズムでモデルを訓練するか提案してくれて、

![031_Q.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/3c5961b7-41be-8be6-69f8-fdb6782c8a28.png)

あっという間にモデルが作られました。

![032_Q.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/7577035b-fce7-5dfc-9b15-1dfc6f0f5258.png)

推論時に影響力のある特徴を教えてくれます。

![033_Q.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/8121f56f-907e-4cdb-6be5-acbdceba6940.png)

![034_Q.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/b622c152-751f-77e6-d59a-ba10ff7713ea.png)

特徴量エンジニアリングとしてどのような処理が行われているかをData Wranglerのデータフローから確認することができます。(Flow nameに「Built by Amazon Q」というタグがついています。)

![036_Q.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/d8f60462-3060-ce21-f11e-b047be407fc7.png)

何から手を付けたらよいか分からない方は、最初にAmazon Qの手助けを借りて、後から自分のやりたいことを追加してもよさそうです。

## おまけ２：Custom transformのコードを生成する
SageMaker CanvasでAmazon BedrockモデルやSageMaker Jumpstartモデルを使用できます。
SageMaker Data Wranglerが提供するノーコードの組み込み変換でできないことは`Custom transform`で実装しますが、ここで使用するPythonコードを生成AIに作ってもらいましょう。

https://aws.amazon.com/jp/blogs/news/new-no-code-generative-ai-capabilities-now-available-in-amazon-sagemaker-canvas/

ここではAmazon Bedrockの「Anthropic Claude Instant」を使用しますのであらかじめBedrockの画面からモデルへのアクセスを有効にしておきます。
SageMaker Canvasの左ペインで「Gen AI」を選択し、「Get started」を押下します。

![gen_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/372d9bad-20c1-d38c-8e04-cd1d86e8f044.png)

「Claude Instant」を選択して「Select」を押下します。

![gen_002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/ae08f368-63f2-b6c1-62cc-ba590f6c3019.png)

年齢のビニング処理について、Pandasを使用したPythonコード例を生成してもらいました。

![037.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144187/2bcf0e2c-3637-37cd-ad08-3ec6a757498f.png)

## SageMaker Data Wranglerの料金
一番安価な`ml.m5.4xlarge`インスタンス(16vCPU、64GiB)を東京リージョンで使用した場合、1時間あたり$1.19とのことで、使わないときにインスタンスを起動したままにしておくと高額になりそうです。使わないときはきちんと停止しましょう。
ストレージ使用料はインスタンスを停止してもかかります。

https://aws.amazon.com/jp/sagemaker/pricing/

## おわりに
SageMaker Data Wranglerを使用することでデータ分析や前処理、特徴量エンジニアリングをノーコード・ローコードで実施でき、コードの書き方が分からないユーザでも分析業務に入りやすくなりました。
単純な処理はノーコード・ローコードで、より複雑な処理はカスタムコードを書いて処理するといったハイブリッドもよさそうです。

最後までご覧いただきありがとうございました。
本記事が皆さまのお役に立てましたら幸いです。