ThingWorxを使って割と手軽に機械学習を体験してみる

#はじめに
PTCが提供しているThingWorxの無料体験版である[ThingWorx Developer Portal](https://developer.thingworx.com/)を使用して、予備知識は抜きにして機械学習を体験し、機械学習が使われる分野やThingWorxがどう関係するのかを肌で感じてみましょうという記事です。

#前提と準備
ステップに入る前に必要な準備と前提条件を記載しておきます。
###使用環境：
Windows 10 PC、ブラウザにGoogle Chromeを使用しています。

###対象バージョン：
ThingWorx 8.4.1をベースとしておりますが、無料体験版でご利用いただけるThingWorx 8.4をとインターフェースに差異はありません。今後リリースされるものを含む異なるバージョンを利用する場合は手順や機能の互換が取れない可能性があります。

###PTCアカウント登録：
環境を手に入れて始める為にはPTCのポータルサイトへアカウント登録を完了している必要があります。[ThingWorxの開発者ポータルサイトにアカウントをつくり、試用版サーバーインスタンスを立ち上げる](https://qiita.com/akiranishi/items/c986bbbae8efc00706c9)を参考にアカウント登録を完了させて下さい。

###ThingWorx環境のセットアップ：

[ダウンロードリンク](https://developer.thingworx.com/en/resources/downloads)にアクセスし、無料体験版の２つの環境をダウンロード、セットアップが完了している必要があります。リンクは英語版と日本語版がありますが、2019年4月時点では下記の通りダウンロード可能なものに差異があるようです。最新版が利用出来る英語版を利用される事を推奨します。

- **ThingWorx Foundation：**日本語版はバージョン8.3に対し、英語版はバージョン8.4をダウンロード可能です。
- **ThingWorx Analytics Server：**日本語版はバージョン8.3に対し、英語版はバージョン8.4をダウンロード可能です。またその中でも**ThingWorx Analytics Server**と**ThingWorx Platform Analytics**のいずれから選択出来ます。今回はThingWorx Foundation以外にツールを必要としないThingWorx Analytics Serverを選択しています。

**ThingWorx-Analytics-Server-Windows-8-4.zip**をダウンロードすると**ThingWorxAnalyticsInstaller**フォルダが解凍され、以下のようなファイルが含まれています。
![download.png](https://qiita-image-store.s3.amazonaws.com/0/386147/42e083a6-561e-ce2f-fbb6-5f5b291233ce.png)

EXEを実行するとウィザードが現れるので以下の通り進めます。

**Next**をクリック。
![wizard1.png](https://qiita-image-store.s3.amazonaws.com/0/386147/7dc487da-568e-0007-d8bc-a901b8a8154b.png)

**I accept the agreement**を選択して**Next**をクリック。
![wizard2.png](https://qiita-image-store.s3.amazonaws.com/0/386147/5feef9b8-613a-865d-015a-5cec13f7f9ed.png)

全てのコンポーネントに✔がある事を確認して**Next**をクリック。
![wizard3.png](https://qiita-image-store.s3.amazonaws.com/0/386147/d5ba9413-b45b-e79c-f093-4265d18b7fb9.png)

任意の場所をインストール先に指定して**Next**をクリック。今回はデフォルトで指定されていた**C:\Program Files (x86)\ThingWorxAnalytics**を指定します。
![wizard4.png](https://qiita-image-store.s3.amazonaws.com/0/386147/bdb08cfc-5d25-012f-8790-71b058db3f5a.png)

**ThingWorx IP Address or Host Name**にThingWorxのサーバアドレスを入力します。**localhost**の場合でもアドレス**127.0.0.1**を設定する必要があるので注意が必要です。**ThingWorx Port**にThingWorxの接続ポート番号を入力します。**ThingWorx AppKey**に予めThingWorxで作成した任意のAppKeyを入力します。**Analytics Server Thing Name**にThingWorxで表示するAnlayticsサーバ名を入力する。デフォルトは**"コンピュータ名"-AnalyticsServer**が設定されています。今回は**Mylaptop-AnalyticsServer**に名前を変更します。今回はトライアルでSSLを使用しないので**Use SSL?**はチェックをオフにします。全ての情報を入力し**Next**をクリックします。
![wizard5.png](https://qiita-image-store.s3.amazonaws.com/0/386147/55963695-b42c-c7e9-090e-f7910aeb9487.png)

ThingWorxのAppKeyと照合が成功するとサマリが表示されるので**Next**をクリック。ここではバージョン整合を取る為の厳格なチェックが行われているようです。ThingWorx FoundationとThingWorx Analytics Serverのバージョンはマイナーバージョンも含めて一致させておく必要があります。もし互いに異なるバージョンをインストールしようとした場合はこのウィザードでエラーになりインストールが進める事が出来ません。
![wizard6.png](https://qiita-image-store.s3.amazonaws.com/0/386147/a1f581f9-7e4f-0b9b-d8f4-2f209f3f5b59.png)

**Next**をクリック。
![wizard7.png](https://qiita-image-store.s3.amazonaws.com/0/386147/0dbd40a6-982e-eac0-d3f0-e061a2b43d89.png)

インストーラが走るので完了するまで数分程度待ちます。
![wizard8.png](https://qiita-image-store.s3.amazonaws.com/0/386147/2b001a83-21be-dd1a-4de3-7f494ea14a7d.png)

完了すると成功の画面に遷移するので**Finish**をクリック。
![wizard9.png](https://qiita-image-store.s3.amazonaws.com/0/386147/70ab3ce3-9969-a3fd-0d68-3b1db85c4587.png)

最後にThingWorx Analytics Serverが正しくインストールされている事を確認する為にThingWorxのブラウザ画面を開きます。図の通り新しく**ANALYTICS MANAGER**が出現していれば成功です。

![analytics manager.png](https://qiita-image-store.s3.amazonaws.com/0/386147/681a30ec-8fe5-7ae3-86eb-174befa56d28.png)

###対象のチュートリアル：
[Build a Predictive Analytics Model](https://developer.thingworx.com/en/resources/guides/analytics-builder-quickstart)のステップを進めます。基本的に同じステップを辿りますが、この投稿では注意点や補足事項を加筆してあります。

#[ステップ１：シナリオ](https://developer.thingworx.com/en/resources/guides/analytics-builder-quickstart/analytics-builder-setup)

機械学習の体験を始めるにあたり、架空の企業を取り上げたシナリオを設定しています。

**MotorCo**社はモーターの製造、販売及びサービスを提供している企業です。MotorCoは最近新しいモーターを開発しプロトタイプフェーズまで進めています。そんな中、モーターの重要な可動部分に注入されるグリースが少なくなった場合、それが適切に充填されていないとモーターが致命的な不具合を起こす恐れがあることに気付きました。この事態を未然に防ぐ為、MotorCoはモーターに振動を記録するセンサーを搭載する事にしました。このセンサーが出力する特定の周波数と低グリース状態の関連を調べ、センサー情報をきっかけに故障が発生する前に必要なメンテナンスを施行出来るようにする事を課題としています。またプロトタイプデータを走査し最終的に課題解決する為に**ThingWorx Analytics**を活用する事にしました。

####チャレンジ

この活動を進めるにあたり予め以下の条件が設けられ、この条件下で課題を解決する必要があります。

- プロトタイプには既知の故障発生時に移行するモードがありますが、現時点ではいつ故障が発生するか予測することができません。
- この故障モードが解除されるまではプロトタイプは完全操業に移行する事が出来ません。
- 接続されたデータを監視できる状態にありますが、そのデータをどう利用するかアイデアがありません。
- 物理センサーを更に追加しようとすると製品全体のコストとして上乗せされてしまうので許容されません。

※最後に結論として触れますが、このシナリオではセンサー1とセンサー2が登場します。これからセンサーと不具合を引き起こす低グリース状態との関連の有無を調べていきますが、関連が高いセンサーだけを残しそれ以外のセンサーを取り外す事で不要なコストを抑えるというビジネス判断が目的のようです。

#[ステップ２：準備](https://developer.thingworx.com/en/resources/guides/analytics-builder-quickstart/analytics-builder-settings)

ThingWorx Composerの**Analytics**タブで **ANALYTICS BUILDER** > **Settings**をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/494a72fc-6bb6-728a-bc21-4ae18234b2c8.png)

**Analytics Server**フィールドでインストール時に設定したサーバー名を検索します。**Mylaptop-AnalyticsServer**がヒットするはずなのでそれを選択します。

![setting1.png](https://qiita-image-store.s3.amazonaws.com/0/386147/47555b50-0a8b-fffe-d10d-e9b57e0e09fe.png)


SSLを使用しないのでチェックボックスをオフにします。**Verify Configuration**をクリックします。

![setting2.png](https://qiita-image-store.s3.amazonaws.com/0/386147/cf014e5e-5a53-516a-b2b1-99b8358e7d3f.png)

Verificationが成功するとAnalytics Server Versionが表示されるのでそれを確認し**Save**をクリックします。保存されるとAnalytics Server Configurationが**Saved**に変化されればOKです。

#[ステップ３：データをアップロードする](https://developer.thingworx.com/en/resources/guides/analytics-builder-quickstart/data-upload)

ThingWorx Analyticsが使うデータをアップロードします。[analytics_vibration.zip](https://tpg-twxdevzone.s3.amazonaws.com/files/media/analytics_builder_v2_stuff/analytics_vibration.zip)をクリックしPCへダウンロードして下さい。ファイルを解凍すると**vibration_data_and_header.csv**及び**vibration_metadata.json**を取得出来ます。

アップロードしたデータを見ていきます。
![uploadeddata.png](https://qiita-image-store.s3.amazonaws.com/0/386147/156ed452-227c-f461-60c2-5fe0ef1dd47f.png)
データにはヘッダがありそれぞれ以下を示しているようです。

- **s1-fb1**：センサー1 or 2における周波数帯 1 - 5を示す。
- **low_greese**：低グリース状態の有無を示す。

**ANALYTICS BUILDER** > **DATA**をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/9b5f3fbb-3050-8953-0045-7ed8e3818368.png)

**Datasets**下の**New...**をクリックすると**New Dataset**ポップアップが開きます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/266e710f-402b-3a45-e96f-0f571019bafe.png)

**Dataset Name (required)**に`vibration_dataset`を入力します。**File Containing Dataset Data (CSV format):**セクション下の**Choose File**をクリックし、**vibration_data_and_header.csv**を検索して選択します。**File Containing Dataset Field Configuration (JSON format):**セクション下の**Choose File**をクリックし**vibration_metadata.json**を検索して選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/b4089417-6f9c-162f-4963-074182d7d50b.png)

**Submit**をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/30c9a412-194d-6479-f864-219c415eaf63.png)

アップロードが成功すると**Datasets**の一覧に**vibration_dataset**が表示されます。

#[ステップ４：シグナル](https://developer.thingworx.com/en/resources/guides/analytics-builder-quickstart/analytics-builder-signals)

このセクションではデータセットのうち、設定した目標に統計的に最も相関の高い単一のデータを検索する**"シグナル"**を作成します。但し必ずしもそれが設定したゴールそのものを示すものではなく、データが期待する目標と相関していることを意味します。

**ANALYTICS BUILDER** > **Signals**をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/d9d96039-ded0-704e-d940-d20effde1ec7.png)

上部にある**New...**をクリックします。**New Signals**ポップアップが開きます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/1e2f9c2d-efc4-0481-0e04-4d0f8bca1189.png)

**Signal Name**フィールドに`vibration_signal`と入力します。**Data from Existing Dataset**の下の**Dataset (required)**フィールドで**vibration_dataset**を選択します。**Goal (required)**フィールドで**low_grease**を設定したままにします。**Filter (required)**フィールドで**all_data**を設定したままにします。**Excluded Fields from Signal**フィールドをデフォルトの空白の状態にしておきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/831cf0f2-636d-45b3-46e7-88a255358f8f.png)

**Submit**をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/a13acf38-36e6-4132-7783-61ebb48c537d.png)

シグナルの状態が**COMPLETED**に変更されるまで30秒間程度待ちます。結果が下部に表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/fcae64d2-6e55-98da-5fb9-9fe05743ff8e.png)

結果を見てみます。統計的に低グリースの状態と相関が高い単一データが順にリストされます。**s1_fb1～s1_fb5**が上位にある通り、センサー1の5つの周波数帯が低グリースの状態と最も相関していることがわかります。また**s2_fb1～s2_fb4**が示すセンサー2の内、周波数帯1と4だけが関連しており2、3、5は殆ど関連性が無い事がわかります。

#[ステップ５：プロファイル](https://developer.thingworx.com/ja/resources/guides/analytics-builder-quickstart/analytics-builder-profiles)

シグナルのセクションではゴールと相関の高い単一のデータを検索しました。このセクションではゴールと相関が高いその単一データの**"組み合わせ"**である**"プロファイル"**を作成します。

**ANALYTICS BUILDER** > **Profiles**をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/c8b241d2-3496-0026-1c23-acd4a0b8ca7c.png)

上部にある**New...**をクリックします。**New Profile**ポップアップが開きます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/277ef1eb-94e1-cd6e-489a-98bdaa24ccd6.png)

**Profile Name**フィールドに`vibration_profile`と入力します。**Data from Existing Dataset**の下の**Dataset (required)**フィールドで**vibration_dataset**を選択します。**Goal (required)**フィールドで**low_grease**を設定したままにします。**Filter (required)**フィールドで**all_data**を設定したままにします。**Excluded Features from Profile**フィールドをデフォルトの空白の状態にしておきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/2c7c8f8a-0ed5-ab6b-a6c8-d5deee9ff93f.png)

**Submit**をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/e80544ed-2101-cc27-193d-740b6769a102.png)

シグナルの状態が**COMPLETED**に変更されるまで30秒間程度待ちます。結果が下部に表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/43ca1c12-20e3-f56b-65f9-84440dd25c3e.png)

結果を見てみます。統計的に有効と考えられる複数のプロファイル（データの組み合わせ）がリストされていますが、はじめの3つのプロファイルだけが総レコード数の内かなりの割合を占めており、後半のプロファイルの大部分は無視することができそうです。
![profile.png](https://qiita-image-store.s3.amazonaws.com/0/386147/386c0a2c-a416-1d52-1e85-61f762ed507f.png)
![profile2.png](https://qiita-image-store.s3.amazonaws.com/0/386147/70f6a0c9-d678-1402-0e6a-17d0e3dd71c2.png)

相関性が高そうな最初のプロファイルの中にはセンサー1とセンサー2の両方の周波数帯が表示されます。しかしシグナルの結果よりセンサー1が高い相関性を持っている事を考慮するとセンサ1が依然として全体で最も重要であることを示していそうです。つまりセンサー1はそれ自体でも組み合わせでも統計的に有益でありセンサー2は統計に不要という予測が立ちます。（一見センサー2は重要に見えるようでもそれはセンサー1との組み合わせの場合のみ該当する）

#[ステップ6：モデルを作成する](https://developer.thingworx.com/en/resources/guides/analytics-builder-quickstart/analytics-builder-create-model)

これまで走査したデータに基づいて、将来発生する可能性の高い事象を予測する**"モデル"**を作成します。モデルはそれ自体が一定量のデータを保持するわけではなくデータに対して実行されます。またモデルを取り扱うにあたり最低限必要な予備知識として、一般的に機械学習で用いられる手法の一つである**ROC曲線**や**AUC**について説明します。この２つは技術ブログや文献で沢山の情報がありますが、ここではThingWorxの利用で最低限必要な知識を操作と共に説明していきます。

###モデルの作成

**ANALYTICS BUILDER** > **Models**をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/c27e2755-7827-623a-ab07-ec16e00fc113.png)

上部にある**New...**をクリックします。**New Predictive Model**ポップアップが開きます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/6860696d-cb81-2138-78a4-ad06aeb3b902.png)

**Model Name**フィールドに`vibration_model`と入力します。**Data Selection**の下の**Dataset (required)**フィールドで**vibration_dataset**を選択します。**Goal (required)**フィールドで**low_grease**を設定したままにします。**Filter (required)**フィールドで**all_data**を設定したままにします。**Excluded Fields from Model**フィールドをデフォルトの空白の状態にしておきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/d139b87d-43f4-6150-8343-25a9b0fdc5d4.png)

**Submit**をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/866dc4f6-dc40-f0fa-8931-07b04bf25f92.png)

モデルの状態が**COMPLETED**に変更されるまで約60秒間程度待ちます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/146f8889-1bba-11fe-a212-47bc3f19cbb6.png)

###ROC曲線・AUCの理解とモデルの確認####

入力データに対してYES or NOとして解決できるような2値問題を考える場合、実際の正解と予測の組み合わせである4つに分ける事ができます。

|正解 (True/False)|予測 (Positive/Negative)|分類|
|:--:|:--:|:------------------:|
| YES|YES |True Positive (TP)  |
| YES|NO  |True Negative (TN)  |
| NO |YES |False Positive (FP) |
| NO |NO  |True Negative (TN)  |

"正解がYESであったもののうちYESと予測できた割合"を**True Positive Ratio**とし、以下の式で表現します。

*TPR(True Positive Ratio)=TP/(TP+FN)*


また"正解がNoであったもののうちYesと予測してしまった割合"を**False Positive Ratio**とし、以下の式で表現します。

*FPR(False Positive Ratio)=FP/(FP+TN)*

TPRが出来るだけ大きいものが良く、FPRが出来るだけ小さい方が良い分類という事がわかります。また割合なので*0<=TPR, FPR<=1*です。


実は前のステップで作成したモデルもこの2値分類問題を扱っています。センサーと周波数帯のデータに対して低グリース状態であるものを1、そうではないものを0として扱います。**ROC曲線(Receiver Operation Characteristic)**はTPRを横軸、FPRを縦軸としてグラフです。ThingWorxでそれを確認する事が出来ます。完成したモデルが選択されている状態で**View...**をクリックすると**Model Information**ページが開きます。
![rocauc.png](https://qiita-image-store.s3.amazonaws.com/0/386147/874933b6-9788-e0c9-3002-04dab3221f5d.png)

低グリース状態と判定する基準（閾値）を変えてプロットを取り描画したROC曲線です。またROC曲線とX軸、Y軸で囲まれた部分、つまりROC曲線から右半分の面積を**AUC(Area under an RoC curve)**と呼びます。理想的な分類はTPRが100%かつFPRが0%であり、AUCの面積が出来るだけ大きいものほど良いモデルと言えます。

**?**をクリックすると用語の詳細を確認する事が出来ます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/5fcd1d4a-2182-7392-6af7-b0739c6d1741.png)
左上の**Confusion Matrix**タブをクリックすると、正しい予測である**True Positive**と**False Negative**の総数と、正しくない予測である**False Positive**と**True Negative**の比較を確認出来、前者が後者よりも高い精度の高い予測モデルである事がわかります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/814f79a9-9144-272a-e703-33f0e4476754.png)
同様に**?**をクリックすると用語の詳細を確認する事が出来ます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/7ee25d4b-6f28-610b-1493-4957a38ea4b1.png)

