ブログ

更新情報や気づいたことなどいろいろと発信していきます。

雨の日について (2019/9/4)

今回は「どの程度1年で雨は降っているのか」について調べてみました。 ただし、具体的に調べるとなると、地域差と年の差がありますので、2018年の東京に限定して議論をします。

注意. 以下の実験データには、筆者のデータの読み間違いや、プログラムミスによって正しい値が出ていない可能性があります。

雨が降っていることの定義

気象庁が公開しているデータで、1時間0.5mm以上の降水量が確認された時、その1時間は雨が降っていると みなすことにします。実際は、その1時間で降ったりやんだりをくりかえしている可能性も充分あり得ますが、 簡単のため連続して雨が降っていると認識します。

連続して雨が降っている最長時間は?

2018年東京のデータですが、1日ごとに連続降水記録をリセットして考えると、 9月21日0時から、21時までの22時間が 最長連続降水時間となります。

1日でリセットしないと 9月20日15時から、9月21日21時までの31時間が 最長連続降水時間となります。

どれくらい連続して雨は降るものなのか

2018年東京のデータ

1時間以上連続降水 117日
2時間以上連続降水 85日
3時間以上連続降水 72日
4時間以上連続降水 58日
5時間以上連続降水 49日
6時間以上連続降水 36日
7時間以上連続降水 28日
8時間以上連続降水 19日
9時間以上連続降水 13日
10時間以上連続降水 10日
11時間以上連続降水 9日
12時間以上連続降水 7日
13時間以上連続降水 5日
14時間以上連続降水 4日
15時間以上連続降水 4日
16時間以上連続降水 3日
17時間以上連続降水 2日
18時間以上連続降水 2日
19時間以上連続降水 2日
20時間以上連続降水 2日
21時間以上連続降水 1日
22時間以上連続降水 1日
23時間以上連続降水 0日

上の表をみると、一日中降り続いている雨というのはなかなかないようです。 6時間以上の連続降水日でもすでに、36日しかありません。

1年でどの程度雨は降っているのか

上の表から、1時間以上の連続降水をみると117日間あることが読み取れます。 データとしては、1時間0.5mm未満の雨はカウントしないというルールなので、 365-117 = 248日 は「人間が感知できる雨が全く降っていない」ということにはなりません。 1時間0.5mm未満の雨が降っている可能性はあり、少量でも短時間に集中していれば激しい雨に感じることもあり得ます。 したがって、人間が感知できる雨が降った日はもっと多いと思われます。 しかし、寝ている間や、屋内にいた場合、少しだけ雨が降っていたとしても気づかないこともあるので、 体感としては、むしろ雨があった日が117日もあるなんて多いなと感じるかもしれません。

1年間の時間の割合で降水があった時間数(データ上0.5mm以上)を考えると意外に少なく、全体の約7.6%しかありません。 過去3年分のデータを調べてみても、この値に大きな違いはありませんでした。

2018年. 降水があった日数: 117. 降水があった時間の割合: 約7.6%. 年間降水量: 1445.5mm
2017年. 降水があった日数: 114. 降水があった時間の割合: 約8.0%. 年間降水量: 1430mm
2016年. 降水があった日数: 128. 降水があった時間の割合: 約7.9%. 年間降水量: 1779mm

2016年の年間降水量は2017年に比べて大きいですが、それでも、降水があった時間の割合はほとんど変わっていないのは少し不思議です。

漢字パズル (2019/8/29)

漢字パズルプログラムを作りました。「こちら」で試すことができます。

夏目漱石の小説から連続する2字の漢字を取得して、問題をランダム生成します。ランダム生成ですので、漢字パズルとしての完成度はあまり高くありません。

問題例

例1

例2

例3

例4

問題の答え

例1 「配」

例2 「劇」 (激甚がむずかしい.)

例3 「曲」 (曲線以外むずかしい.)

例4 「機」 (機敏以外むずかしい.)

感想

時代が違うのでよく利用される熟語も少し変化していることもあるのでしょうが、それにしても こうしていくつか実験してみると、夏目漱石の語彙力の高さを実感せずにはいられません。

勝率は棋力に依存する (2019/8/25)

将棋や囲碁などのボードゲームでは、先手と後手が最善を尽くした場合、 どちらが勝つのか、あるいは引き分けになるのかという問題があります。

この問題は、もし全ての手順を網羅すれば解決できますが、将棋のような複雑なものになると、指し手の総数が大きすぎて、すべてを解析することは困難です。

将棋や囲碁では問題が難しすぎるので、ここでは三目並べ(〇×ゲーム)について考えます。

三目並べは、コンピュータで解析するまでもなく、最善を尽くせば、引き分けになることが知られています。

