Loading [MathJax]/extensions/tex2jax.js

2018年12月16日日曜日

JavaScriptでPythonのrange関数っぽいものを作る

JavaScriptで連続した適当な配列を作りたい場合

const arr = [1, 2, 3, 4, 5];
でもいいですがPythonの様なrange関数でささっと作りたい場合があります。
Rangeオブジェクトは存在しますが、DOM用のオブジェクトでありPythonのものとは用途が違います。
underscore.jsで同じようなものが提供されているのでライブラリを使用するならそれがいいでしょう。

Pythonのrange関数

Pythonのrange関数はリスト(JavaScriptで言う配列)を容易に作れる関数です。
Pythonを使う方ならお馴染みでしょう。

主な仕様は、

range(0からの終了数)
range(開始数, 終了数)
range(開始数, 終了数, STEP数)

となります。引数の数によって動作が違います。


[ソース]

#! /usr/bin/env python

# -*- coding: utf-8 -*-

print("[range]")

for i in range(10):
    print(i, end=", ")
print()

for i in range(5, 10):
    print(i, end=", ")
print()

for i in range(0, 10, 2):
    print(i, end=", ")



[結果]

[range]
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
5, 6, 7, 8, 9,
0, 2, 4, 6, 8,

このような動作となります。
JavaScriptで同じような動作の関数を作ってみましょう。

ここあたり
https://dev.to/ycmjason/how-to-create-range-in-javascript-539i
を見ると、同じような考えでrange関数を作っている人がいます。

主な仕様は2番目のrange(開始数, 終了数)のようです。
Array.from() や Array.prototype.fill()を使った方法などがあるみたいです。
例にあるようなものに加え、STEP数まで加味出来る仕様にしましょう。


  1.   function range(/* 開始数, 終了数, STEP数 */) {  
  2.     const len = arguments.length;  
  3.     const arr = [];  
  4.     let min = 0;  
  5.     let max = 0;  
  6.     let step = 1;  
  7.   
  8. //引数の数により開始数と終了数を変える  
  9.     switch(len) {  
  10.       case 1:  
  11.         max = arguments[0];  
  12.       break;  
  13.       case 2:  
  14.         min = arguments[0];  
  15.         max = arguments[1];  
  16.       break;  
  17.       case 3:  
  18.         min = arguments[0];  
  19.         max = arguments[1];  
  20.         step = arguments[2];  
  21.       break;  
  22.     };  
  23.   
  24.     for(let i = min; i < max; i++) {  
  25. // 第三引数があればSTEP数として処理をする  
  26.       if(step != 1) {  
  27.         if(i % step == 0) {  
  28.           arr.push(i);  
  29.         }  
  30.       }else {  
  31.         arr.push(i);  
  32.       }  
  33.     }  
  34.   
  35.     return arr;  
  36.    }  
  37.   
  38.   
  39. //①  
  40.    const a1 = range(10);  
  41.    console.log(a1);  
  42.   
  43.   
  44. //②  
  45.    const a2 = range(5, 10);  
  46.    console.log(a2);  
  47.   
  48.   
  49. //③  
  50.    const a3 = range(1, 10, 2);  
  51.    console.log(a3);  
  52.   
  53. //④  
  54.    for(let i of range2(5, 10)) {  
  55.       console.log(i);  
  56.    }  


[結果]

[0,1,2,3,4,5,6,7,8,9]
[5,6,7,8,9]
[2,4,6,8]
5
6
7
8
9

レガシーな書き方ですが、こんな感じでしょうか?
④はPythonのrangeの様な使い方です。

2018年11月23日金曜日

アントワーヌ・ゴンボーの疑問をPythonで検証してみる

確率論の始まりの話でよく出てくるアントワーヌ・ゴンボーの疑問

17世紀、フランスの貴族シュバリエ・ド・メレ卿(アントワーヌ・ゴンボー)という人はギャンブル好きだった。
彼は、サイコロのギャンブルが好きで、
1つのサイコロを4回投げて、6が出れば勝ちというゲームをした時は2/3の確率で勝つと考えた。
勝率は予想に届かなったが、勝ち越すことは出来た。
そして、2つのサイコロを24回投げて、6,6のゾロ目が出れば勝ちというダブルシックスも同じように、6,6のゾロ目が出る確率は1/36なのだから24回投げれば2/3で勝てるはずと考えた。
しかし、実際は予想に反してあまり勝てなかった。
そこで、ゴンボーは数学者パスカルに、何がおかしいか相談してみた。
パスカルはゴンボーの考え違いを見抜き、出る目から計算するのでなく、出ない目から計算するのが正しいと答えたそう。

