A Day In The Life

とあるプログラマの備忘録

Python を使って緯度経度から地域メッシュコードを算出する

緯度経度(latitude, longitude)から日本の地域メッシュコードを算出する Python3.7 のプログラムを作成しました。

プログラム

緯度経度から1-3次メッシュコード(基準地域メッシュコード)を算出します。精度を出すためにミリ秒で計算しています。

import math

# 計算の単位(ミリ秒)
MILLISECOND = 3600000

class FirstGrid(object):
    def __init__(self, lat, lon):
        '''
        1次メッシュコード計算
        '''
        self.lat = lat
        self.lon = lon
        # メッシュの高さ
        self.height_ms = MILLISECOND * (40 / 60)
        # メッシュの幅
        self.width_ms = MILLISECOND
        # メッシュコードの上位桁
        self.upper = int(math.floor(lat * 15 / 10))
        # メッシュコードの下位桁
        self.lower = int(math.floor(lon - 100))
        # 南端(緯度)
        self.south_ms = self.upper * MILLISECOND / 1.5
        # 西端(経度)
        self.west_ms = (self.lower + 100) * MILLISECOND

    def code(self):
        ''' メッシュコード '''
        return f'{self.upper}{self.lower}'

    def origin(self):
        ''' メッシュの南西端(緯度経度) '''
        return self.south_ms / MILLISECOND, self.west_ms / MILLISECOND

class Grid(FirstGrid):
    def __init__(self, parent, divide):
        '''
        2,3次メッシュコード計算
        :param parent 親メッシュ
        :param divide 分割単位
        '''
        self.lat = parent.lat
        self.lon = parent.lon
        lat_ms = parent.lat * MILLISECOND
        lon_ms = parent.lon * MILLISECOND
        # 親メッシュの高さと幅から当該メッシュの高さと幅を算出する
        self.height_ms = parent.height_ms / divide
        self.width_ms = parent.width_ms / divide
        h = self.height_ms
        w = self.width_ms
        # 上位桁
        self.upper = int(math.floor((lat_ms - parent.south_ms) / h))
        # 下位桁
        self.lower = int(math.floor((lon_ms - parent.west_ms) / w))
        # 南端
        self.south_ms = self.upper * h + parent.south_ms
        # 西端
        self.west_ms = self.lower * w + parent.west_ms

    def code(self):
        return f'{self.upper}{self.lower}'

    def origin(self):
        return self.south_ms / MILLISECOND, self.west_ms / MILLISECOND

class LatLon2Code(object):
    def __init__(self, lat, lon):
        f = FirstGrid(lat, lon)
        # 2次メッシュは1次メッシュを8分割する
        s = Grid(f, 8)
        self._first = f
        self._second = s
        # 3次メッシュは2次メッシュを10分割する
        self._third = Grid(s, 10)

    def first(self):
        return self._first.code()

    def second(self):
        return f'{self._first.code()}{self._second.code()}'

    def third(self):
        return f'{self._first.code()}{self._second.code()}{self._third.code()}'

地域メッシュは英語だと Grid Square と表現するらしいのでクラス名は Grid にしています。1次メッシュの計算が特殊で2次3次は同じ計算をするので、1次と2次3次でクラスを分けました。

使い方

LatLon2Code クラスのコンストラクタに緯度経度を渡してコードを取得します。

def test_latlon2code():
    # 渋谷
    ll2c = LatLon2Code(35.6640352, 139.6982122)
    assert(ll2c.first() == '5339')
    assert(ll2c.second() == '533935')
    assert(ll2c.third() == '53393595')

参考記事

PostGISでgeometry型からgeography型に変換するときは座標系に注意する

SRID=4612(JGD2000測地系+地理座標系)のgeometry型フィールドだとgeography型に変換できる

postgres=> SELECT ST_SetSRID(geom, 4612)::geography FROM map WHERE id=1;
                     st_setsrid
----------------------------------------------------
 0101000020041200006B405577CB756140404749F6A1BF4140

SRID=3857(WGS84測地系球面+メルカトル図法)のgeometry型フィールドをgeography型に変換しようとするとエラーになる