すべての指し手を対称性などを考慮せずに考えたとしても、高々 9!=362880 通りなので、 パソコンを使えば完全解析可能なレベルですが、網羅する方法は複雑化した場合応用できないので、他の手段を考えます。

勝率から究極的結果を予想することができるのか

「先手勝率:後手勝率:引き分けの確率」の比から、究極的な結果(最善を尽くした結果)を予想することはできるでしょうか。

例えば、1000局の対局結果が

(先手勝率:後手勝率:引き分けの確率)=(800,150,50)

となったとき、先手が勝ちやすいので、究極的な結果として「先手必勝」だと予想しても良いでしょうか。

もし、この1000局の対局で、先手を持った人の棋力が後手を持った人に比べて比較的高い傾向にあれば、 先手の勝率が高くなるのは、ゲームの特性を反映した結果とはいえません。

したがって、対局結果から先手の勝ちやすさを測るには、先手を持った人と後手を持った人の棋力差がほとんどないのが望ましいといえます。

人間同士の対局ではこの状況を作るのは難しいかもしれませんが、コンピュータであればある程度実現可能です。

三目並べ100万局

コンピュータの棋力を3段階に分けて、100万局ずつ対局を行います。

  • (Lv.1) 全くランダムに指す.
  • (Lv.2) 次の一手で三目並べられる手があればそれを指す.他はランダム.
  • (Lv.3) レベル2に加えて、相手にリーチがかかっている場合はできるだけそれを阻止する手を選択する.他はランダム.

Lv.1の結果

まったくランダムな指し手で100万局指した場合の勝率は以下のようになりました。

先手勝ち:584557 (約58%)
後手勝ち:288423 (約29%)
引き分け:127020 (約13%)

Lv.2の結果

次の一手で三目並べられる手があればそれを指し、その他はランダムに指します。

先手勝ち:686114 (約69%)
後手勝ち:269760 (約27%)
引き分け: 44126 (約4%)

Lv.3の結果

レベル2に加えて、次の手で相手が3目そろえるのを阻止する手を指すようにします。どうしても阻止できない場合はランダムに指します。

先手勝ち: 311632 (約31%)
後手勝ち: 174190 (約17%)
引き分け: 514178 (約51%)

考察

三つの値の比、(先手勝率:後手勝率:引き分けの確率)は、棋力に大きく依存することが見て取れます。

ランダムな指し手による結果から、究極的結論を予想するのは難しいようですが、 完全にランダムではなくコンピュータの思考レベルを上げていけば、意義のある予想につながるかもしれません。

将棋や囲碁などについてですが、三つの比(先手勝率:後手勝率:引き分けの確率)を調べる際に、全体の統計ではなくて、 同レベルのレーティング同士の対局者に限定して調べるのが、意義があるのではないかと思います。

なぜならば、もしかすると、低レーティング者同士だと後手勝率が高く、 高レーティング者同士だと先手勝率が高いという状態が発生していた場合、 全体で考えるとお互いの結果が相殺してしまう可能性があるからです。

囲碁は初めから後手が「6目半」や「7目半」のコミが与えられますが、 「何目半」が妥当かどうかという判断は、「棋力」に依存して決めるのが妥当だという可能性もあります。

もしかするとですが、プロに限定しても上位層と下位層では適切なコミが異なるのかもしれません。

注:三目並べの対局結果は、自作プログラミングによるものなので、数値は参考程度にお願いします。

C#の拡張メソッド (2019/8/24)

C#の拡張メソッドとして、doubleにMathクラスのメソッドを入れると便利ではないでしょうか。

たとえば \[ \sin(1) \] を計算するとき、拡張メソッドとしてdoubleにMath.Sinを定義しておけば

double x = 1;
Console.WriteLine(x.Sin());     

というようにインスタンスメソッドとして使用でき、インテリセンスも有効に使えます。

もう一つ例をあげます。 \[ \sin(1+\sin(1)) \] であれば、拡張メソッドとして引数を加えるAddメソッドを追加することで

double x = 1;
Console.WriteLine(x.Sin().Add(1).Sin());

というように一つのメソッドチェインとして使用できます。

以下は、$\sin(1+\sin(1))$の計算を行う、(usingディレクティブを除いた)全体のコードです。

class Program
{
    static void Main(string[] args)
    {
        double x = 1;
        Console.WriteLine(x.Sin().Add(1).Sin());
    }
}
static class ExtendDouble
{
    public static double Add(this double x,double y)
    {
        return x + y;
    }
    public static double Sin(this double x)
    {
        return Math.Sin(x);
    }
}

実行結果. 0.963590724541833