さてそれをPythonで検証してみましょう。

まずは1つのサイコロから6の目が出れば勝つというゲーム
4回投げてどれくらいの確率で勝つかrandomを使って試してみましょう。

  1. #! /usr/bin/env python  
  2.   
  3. # -*- coding: utf-8 -*-  
  4.   
  5. import random  
  6.   
  7. print("[probability]")  
  8.   
  9. #試行回数  
  10. trial = 10000  
  11.   
  12. #投げる回数  
  13. roll = 4  
  14.   
  15. #勝った回数  
  16. win = 0  
  17.   
  18. def dice(trial, roll):  
  19.     win = 0  
  20.     reset = False  
  21.     for i in range(trial):  
  22.         reset = False  
  23.         for j in range(roll):  
  24.             if reset == False:  
  25.                 #サイの目をランダムに出す  
  26.                 pip = random.randrange(17)  
  27.                 #目が6なら勝ち  
  28.                 if pip == 6:  
  29.                     win += 1  
  30.                     reset = True  
  31.     return win  
  32.   
  33. win = dice(trial, roll)  
  34. print("試行回数: ", trial)  
  35. print("勝った回数: ", win)  
  36. print("勝率: ", (win / trial))  

結果:
[probability]
試行回数:  10000
勝った回数:  5218
勝率:  0.5218

[probability]
試行回数:  10000
勝った回数:  5184
勝率:  0.5184

[probability]
試行回数:  10000
勝った回数:  5140
勝率:  0.514

[probability]
試行回数:  10000
勝った回数:  5144
勝率:  0.5144

[probability]
試行回数:  10000
勝った回数:  5222
勝率:  0.5222


2/3には届きませんが勝ち越すことは出来ます。
次に、2つのサイコロを24回投げ、6,6のゾロ目が出たら勝ちというゲーム


  1. #! /usr/bin/env python  
  2.   
  3. # -*- coding: utf-8 -*-  
  4.   
  5. import random  
  6.   
  7. print("[probability]")  
  8.   
  9. #試行回数  
  10. trial = 10000  
  11.   
  12. #投げる回数  
  13. roll = 24  
  14.   
  15. #勝った回数  
  16. win = 0  
  17.   
  18. def dice(trial, roll):  
  19.     win = 0  
  20.     #ゲームリセットフラグ  
  21.     reset = False  
  22.     for i in range(trial):  
  23.         reset = False  
  24.         for j in range(roll):  
  25.             if reset == False:  
  26.                 #サイの目をランダムに出す  
  27.                 pip1 = random.randrange(17)  
  28.                 pip2 = random.randrange(17)  
  29.                 #print("({}, {})".format(pip1, pip2), end=" ")  
  30.                 #目が6, 6なら勝ち  
  31.                 if pip1 == 6 & pip2 == 6:  
  32.                     win += 1  
  33.                     reset = True  
  34.                     #print()  
  35.   
  36.     return win  
  37.   
  38. win = dice(trial, roll)  
  39. print("試行回数: ", trial)  
  40. print("勝った回数: ", win)  
  41. print("勝率: ", (win / trial))  

結果:

試行回数:  10000
勝った回数:  4939
勝率:  0.4939

[probability]
試行回数:  10000
勝った回数:  4997
勝率:  0.4997

[probability]
試行回数:  10000
勝った回数:  4900
勝率:  0.49

[probability]
試行回数:  10000
勝った回数:  4957
勝率:  0.4957

[probability]
試行回数:  10000
勝った回数:  4961
勝率:  0.4961

10000万回試行した結果では勝率5割を割りました。
パスカルの計算したとおりですね。
ポイントは勝った場合にゲームリセットすることです。
これが無いと一つのゲームに複数勝利することになりますので2/3に近い数字が出ます。

パスカルの計算式
1つのサイコロを4回投げて6が出たら勝つゲームの勝率
1 - (5/6) ^4 = 0.5177469

2つのサイコロを24回投げて6, 6のゾロ目が出たら勝つゲームの勝率
1 - (35/36) ^4 = 0.491403876

