機械学習や統計ソフトと連携した分析ツール「Yellowfin」による可視化を体感する - JDMCカンファレンス データマネジメント2018

Yellowfinを体験してみる最も手軽な方法は、Yellowfin Japan社が提供しているトライアル環境を利用することです。
今回はそのトライアル環境を利用してレポートを作成し、さらにYellowfin 7.4で提供されたPMML（Predictive Model Markup Language）のプラグインを使ったクラスター分析や、JavaScriptを使用したグラフによる可視化を体験してみましょう。

# Yellowfinトライアル環境へのログイン

Yellowfin Japan社へクラウドでのトライアル利用を申し込むと、URLやユーザー名・パスワードといった情報が案内されますので、その内容に基づいてログインしてください。
初回ログイン時にはパスワードの変更を求められます。大文字・小文字・記号・数字をすべて含む8桁以上の文字列で新しいパスワードを設定してください。

# 機械学習や統計分析ツールとの連携

Yellowfin 7.4では、RやPython、H2O.aiといった機械学習や統計分析でよく使用されるツールとの連携機能が追加されました。
今回はRからPMML形式で出力された分析モデルをYellowfinで活用するというシーンを想定して、実際の操作を進めます。

## レポートの作成

レポートを作成するには画面右上の「＋」ボタンをクリックします。
ここではサンプルとしてあらかじめ用意されている「スキーチーム」のデータを使用します。

