1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Salesforce Visualforce Chart で 近似直線 を実装する

Posted at

■きっかけ

自分の日々の作業の量を比較するため、グラフを使って比較したとき、
「なんとなく忙しいようにみえる」 と 「なんとなく」 でしかわからなかったため、
ひと目で分かる方法がないか、と考えたのがきっかけでした。

また、Salesforce のグラフ上で実現できないか、を考えました。

■ケース

毎日行う作業とそれを累計したグラフです。(Google SpreadSheet)
日々の件数が棒グラフ、累計が線グラフ、横軸が日、縦軸が件数です。

ある月 べつの月
image.png image.png

「ある月」と「別の月」を比較すると

  • 「ある月」は、初旬はそこまで日々の件数は少なかったものの、中旬ごろから件数が増え、忙しくなったように見えます。
  • 「べつの月」は、初旬から忙しく、中旬ごろからは、日々の件数は少なくなり、ゆったりしたように見えます。

あくまでも感覚なので、わかりやすくならないか、考えました。

グラフには、「トレンドライン」という機能があります。
種類でいくつか選ぶことができ、今回は「線形」を選びました。

image.png

ある月 べつの月
image.png image.png
  • 「ある月」のほうが角度が急です。
    • やっぱり、突然いそがしくなった、と言えそうです。
    • 4日ごろから線が発生しているので、そのあたりから忙しくなった、と言えそうです。
  • 「べつの月」のほうは角度が緩やかです。

この線、わかりやすいですね。
では、この「トレンドライン」の「線形」のこの線はどうやって求めるのでしょうか。

■検証しましょう

この線は「近似直線」というらしいです。
(数学は詳しくないので、細かいことまでわかりませんが汗)

式を求めるため調べました。

こちらのページで理解しました。

y = ax + b
a = (ΣXiYi - nX'Y') / (ΣXi^2 - nX'^2)
b = Y'-aX'  (i=1,2,3・・・)

らしいです。わかりやすくします。

a = (X×Yの合計 - 標本数 × Xの平均 × Yの平均) ÷ (Xを二乗した合計 - 標本数 × Xの平均の二乗)
b = b = (Yの平均 - a × Xの平均)

上記のページで示されている例題で試してみましょう。

x y
10 6
12 9
14 10
16 10
  • 標本数 は、x と y の組み合わせの個数、今回は 4 です。
  • x の平均
    • (10 + 12 + 14 + 16) ÷ 4 = 13
  • y の平均
    • (6 + 9 + 10 + 10) ÷ 4 = 8.75
  • x の2乗 と x×y の合計
x y  x の 2乗 x×y
10 6 100 60
12 9 144 108
14 10 196 140
16 10 256 160
合計 - - 696 468
  • x の 2乗の合計(ΣXi^2) = 696
  • x × y の合計(ΣXiYi) = 468
a = (X×Yの合計 - 標本数 × Xの平均 × Yの平均) ÷ (Xを二乗した合計 - 標本数 × Xの平均の二乗)
a = (468 - 4 × 13 × 8.75) ÷ (696 - 4 × 13 × 13)
a = 0.65
b = (Yの平均 - a × Xの平均)
b = (8.75 - 0.65 × 13)
b = 0.3

つまり、

y = ax + b
y = 0.65 × x + 0.3

となります。

では、上記の式にサンプルに当てはめてみたいと思います。

x y  y = 0.65 × x + 0.3
10 6 6.8
12 9 8.1
14 10 9.4
16 10 10.7

トレンドラインで表示したときのグラフと、この計算で取得した値で作ったグラフを比較してしましょう。

トレンドライン 計算して取得した値で作ったグラフ
image.png image.png

同じ形になりました。
これで、トレンドラインの線形は、この計算方法で算出できることがわかりました。

■実装してみましょう

では、これを Salesforce Visualforce の Chart で実装してみましょう。

基本的な Salesforce Visualforce の Chart の使い方は以下を参考にしてください。
 ■Visualforce Charting を使用した複雑なグラフの作成
  https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/pages_charting_example.htm

■近似直線計算クラス

ApproximationStraightLine.cls
public class ApproximationStraightLine {
    public Double x {get; set;}
    public Double y {get; set;}
    public Double ay {get; set;}

    public ApproximationStraightLine(Double x, Double y) {
        this.x = x;
        this.y = y;
        this.ay = 0;
    }

    public static List<ApproximationStraightLine> calcurate(List<ApproximationStraightLine> listData) {
        Double numberOfSamples = numberOfSamples(listData);
        Double averageX        = getAverageX(listData);
        Double averageY        = getAverageY(listData);
        Double sigmaXiYi       = getSigmaXiYi(listData);
        Double sigmaXiPow2     = getSigmaXiPow2(listData);

        // a = (ΣXiYi-標本数×Xの平均×Yの平均)÷(ΣXi^2-標本数×Xの平均の二乗)
        Double a = (sigmaXiYi - numberOfSamples * averageX * averageY) / (sigmaXiPow2 - numberOfSamples * Math.pow(averageX, 2));

        // b = (Yの平均-a×Xの平均)
        Double b = averageY - a * averageX;

        for (ApproximationStraightLine data : listData) {
            // y = xa + b
            data.ay = data.x * a + b;
        }

        return listData;
    }

    private static Double numberOfSamples(List<ApproximationStraightLine> listData) {
        Double size = (Double) listData.size();
        return size;
    }

    private static Double getAverageX(List<ApproximationStraightLine> listData) {
        Double total = 0;
        Integer count = 0;

        for (ApproximationStraightLine data : listData) {
            total += data.x;
            count++;
        }

        return total / count;
    }

    private static Double getAverageY(List<ApproximationStraightLine> listData) {
        Double total = 0;
        Integer count = 0;

        for (ApproximationStraightLine data : listData) {
            total += data.y;
            count++;
        }

        return total / count;
    }

    private static Double getSigmaXiYi(List<ApproximationStraightLine> listData) {
        Double value = 0;

        for (ApproximationStraightLine data : listData) {
            value += (data.x * data.y);
        }

        return value;
    }

    private static Double getSigmaXiPow2(List<ApproximationStraightLine> listData) {
        Double value = 0;

        for (ApproximationStraightLine data : listData) {
            value += Math.pow(data.x, 2);
        }

        return value;
    }

}

■Visualforceページのコントロールクラス  

ChartTestController.cls
public class ChartTestController {

    public List<ApproximationStraightLine> getData() {
        List<ApproximationStraightLine> listData = new List<ApproximationStraightLine>();
        listData.add(new ApproximationStraightLine(10, 6));
        listData.add(new ApproximationStraightLine(12, 9));
        listData.add(new ApproximationStraightLine(14, 10));
        listData.add(new ApproximationStraightLine(16, 10));

        return ApproximationStraightLine.calcurate(listData);
    }
}

■Visualforceページ  

ChartTest.vfpage
<apex:page controller="ChartTestController">
    <apex:chart height="400" width="700" data="{!data}">
        <apex:axis type="Numeric" position="left" fields="y"  title="Y" grid="true" minimum="0" maximum="12"/>
        <apex:axis type="Category" position="bottom" fields="x"  title="X"/>

        <apex:barSeries orientation="vertical" axis="left"  xField="x" yField="y">
            <apex:chartTips height="20" width="120"/>
        </apex:barSeries>
        <apex:lineSeries axis="left" xField="x" yField="ay"  markerType="circle" markerSize="4" markerFill="#00FF00"/>
    </apex:chart>
</apex:page>

同じ近似直線を実現することができました。

image.png

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?