2016年8月23日火曜日

開発環境

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

問題3-3(他のCSVデータでの実験)

CSVファイル(WWDI | Population, total - Japan)

コード(Emacs)

HTML5

<div id="graphs0"></div>
<br>
値: <span style="color:blue">----------</span> 
平均値: <span style="color:green">----------</span> 
中央値: <span style="color:red">----------</span> 
<div id="output0"></div>
<input id="nums_data" type="file">

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

JavaScript

(function () {
    'use strict';
    var width = 600,
        height = 400,
        padding = 50,
        padding_left = 120,
        div_graphs = document.querySelector('#graphs0'),
        div_output = document.querySelector('#output0'),
        input_file = document.querySelector('#nums_data'),

        readCsv,
        display,
        drawGraph;

    Array.prototype.sum = function () {
        var s = 0;

        this.forEach(function (num) {
            s += num;
        });
        return s;
    };
    Array.prototype.mean = function () {
        var s = this.sum(),
            n = this.length;

        return s / n;
    };
    Array.prototype.median = function () {
        var numbers = this.slice(),
            len = numbers.length,
            i1,
            i2,
            median;

        numbers.sort();
        if (len % 2 === 0) {
            i1 = len / 2 - 1;
            i2 = i1 + 1;
            median = (numbers[i1] + numbers[i2]) / 2;
        } else {
            i1 = (len + 1) / 2 - 1;
            median = numbers[i1];
        }
        return median;
    };
    Array.prototype.modes = function () {
        var obj = {},
            count,
            num,
            max = 0,
            modes = [];

        this.forEach(function (num) {
            if (obj[num] === undefined) {
                obj[num] = 1;
                if (max === 0) {
                    max = 1;
                }
            } else {
                count = obj[num] + 1;
                obj[num] = count;
                if (count > max) {
                    max = count;
                }
            }
        });
        for (num in obj) {
            if (obj[num] === max) {
                modes.push(parseInt(num, 10));
            }
        }
        return modes;
    };
    Array.prototype.differences = function () {
        var mean = this.mean(),
            diff;

        diff = this.map(function (num) {
            return num - mean;
        });
        return diff;
    };
    Array.prototype.variance = function () {
        var diff = this.differences(),
            squared_diff,
            len = this.length;

        squared_diff = diff.map(function (x) {
            return Math.pow(x, 2);
        });
        return squared_diff.sum() / len;
    };
    Array.prototype.standard_deviation = function () {
        var variance = this.variance(),
            std_deviation = Math.sqrt(variance);

        return std_deviation;
    };
    Array.prototype.zip = function (a) {
        var len1 = this.length,
            len2 = a.length,
            ary = [],
            i;

        if (len2 < len1) {
            len1 = len2;
        }
        for (i = 0; i < len1; i += 1) {
            ary[i] = [this[i], a[i]];
        }
        return ary;
    };
    readCsv = function () {
        var file = input_file.files[0],
            reader;

        reader = new FileReader()
        reader.readAsText(file);
        reader.onload = function () {
            var text = reader.result,
                years_and_population = [];

            years_and_population = text.split('\n')
                .slice(1, -1)
                .map(function (row) {
                    var cols = row.split(','),
                        year = parseInt(cols[0].split('-')[0], 10),
                        pop = parseFloat(cols[1]);

                    return [year, pop];
                });
            years_and_population.reverse();
            display(years_and_population);
        };
        reader.onerror = function (error) {
            throw error;
        };
    };
    display = function (points) {
        var years,
            population,
            pop_len,
            diff = [],
            years_and_diff,
            mean,
            median,
            modes,
            variance,
            std_dev,
            i;

        years = points.map(function (point) {
            return point[0];
        });
        population = points.map(function (point) {
            return point[1];
        });
        pop_len = population.length;
        for (i = 0; i < pop_len - 1; i += 1) {
            diff[i] = population[i + 1] - population[i];
        }
        mean = diff.mean();
        median = diff.median();
        modes = diff.modes();
        variance = diff.variance();
        std_dev = diff.standard_deviation();
        years_and_diff = years.slice(1).zip(diff);
        
        div_output.innerHTML =
            '平均値: ' + mean + '<br>' +
            '中央値: ' + median + '<br>' +
            '最頻値: ' + modes.join(', ') + '<br>' +
            '分散: ' + variance + '<br>' +
            '標準偏差: ' + std_dev + '<br>';

        div_graphs.innerHTML =
            '<div id="graph0"></div>' +
            '<div id="graph1"></div>';
        
        drawGraph('graph0', points,
                  {
                      x_label:'年',
                      y_label:'人口',
                  });
        drawGraph('graph1', years_and_diff,
                  {
                      x_label:'年',
                      y_label:'差異',
                      mean: mean,
                      median: median
                  });
    };
    drawGraph = function (id, points, obj) {
        var n = points.length,
            xs,
            ys,
            svg,
            xscale,
            xaxis,
            yscale,
            yaxis;

        xs = points.map(function (elem) {
            return elem[0];
        });
        ys = points.map(function (elem) {
            return elem[1];
        });
        xscale = d3.scaleLinear()
            .domain([d3.min(xs), d3.max(xs)])
            .range([padding_left, width - padding]);
        xaxis = d3.axisBottom().scale(xscale);

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

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

        svg.selectAll('line')
            .data(points.slice(0, n - 1))
            .enter()
            .append('line')
            .attr('x1', function (d, i) {
                return xscale(d[0]);
            })
            .attr('y1', function (d, i) {
                return yscale(d[1]);
            })
            .attr('x2', function (d, i) {
                return xscale(points[i + 1][0]);
            })
            .attr('y2', function (d, i) {
                return yscale(points[i + 1][1]);
            })
            .attr('stroke', function (d, i) {
                return 'blue';
            });
        
        svg.append('g')
            .attr('transform', 'translate(0, ' + (height - padding) + ')')
            .call(xaxis);
        
        svg.append('g')
            .attr('transform', 'translate(' + padding_left + ', 0)')
            .call(yaxis);

        if (obj.x_label) {
            svg.append('text')
                .attr('x', padding_left + (width - padding_left - padding) / 2)
                .attr('y', height - padding / 4)
                .attr('text-anchor', 'middle')
                .text(obj.x_label);
        }
        if (obj.y_label) {
            svg.append('text')
                .attr('x', padding_left / 4)
                .attr('y', height / 2)
                .attr('text-anchor', 'middle')
                .text(obj.y_label);
        }
        if (obj.mean) {
            svg.append('line')
                .attr('x1', xscale(d3.min(xs)))
                .attr('y1', yscale(obj.mean))
                .attr('x2', xscale(d3.max(xs)))
                .attr('y2', yscale(obj.mean))
                .attr('stroke', 'green');
        }
        if (obj.median) {
            svg.append('line')
                .attr('x1', xscale(d3.min(xs)))
                .attr('y1', yscale(obj.median))
                .attr('x2', xscale(d3.max(xs)))
                .attr('y2', yscale(obj.median))
                .attr('stroke', 'red');
        }    
    };

    input_file.onchange = readCsv;
}());

値: ---------- 平均値: ---------- 中央値: ----------

0 コメント:

コメントを投稿