#[ステップ７：モデルの最適化](https://developer.thingworx.com/en/resources/guides/analytics-builder-quickstart/analytics-builder-refine-model)#

プロファイルのステップより、センサー2がゴールを達成する為に不要である可能性がわかっています。作成したもモデルからセンサー2の要素を取り除く事でより精度の高い予測モデルを作成出来る可能性があるので、その比較を行います。

**ANALYTICS BUILDER** > **Models**をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/5a0232e3-01c3-0239-4a58-128acb32e2a2.png)

**New...**をクリックします。**Model Name (required)**フィールドに`vibration_model_s1_only`と入力します。**Data Selection**の下の**Dataset (required)**フィールドで**vibration_dataset**を選択します。**Goal (required)**フィールドで**low_grease**を設定したままにします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/18b833ea-11a6-4935-3610-ecf2f77569fb.png)

**Excluded Fields from Model:**の右横にある**Exclude Fields**をクリックします。**Exclude these Fields from this Model:**ポップアップが開きます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/9978e3be-e0da-59d2-a264-42b6bb0337d3.png)

**s2_fb1**をクリックしセンサー2の最初の周波数帯を選択します。シフトキーを押しながら**s2_fb5**をクリックし、センサー2全ての周波数を選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/6b3abc36-513a-b3b2-d622-9631c62e8379.png)

