Watsonにパレート最適な休日の過ごし方を提案してもらう

IBMのクラウド環境である[Bluemix](https://console.ng.bluemix.net/)では、1ヶ月のフリートライアル期間が用意されており、この期間内であれば人工知能のWatsonを無料で触ることができるというので、WatsonのTradeoff Analyticsというサービスを使って、パレート最適な休日の過ごし方を提案してもらいました。

アカウント作成は[IBM Bluemixフリートライアルアカウント作成手順 - Qiita](http://qiita.com/KenichiSekine/items/6ad49b25167b3f4cdb63)を参考に。

Bluemix上で利用可能なサービスの一覧は[カタログ](https://console.ng.bluemix.net/catalog/)ページで見ることができます。

追記: この投稿は[teratailのBluemixアドベントカレンダー](https://teratail.com/Bluemix)に参加しています。よかったらNiceをお願いします！

## Watson Tradeoff Analytics

カタログの[Tradeoff Analytics](https://console.ng.bluemix.net/catalog/services/tradeoff-analytics/)ページによると、

> Tradeoff Analytics を使用すると、対立することが多い複数の目標について、ある選択を行った場合にどのような影響があるのか考慮しながら、より良い選択を行うことができます。このサービスは、どのローンを組むかといった複雑な決定を下す際にも、また、どのラップトップを購入するかといった日常的な決定を下す際にも役立ちます。Tradeoff Analytics は、パレートのフィルタリング技法を使用して、複数の条件下において最適な選択肢を特定します。そして、意思決定者は、それらの最適な選択肢間のトレードオフを、各種の分析と視覚的なアプローチによって検討することができます。これにより、選択したオプションは、意思決定者にとって重要な目標と条件を必ず満たすようになります。

とあり、Tradeoff Analyticsを使うことで、いくつかの選択肢の中から最適なものを、パレートのフィルタリング技法を使って提案してもらえます。

## パレートのフィルタリング技法

Tradeoff Analyticsが単なる数値計算ツールではないポイントが、この「パレートのフィルタリング技法を使用して」というところだと思いますが、詳しい内容は難しそうなので、Wikipediaへのリンクを貼っておきます。

[パレート効率性 - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%AC%E3%83%BC%E3%83%88%E5%8A%B9%E7%8E%87%E6%80%A7)

大雑把に言うと、複数の評価項目において最大の効用が得られるような選択肢をフィルタリングできます。

## 使い方

Bluemixのカタログページから「作成」ボタンをクリックすると、ドキュメントやDEMOを見ることができます。

Tradeoff Analyticsの使い方は簡単で、[APIリファレンス](http://www.ibm.com/watson/developercloud/tradeoff-analytics/api/v1/)を見ると大体のことは書いてありました。

APIエンドポイントは共通で以下です。

> https://gateway.watsonplatform.net/tradeoff-analytics/api

今回のように、問題と解決策を得るためには`/v1/dilemmas`を使っていきます。

### PHPでcURLを使ったリクエスト送信

大枠としては以下のように、`columns`(評価項目)と`options`(選択肢)を含んだリクエストを送信すると、パレート最適な解決策をJSONで返してくれます。  

`$request["columns"]`や`$request["options"]`やレスポンスの例は、[APIリファレンス](http://www.ibm.com/watson/developercloud/tradeoff-analytics/api/v1/#dilemmas)にスマホ選びの良くできた例があるので、そちらを見てください。

```php
$endpoint_url = "https://gateway.watsonplatform.net/tradeoff-analytics/api/v1/dilemmas?generate_visualization=false";
$credentials = [
	"username" => "",// コピペする
	"password" => ""// コピペする
];
$credentials_text = "{$credentials['username']}: {$credentials['password']}";

$request = [
	"subject" => "holiday",
	"columns" => [
		// ...
	],
	"options" => [
		// ...
	]
];

$ch = curl_init($endpoint_url);
curl_setopt($ch, CURLOPT_USERPWD, $credentials_text);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($request));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
```

## 休日の過ごし方を提案してもらう

それでは上に書いた`$request`の中身を考えていきます。

まず選択肢(`options`)は、代表的な休日の過ごし方として以下のものを選びました。
※異論は大いに認めます

- 山登り
- ランニング
- 映画鑑賞
- 読書
- 車を買う
- デート
- 何もしない

配列は以下のようになります。

```php
$request["options"] = [
	[
		"key" => "1",
		"name" => "山登り",
		"values" => [
			"price" => 3000,
			"time" => 15,
			"energy" => 100,
			"girlfriend" => 0
		]
	],
	[
		"key" => "2",
		"name" => "ランニング",
		"values" => [
			"price" => 0,
			"time" => 2,
			"energy" => 50,
			"girlfriend" => 0
		]
	],
	[
		"key" => "3",
		"name" => "映画鑑賞",
		"values" => [
			"price" => 3000,
			"time" => 3,
			"energy" => 15,
			"girlfriend" => 0
		]
	],
	[
		"key" => "4",
		"name" => "読書",
		"values" => [
			"price" => 1400,
			"time" => 3,
			"energy" => 10,
			"girlfriend" => 0
		]
	],
	[
		"key" => "5",
		"name" => "車を買う",
		"values" => [
			"price" => 4000000,
			"time" => 5,
			"energy" => 60,
			"girlfriend" => 0
		]
	],
	[
		"key" => "6",
		"name" => "デート",
		"values" => [
			"price" => 15000,
			"time" => 10,
			"energy" => 50,
			"girlfriend" => 1
		]
	],
	[
		"key" => "7",
		"name" => "何もしない",
		"values" => [
			"price" => 0,
			"time" => 24,
			"energy" => 0,
			"girlfriend" => 0
		]
	]
];
```

続いて上記の選択肢に、以下のような条件(`columns`)を設定していきます。

- お金を使わない
- 時間がかからない
- 体力を消耗しない
- 彼女が必要ない

こちらの配列は以下のようになります。

```php
$request["columns"] = [
	[
		"key" => "price",
		"type" => "numeric",
		"goal" => "min",
		"is_objective" => true,
		"full_name" => "お金",
		"range" => [
			"low" => 0,
			"high" => 5000
		]
	],
	[
		"key" => "time",
		"type" => "numeric",
		"goal" => "min",
		"is_objective" => true,
		"full_name" => "時間"
	],
	[
		"key" => "energy",
		"type" => "numeric",
		"goal" => "min",
		"is_objective" => true,
		"full_name" => "体力"
	],
	[
		"key" => "girlfriend",
		"type" => "numeric",
		"goal" => "min",
		"is_objective" => true,
		"full_name" => "彼女",
		"range" => [
			"low" => 0,
			"high" => 0
		]
	]
];
```

## 結果

上記のリクエストに対してTradeoff Analyticsから返ってきた結果は、

...

山登り => **EXCLUDED**
ランニング => **FRONT**
映画鑑賞 => **EXCLUDED**
読書 => **FRONT**
車を買う => **INCOMPLETE**
デート => **INCOMPLETE**
何もしない => **FRONT**

...

以上より、「ランニング」と「読書」と「何もしない」がパレート最適な休日の過ごし方であることがわかりました！

INCOMPLETEというのは条件の範囲を超えた印で、車については金額が、デートについては彼女の数が、それぞれ最大値を超えていることを示しています。

## 最後に

意味のある結果を得るためには事前に適切なパラメータや実際の値を設定する必要がありますが、それ以外の部分についてはとても簡単に扱うことができました。

どこかに書いてありましたが、条件の重み付けやON/OFFを行えるビジュアルなエディターをBluemix上に用意することもできるようです。

今回のようなライトな利用方法ではオーバーヘッドが大きいかもしれませんが、ある程度パターン化されているような場合などには便利そうだと感じました。