postgres=> SELECT ST_SetSRID(geom, 3857)::geography FROM map WHERE id=1;
ERROR:  Only lon/lat coordinate systems are supported in geography.

座標系が投影座標系だとダイレクトに変換できないようです。

Golang書くときのちょっとしたテクニック

MarshalJSONを使ってJSONに表示用のフィールドを追加する

無限ループしないように元の構造体を拡張する

// UTCな時間をJsonに変換するタイミングでJSTに変換する例
import "time"

type Hoge struct {
    ID uint
    CreatedAt time.Time
}

func (h Hoge) MarshalJSON() ([]byte, error) {
    type Alias Hoge
    return json.Marshal(&struct {
        Alias
        CreatedAtJST time.Time
    }{
        Alias:     (Alias)(h),
        CreatedAtJST: h.CreatedAt.In(time.LoadLocation("Asia/Tokyo")),
    }
}

参考

Enum

数値系Enum

ゼロ値をUnknownにするのがGolang

type DeviceType uint
const (
    Unknown DeviceType = iota
    Android
    IOS
)

文字列系Enum

type Status string
const (
    Success Status = "success"
    Failure Status = "failure" 
)

関数にオプショナルな引数を設定したいとき

FunctionalOptionPatternを使って実装する

Functional Option Pattern

リクエストボディの読み出しが1回しかできないときの対処方法

リクエストボディを ioutil.ReadAll 関数で読み出すと2回目以降は中身空っぽになります。それの回避方法です。

http - How to read response body twice in Golang middleware? - Stack Overflow

Gotestでいい感じのスタブを作る方法

gomockインストールするのはちょっとなぁって時に良いです。

Golangにおけるinterfaceをつかったテストで mock を書く技法 - haya14busa

今時のサーバエンジニアのためのオススメ本

2017年の11月から本格的にサーバサイドのお仕事をするようになりました。それで今までに読んだオススメの本をまとめました。

使いやすいAPIを開発するために

RESRfulなAPIを開発するための指針など。他社(Twitter, GitHub, Yahoo.com...etc)のAPIを比較しながら説明

サーバ側のアーキテクチャ構成

マイクロサービス

運用しつつアーキテクチャを進化させていく

運用的な話

SREの基礎やSRE全般の話題

Golangでサーバプログラミングするなら始めに読むべき記事

最近 Golng 使ってサーバのプログラム書いてます。 始める前に読んでおけばよかったと感じた記事が2つあったのでメモ程度に紹介します。

Handlerのチェインをどうやって解決するか
- Making a RESTful JSON API in Go - The New Stack
Context問題どうするか
- Go’s net/context and http.Handler – joe shaw

micro:bitを使って子供と一緒に夏休みの自由研究をしてみました

夏休みのことなので少し前の話になりますが、小学生の娘と一緒に夏休みの自由研究にmicro:bit を使ったギターを制作しました。

f:id:glass-_-onion:20171009105814j:plain
エアギター

micro:bit って何ですか?

イギリスの BBC が開発した小学生向けの小型コンピュータです。子供向けではありますが、傾きセンサや光センサ、温度センサなんかもついていて本格的です。スピーカーに繋げば音を出すこともできます。Raspberry Pie や Arduino の子供版といった感じです。

マイクロソフトが開発した Scratch ライクな開発環境があるのでブラウザ上で手軽にプログラミングができます。

ギターの制作

小学2年生の娘が工作担当、自分がプログラミング担当といった感じで作りました。本当は娘にプログラミングもやって欲しかったのですが制作期間の関係で私が担当しました。以下の二つの工作例が元ネタです。

ちなみに電源供給とスピーカーは MI:power board で行いました。

ワニ口クリップがあるといろいろ捗ります

mcro:bit から音を出すためにスピーカーに繋いだりするのにワニ口クリップがあると便利です。mcro:bit 単体でも十分遊べるのですがワニ口クリップがあると遊びの幅がグッと広がるのでオススメです。

接着にはグルーガンがおすすめです

ダンボール同士をくっつける時なんかはボンドやノリを使うよりもグルーガンを使った方が丈夫に仕上がります。うちの小学2年生の娘も初めこそ苦戦してましたがそこそこちゃんと使えるようになってました。

参照ページ

数学知識ほぼ0の人間が深層学習の勉強をはじめてみた

きっかけは Magenta プロジェクト

最近巷では機械学習や深層学習(ディープラーニング)などAI系の技術が流行っていますが自分は2-3ヶ月前まで全くと言っていいほど興味がありませんでした。機械学習とかって画像解析や翻訳で使う技術でそのうち頭のいい人がなんとかしてくれるんじゃないのくらいの認識でした。その認識が一変したのが Google Magenta プロジェクト の AI Duet by Yotam Mann - AI Experiments でした。自分も深層学習を使って自動作曲やりたいということで勉強を始めることにしました。これまで自分が勉強したことや読んだ本のことをメモがてらまとめてみます。

勉強をはじめたころのスペック

  • Pythonは使ったことがある、ただしnumpyは使ったことがない
  • 数学はほどんとわからない(または忘れた)、ゲームの開発をしていたので三角関数くらいはなんとか理解できるくらい
  • 機械学習と深層学習の違いがわからない
  • 昨今流行っているAIがゲームAIとどう違うのかわからない

自動作曲やるならニューラルネットワークを勉強するのがよさげ

軽くMagenta プロジェクトのことや「自動作曲+AI」みたいなキーワードで調べてみるとニューラルネットワークを理解すると色々できるようになるっぽいということがわかりました。

数学さっぱりだけどニューラルネットワークについて勉強したい

本屋さんでニューラルネットワークの本を探して見ましたがどれも最低限の数学的な知識が必要そうな雰囲気でした。自分は数学が苦手で高校生の頃まともに数学を勉強した記憶がほとんどない....これは敷居が高いどうしようとなりました。

ライブラリを使って学ぶかライブラリ無しで勉強するか

いろいろと調べているうちに TensorFlow と Chainer この2つのライブラリが人気らしいことがわかりました。ただこれらのライブラリのチュートリアル読んでも専門用語がわからなさすぎて使いこなせる気が全くしませんでした。なのでライブラリに頼らず1から自分で実装してみるのがよさそうとなりました。

数学が苦手でも読めるニューラルネットワーク本との出会い

数学が苦手な自分でも内容がわかりライブラリに頼らず1から実装を学べるそんなわがままに答えてくれる本なんてないと思っていたらなんとも自分にぴったりな本を見つけました。

数式はあるものの初心者にもわかるように丁寧に解説してくれている、ニューラルネットワークについての基本的な用語の解説もある、Pythonの実装例まである、知りたいことほとんど載ってるじゃないか...素晴らしすぎる。バイアスの説明が省略されていること以外は必要な知識がほぼ網羅されています。

もっと基本的なところから数学の勉強したい場合は

深層学習の本ではなく機械学習の本ですが、深層学習に比べて数式が簡単なので深層学習の本よんで数式が全く理解できないって場合にオススメです。

ものすごく基本的なところから説明してあってかつPythonの実装例もあるのでかなり理解しやすいです。

深層学習を使ってどんなことができるのか

覚えた用語

  • 入力層
  • かくれ層
  • 出力層
  • 重み
  • 誤差逆伝搬

学習って何?

誤差が最小になるような重みの組み合わせを見つけること

深層学習を理解する上で必要な知識

よく出てくる数学用語

スカラー、ベクトル、行列、テンソル

次元 名前 説明
0次元 スカラー 数値
1次元 ベクトル 配列
2次元 行列 2次元配列
3次元以上 テンソル 3次元配列以上

ただしベクトルには列ベクトルと行ベクトルがある、通常は列ベクトルだけ考えれば良い

ベクトルと行列関連の用語

実装してみる

Pythonの実装例を元にSwiftで実装してみました。 github.com 3層ニューラルネットだけでは物足りず、今はLSTMの実装に挑戦中です。

参考