![rep001.gif](https://qiita-image-store.s3.amazonaws.com/0/116818/228df567-14a1-1565-dabc-0a55ca4b584e.gif)

レポート作成は基本的にマウスのドラッグ＆ドロップ操作で行います。
画面左の青いフォルダの中にデータ項目が格納されています。その中からレポートに使用したい項目を選び、画面右の白いキャンバスエリアにドラッグ＆ドロップするだけで、表を作成することができます。

この例では「顧客ID」と「請求金額」と「利益」の3つをドラッグ＆ドロップしてください。

![rep002.gif](https://qiita-image-store.s3.amazonaws.com/0/116818/e0134962-0beb-e14c-ff31-e6f56aa15bb8.gif)

画面左上の「グラフ」をクリックすると、グラフ作成の画面に遷移します。
作成したいグラフの種類を選択し、表で使用した項目を「縦軸」、「横軸」、「色」といった画面中央のフィールドにドラッグ＆ドロップすればグラフが作成できます。

ここではグラフの種類は「散布図」を選択し、横軸に「請求金額」、縦軸に「利益」を置きます。

![rep003.gif](https://qiita-image-store.s3.amazonaws.com/0/116818/47c21059-73ce-8b4f-ad9a-346e1939d838.gif)

## データを人力でクラスタリングしてみる

上記の操作で作成したグラフを眺めていると、３つくらいのデータの集団に分けられそうなことが見て取れるかと思います。

![rep004.png](https://qiita-image-store.s3.amazonaws.com/0/116818/110af244-40f9-b5c7-c1ba-d414f0053225.png)

マーケティングの手法として、データをいくつかの集団（クラスター）に分け、それぞれ別のアプローチを取ることがよくあります。
Yellowfinでそれを実現しようとした場合に最も単純なやり方は、データを見た人自身がしきい値を決め、レポート中に条件を埋め込むという手順です。

上記のデータを例に取り、請求金額が30万以下、30万〜250万、250万以上の３つに分けた区分を作ってみましょう。
「データ」の画面で、CASE式を使って条件分けした計算フィールドを作成し、そのフィールドを表とグラフに追加するという流れになります。

![rep005.gif](https://qiita-image-store.s3.amazonaws.com/0/116818/18059e0e-a057-b36d-dfa3-f93367678546.gif)

計算フィールドに記述する式は以下のようにします。

![rep006.png](https://qiita-image-store.s3.amazonaws.com/0/116818/69b40fcb-0dcf-08f4-a1fa-fd1f244a5bca.png)

するとグラフは以下のように色分けされました。

![rep007.png](https://qiita-image-store.s3.amazonaws.com/0/116818/d0b10dc6-97c8-9059-c868-31bc4ad2c05b.png)

力技に近い方法でしたが、これでもひとまずニーズは満たせるかもしれません。
しかしこのやり方だと、将来的に数値が増減したり、緑色で表されたクラスターをさらに分割したいといった要望が出てきたり、何らかの変化が起きたときには都度対応が必要になってしまいます。
先々の運用まで考えると、やはり分析ロジックそのものも自動化しておくべきでしょう。

## Yellowfinでデータサイエンスモデルを活用する

データサイエンティストやデータアナリストと呼ばれる方々がクラスタリングのような分析を行う場合、通常はRやPythonといったツールが使われます。
ですが、そうしたツールはローカルPCで環境構築されていることが多く、エンドユーザーが実際の業務を行っている環境で活用するには、別途システム改修が必要になるケースが大半でした。

そのハードルを下げるために、Yellowfin 7.4ではPMMLやPFAといった統計やデータマイニングモデルの標準フォーマットを使用するプラグインを提供しています。

<img width="1143" alt="rep008.png" src="https://qiita-image-store.s3.amazonaws.com/0/116818/bddfb60e-633f-d80c-ab8a-3877674cf160.png">

では、実際にYellowfinでPMMLプラグインを使ってみましょう。
まずはプラグインからの戻り値を受け取るためのダミー項目を計算フィールドで作成します。

![rep009.gif](https://qiita-image-store.s3.amazonaws.com/0/116818/6ed03f3c-fe4a-3326-5fcc-6e2fdd6423be.gif)

PMMLプラグインは「高度な関数」の機能で使用できます。
作成したダミー項目の横にある「▼」をクリックし、「高度な関数」を選択します。

![rep010.gif](https://qiita-image-store.s3.amazonaws.com/0/116818/3a3ba94a-424b-0255-5f9a-8da8462a6b9b.gif)

「PMML Model (Text)」を選択し、「PMML File」には以下のURLをコピーして貼り付けます。
https://raw.githubusercontent.com/hadatuna/skiteam_cluster/master/skiteam_cluster.pmml

先の例では３つのクラスターに分けましたが、今回はクラスターを１つ追加して４つに分けるモデルをRで作成し、上記のPMMLファイルを出力しています。

そしてPMMLファイルをロードした後に、請求金額と利益をパラメーターに設定します。

![rep011.gif](https://qiita-image-store.s3.amazonaws.com/0/116818/77ace2d5-7f07-8431-726f-35a5940f001a.gif)

最後に、グラフの画面で「PMML Model」の項目を色に適用すれば完了です。

![rep012.gif](https://qiita-image-store.s3.amazonaws.com/0/116818/eca8e6c1-ca4e-7bd8-5575-41e03e578c81.gif)

# JavaScriptグラフによる可視化

Yellowfinには標準で組み込まれているグラフ以外にも、直接JavaScriptを記述してグラフを描画する機能が備わっています。
直接コードを記述するため若干ハードルは高いですが、使いこなせば非常に強力な機能です。
今回の例では、JavaScriptのグラフライブラリであるD3.jsを使って、タグクラウドを描画します。

## レポートの作成

先の例と同様に、「スキーチーム」のビューからレポートを作成します。

「ツアー」と「請求金額」の2つをドラッグ＆ドロップしてください。
また、JavaScriptグラフ機能では項目名に日本語が使えないという制約があるため、名称をそれぞれ「tour」と「invoice」に変更します。

![rep013.gif](https://qiita-image-store.s3.amazonaws.com/0/116818/1291de82-e28f-c1ce-8c25-04afc4c5b3aa.gif)

## JavaScriptグラフの作成

「グラフ」の画面へ遷移し、画面右にある「JS」をクリックしてJavaScriptを記述する画面を開きます。

![rep014.gif](https://qiita-image-store.s3.amazonaws.com/0/116818/105bf9b7-454f-090a-40ec-53dc1a784b3d.gif)

すると初期値のスクリプトが表示されますが、ここではすべて削除し、以下のスクリプトを貼り付けてください。

```javascript:yellowfinTagCloud.js
// Javascript Panel
// generateChart is a required function which will be called to generate your JS chart
generateChart = function (options) {
    // Use require to load the javascript libraries you need
    require(['js/chartingLibraries/d3_3.5.17/d3_3.5.17.min', 'js/chartingLibraries/cloud'], function (d3, cloud) {
        debugger; // This will trigger a breakpoint in your browser debugger so you can debug your javascript

        var $chartDrawDiv = $(options.divSelector);
        $chartDrawDiv.html(
            '<svg1></svg1>'
        );

        var data = options.dataset.data;

        //change data.xxxname to properly column name
        var nameColumn = data.tour;
        //change data.xxxcount to properly column name
        var countColumn = data.invoice;

        var countMax = d3.max(countColumn, function (d) { return parseInt(d.raw_data) });
        var sizeScale = d3.scale.linear().domain([0, countMax]).range([10, 100])
        var fill = d3.scale.category20();
        var neodata = { name_Column: [], count_Column: [] };
        var data_names = [];
        var data_counts = [];

        //for excepting formatted data
        var nC = nameColumn;
        nC.forEach(function (key) {
            data_names.push(key.raw_data);
        });

        var cC = countColumn;
        cC.forEach(function (key) {
            data_counts.push(parseInt(key.raw_data));
        });
        neodata.name_Column = data_names;


        var words = neodata.name_Column.map(function (d) {
            return {
                text: d
            };
        });

        for (var i = 0; i < data_counts.length; i++) {
            words[i].size = sizeScale(data_counts[i]);
        }
        var random = d3.random.irwinHall(2)
        var layout = cloud()
            .size([600, 600])
            .words(words)
            .padding(1)
            //    .rotate(function() { return ~~(Math.random() * 2) * 90; })
            .rotate(function () { return Math.round(1 - random()) * 60; })// set the angle
            .font("Impact")
            .fontSize(function (d) { return d.size; })
            .on("end", draw);

        layout.start();

        function draw(words) {
            d3.select("svg1").append("svg")
                .attr("width", layout.size()[0])
                .attr("height", layout.size()[1])
                .append("g")
                .attr("transform", "translate(" + layout.size()[0] / 2 + "," + layout.size()[1] / 2 + ")")
                .selectAll("text")
                .data(words)
                .enter().append("text")
                .style("font-size", function (d) { return d.size + "px"; })
                .style("font-family", "Impact")
                .style("fill", function (d, i) { return fill(i); })
                .attr("text-anchor", "middle")
                .attr("transform", function (d) {
                    return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
                })
                .text(function (d) { return d.text; });
        }
    });
};
```

![rep015.gif](https://qiita-image-store.s3.amazonaws.com/0/116818/3d9dffd4-b17e-7fec-19b4-49d93b11320b.gif)

今回はあらかじめ用意したスクリプトを貼り付けただけでしたが、もちろん自由にJavaScriptを記述することが可能です。