全てのセンサー2の値が選択されている状態で中央の**Add >**ボタンをクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/6692ef0c-c3c6-1a26-7377-08763490391a.png)

左下の**Select**をクリックしポップアップを閉じます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/955df81f-d88f-5010-1d9f-4e7bfe93e41a.png)

**Submit**をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/64897633-0969-064e-9f93-508feb2de9ff.png)

モデルの状態が**COMPLETED**に変更されるまで約60秒間程度待ちます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/07777ce0-0c2b-33ca-549d-9df6b3fa481c.png)

**vibration_model_s1_only**が選択された状態で**View...**をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/59a52cca-b7d4-e72b-8b71-d685fb9d7129.png)

ROC曲線を確認する事ができ、センサー2を含むオリジナルと同等の結果が得られました。同様に、**Confusion Matrix**の結果より正しい予測と正しくない予測の比率も同等の結果が得られました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/386147/72927d1b-2491-b68d-6b37-2eea06f7694d.png)

このモデルの結果より、センサーは1つでも2つでも低グリース状態を凡そ同じ制度で検出する事が出来るようです。1つのセンサと予測モデルを活用する事で、低グリース状態を正確に検出し不具合発生前にメンテナンスすることができれば、物理センサーのコストを抑えながらモーターの安全性や品質を上げるビジネス価値の創造に役立ちそうです。