2016年8月21日日曜日

開発環境

Pythonからはじめる数学入門 (Amit Saha (著)、黒川 利明 (翻訳)、オライリージャパン)の3章(データを統計量で記述する)、3.9(プログラミングチャレンジ)、問題3-1(よりよい相関関係を求めるプログラム)をJavaScript(とD3.js)で取り組んでみる。(バージョンアップで D3.js にいろいろ変更点があったみたい。)

問題3-1(よりよい相関関係を求めるプログラム)

コード(Emacs)

HTML5

<div id="graphs0"></div>
<button id="calc_and_draw">calc and draw</button>

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>

<script src="sample1.js"></script>

JavaScript

(function () {
    'use strict';
    var x0,
        x1,
        x2,
        y0,
        y1,
        y2,
        setNumbers,
        sum,
        findCorrXandY,
        
        width = 600,
        height = 400,
        padding = 50,
        padding_left = 50,
        div_graphs = document.querySelector('#graphs0'),
        input_number = document.querySelector('#number0'),
        button_calc_and_draw = document.querySelector('#calc_and_draw'),
        
        drawGraph,
        drawGraphs;

    sum = function (numbers) {
        var i,
            max,
            result = 0;

        for (i = 0, max = numbers.length; i < max; i += 1) {
            result += numbers[i];
        }
        return result;
    };
    setNumbers = function () {
        var i,
            max;

        x0 = [];
        x1 = [];
        x2 = [];
        y0 = [];
        y1 = [];
        y2 = [];
        for (i = 0; i < 10; i += 1) {
            x0[i] = i;
            x1[i] = Math.floor(Math.random() * 10);
            y0[i] = 9 - i;
            y1[i] = Math.floor(Math.random() * 10);
        }
        for (i = 0; i < 11; i += 1) {
            x2[i] = Math.floor(Math.random() * 10);
            y2[i] = Math.floor(Math.random() * 10);
        }
    };
    findCorrXandY = function (x, y) {
        var x_len = x.length,
            y_len = y.length,
            n,
            prod = [],
            sum_prod_x_y,
            sum_x,
            sum_y,
            squared_sum_x,
            squared_sum_y,
            x_square_sum,
            y_square_sum,
            numerator,
            denominator_term_x,
            denominator_term_y,
            denominator,
            i;
        
        if (x_len !== y_len) {
            throw {
                name: 'findCorrXandY Error',
                message: '2つの数集合の長さが異なり、相関関数は計算できない'
            };
        }
        
        n = x_len;
        for (i = 0; i < n; i += 1) {
            prod[i] = x[i] * y[i];
        }
        sum_prod_x_y = sum(prod);
        sum_x = sum(x);
        sum_y = sum(y);
        squared_sum_x = Math.pow(sum_x, 2);
        squared_sum_y = Math.pow(sum_y, 2);
        x_square_sum = sum(
            x.map(function (xi) {
                return Math.pow(xi, 2);
            })
        );
        y_square_sum = sum(
            y.map(function (yi) {
                return Math.pow(yi, 2);
            })
        );
        numerator = n * sum_prod_x_y - sum_x * sum_y;
        denominator_term_x = n * x_square_sum - squared_sum_x;
        denominator_term_y = n * y_square_sum - squared_sum_y;
        denominator = Math.sqrt(denominator_term_x * denominator_term_y);

        return numerator / denominator;
    };

    drawGraph = function (x, y, id_str) {
        var n = x.length,
            y0 = x.concat(y),
            svg,
            xscale,
            xaxis,
            yscale,
            yaxis;
        
        xscale = d3.scaleLinear()
            .domain([0, n])
            .range([padding_left, width - padding]);
        xaxis = d3.axisBottom().scale(xscale);

        yscale = d3.scaleLinear()
            .domain([d3.min(y0), d3.max(y0)])
            .range([height - padding, padding]);
        yaxis = d3.axisLeft().scale(yscale);

        svg = d3.select('#' + id_str)
            .append('svg')
            .attr('width', width)
            .attr('height', height);

        console.log(y0);
        svg.selectAll('line')
            .data(y0)
            .enter()
            .append('line')
            .attr('x1', function (d, i) {
                if (i < (n - 1)) {
                    return xscale(i);
                }
                if (i === n - 1 || i === 2 * n - 1) {
                    return xscale(0);
                }
                if (i < (2 * n - 1)) {
                    return xscale(i - n);
                }
            })
            .attr('y1', function (d, i) {
                if (i < (n - 1)) {
                    return yscale(d);
                }
                if (i === (n - 1) || i === (2 * n - 1)) {
                    return yscale(0);
                }
                if (i < (2 * n - 1)) {
                    return yscale(d);
                }
            })
            .attr('x2', function (d, i) {
                if (i < (n - 1)) {
                    return xscale(i + 1);
                }
                if (i === (n - 1) || i === (2 * n - 1)) {
                    return xscale(0);
                }
                if (i < (2 * n - 1)) {
                    return xscale(i - n + 1);
                }
            })
            .attr('y2', function (d, i) {
                if (i < (n - 1)) {
                    return yscale(y0[i + 1]);
                }
                if (i === (n - 1) || i === (2 * n - 1)) {
                    return yscale(0);
                }
                if (i < (2 * n - 1)) {
                    return yscale(y0[i + 1]);
                }
            })
            .attr('stroke', function (d, i) {
                if (i < (n - 1)) {
                    return 'green';
                }
                if (i === (n - 1) || i === (2 * n - 1)) {
                    return 'white';
                }
                if (i < (2 * n - 1)) {
                    return 'blue';
                }
            });
        
        svg.append('g')
            .attr('transform', 'translate(0, ' + (height - padding) + ')')
            .call(xaxis);
        
        svg.append('g')
            .attr('transform', 'translate(' + padding_left + ', 0)')
            .call(yaxis);
    };
    drawGraphs = function () {
        setNumbers();
        div_graphs.innerHTML =
            'x: <span style="color:green">----------</span> ' +
            'y: <span style="color:blue">----------</span></br><br>';
        [x0, y0, x1, x2].forEach(function (x, i) {
            [y0, x0, y1, y2].forEach(function (y, j) {
                var correlation,
                    id_str;
                
                div_graphs.innerHTML +=
                    'x: ' + x.join(', ') + '<br>' +
                    'y: ' + y.join(', ') + '<br>';
                try {
                    correlation = findCorrXandY(x, y);
                    id_str = 'graph' + i.toString() + j.toString();
                    div_graphs.innerHTML +=
                        '相関係数: ' + correlation + '<br>' +
                        '<div id="' + id_str + '"><div>';
                    drawGraph(x, y, id_str);
                } catch (e) {
                    div_graphs.innerHTML += e.name + ': ' + e.message + '<br>';
                } finally {
                    div_graphs.innerHTML += '<br>';
                }
            });
        });
    };

    button_calc_and_draw.onclick = drawGraphs;

    drawGraphs();
}());

0 コメント:

コメントを投稿