実際にランダムに試行した結果も計算に近い数字が出ましたね。

2018年10月22日月曜日

XMLHttpRequestで画像を扱う

XMLHttpRequestで画像を読み込む


Ajaxで一部のWebデータを読み込む時、XMLHttpRequestを使いますが、テキストデータが主に読み込みの対象となっているので今回は画像データを読み込みたいと思います。

読み込み方はテキストと同じで、 読み込んだ画層データをBlobかArrayBufferとして処理するだけでOKです。


Blobによる読み込み

  1. <!--doctype html-->  
  2.   
  3.     
  4.     <meta charset="UTF-8">  
  5.     <title>XMLHttpRequest</title>  
  6.     
  7.   
  8.   <div id="base">  
  9.  <h1>XMLHttpRequest</h1>  
  10.  <form>  
  11.       <input id="btn" type="button" value="read">  
  12.  </form>  
  13.  <div id="res"></div>  
  14.   </div>  
  15.   <script>  
  16.   
  17.    //XMKHttpRequestで画像読込  
  18.      
  19.    document.addEventListener("DOMContentLoaded", function() {  
  20.   
  21.   var btn = document. getElementById("btn");  
  22.   var res = document.getElementById("res");  
  23.   
  24.   //ボタンクリックによりXMLHttpRequestで読込  
  25.   btn.addEventListener("click", function() {  
  26.     var xhr = new XMLHttpRequest();  
  27.     //読み込む画像ファイル  
  28.     var path = "ika1.png";  
  29.   
  30.     xhr.open("GET", path, true);  
  31.   
  32.     //タイプ指定を忘れずに  
  33.     xhr.responseType = "blob";  
  34.       
  35.     xhr.onreadystatechange = function(e) {  
  36.   
  37.    if(xhr.readyState == 4 && xhr.status == 200) {  
  38.   
  39.      //var blob = e.target.response;  
  40.      var blob = xhr.response; //どちらも同じ  
  41.        
  42.      res.innerHTML = '<img src="' + URL.createObjectURL(blob) + '" />';  
  43.    };  
  44.     };  
  45.   
  46.     xhr.send(null);  
  47.   
  48.   }, false);  
  49.   
  50.    }, false);  
  51.   
  52.   </script>  

もう一つの例

  1. <!--doctype html-->  
  2.   
  3.     
  4.     <meta charset="UTF-8">  
  5.     <title>XMLHttpRequest</title>  
  6.     
  7.   
  8.   <div id="base">  
  9.  <h1>XMLHttpRequest</h1>  
  10.  <form>  
  11.       <input id="btn" type="button" value="read">  
  12.  </form>  
  13.  <div id="res"></div>  
  14.   </div>  
  15.   <script>  
  16.   
  17.    //XMKHttpRequestで画像読込  
  18.      
  19.    document.addEventListener("DOMContentLoaded", function() {  
  20.   
  21.   var btn = document.getElementById("btn");  
  22.   var res = document.getElementById("res");  
  23.   
  24.   //ボタンクリックによりXMLHttpRequestで読込  
  25.   btn.addEventListener("click", function() {  
  26.     var xhr = new XMLHttpRequest();  
  27.     //読み込む画像ファイル  
  28.     var path = "画像.png";  
  29.   
  30.     xhr.open("GET", path, true);  
  31.   
  32.     xhr.responseType = "blob";  
  33.       
  34.     xhr.onreadystatechange = function(e) {  
  35.   
  36.    if(xhr.readyState == 4 && xhr.status == 200) {  
  37.      //タイプを指定  
  38.      var blob = new Blob([xhr.response], {type: "image/png"});  
  39.   
  40.      res.innerHTML = '<img src="' + URL.createObjectURL(blob) + '" />';  
  41.    };  
  42.     };  
  43.   
  44.     xhr.send(null);  
  45.   
  46.   }, false);  
  47.   
  48.    }, false);  
  49.   
  50.   </script>  

Pythonで地図空間データを扱う⑤

ベースの地図が出来た所で、他のデータを被せてみます。 国土地理院の  500mメッシュ別将来推計人口データ  を使用します。 同じく神奈川県のデータ  500m_mesh_suikei_2018_shape_14.zip をダウンロードします。 ベースの地図データと同じ場所に展開...