RACCOON TECH BLOG

株式会社ラクーンホールディングス
技術戦略部より、
tipsやノウハウなど
技術的な話題を発信いたします。

一緒にラクーンのサービスをつくりませんか?採用情報はこちら

会社の近くに住みたい!緯度経度のAPI・データセットを使って部屋を探してみた

こんにちは、技術戦略部のわたべです。
今回は会社の近くにある部屋を探すために作った「緯度経度を使ってある地点からnメートル以内に存在する駅をリストアップするスクリプト」を紹介したいと思います。

弊社には会社から3キロ圏内に住むと月2万円が支給される「住宅補助制度」が存在します。(2022/4/17時点)

引っ越しの際に制度圏内に絞って部屋を探していましたが問題が一つありました。
「とある住所からNメートル以内の物件」という探し方が出来るサイトが見つからないことです。
賃貸検索サイトではエリアや沿線・駅を使っての探し方が主流であり、圏内の部屋を網羅するのが難しいと感じました。

探し方について考えた結果、「圏内の駅をリストアップして、賃貸検索サイトでは駅の近くにある部屋を探す」という手法を思いつきました。
駅を指定する検索方法はどの賃貸検索サイトにもあるので汎用性が高そうです。

駅が3キロ圏内に存在するかの判定には緯度経度を使うことにしました。
今回はruby v2.4.4でスクリプトを書きました。

Yahoo!ジオコーダAPIで中心の緯度経度を求める

圏内駅をリストアップするには、いくつかのステップを踏む必要があります。
まずは、中心地点となる会社の住所から緯度経度を求める必要があります。

緯度経度の取得にはYahoo!ジオコーダAPIを使用しました。

住所をパラメータとしてリクエストを送ることができ、レスポンスの中に緯度経度が含まれています。
弊社本社の住所をパラメータとして送ってみると下記のようなレスポンスが返ってきます。

https://map.yahooapis.jp/geocode/V1/geoCoder?appid={APP_ID_YAHOO}&query=東京都中央区日本橋蛎殻町1-14-14&output=json

→

{
    "ResultInfo": {
        "Count": 1,
        "Total": 1,
        "Start": 1,
        "Status": 200,
        "Description": "",
        "Copyright": "",
        "Latency": 0.133
    },
    "Feature": [
        {
            "Id": "13102.14.1.14.14",
            "Gid": "",
            "Name": "東京都中央区日本橋蛎殻町1丁目14-14",
            "Geometry": {
                "Type": "point",
                "Coordinates": "139.78207379,35.68338202",
                "BoundingBox": "139.78062000,35.68052000 139.78635400,35.68439300"
            },
            "Category": [],
            "Description": "",
            "Style": [],
            "Property": {
                "Uid": "98986ca87ea4c85748112cb77b83abfef6cd57d2",
                "CassetteId": "b22fee69b0dcaf2c2fe2d6a27906dafc",
                "Yomi": "トウキョウトチュウオウクニホンバシカキガラチョウ1チョウメ",
                "Country": {
                    "Code": "JP",
                    "Name": "日本"
                },
                "Address": "東京都中央区日本橋蛎殻町1丁目14-14",
                "GovernmentCode": "13102",
                "AddressMatchingLevel": "6",
                "AddressType": "地番・戸番"
            }
        }
    ]
}

["Feature"][0]["Geometry"]["Coordinates"]から緯度経度が取得できます。(経度,緯度の順)
スクリプトではAPIに対しGETリクエストを行い、レスポンスから緯度経度のみを取り出しました。

require "net/http"
require "json"
BASE_URL_YOLP_GEOCODER = "https://map.yahooapis.jp/geocode/V1/geoCoder"
APP_ID_YAHOO = # APIキー

def geosearch(address)
    # 中心の緯度経度を求める
    address = URI.encode(address)
    reqUrl = "#{BASE_URL_YOLP_GEOCODER}?appid=#{APP_ID_YAHOO}&query=#{address}&output=json"
    response = Net::HTTP.get_response(URI.parse(reqUrl))
    coordinates = nil

    case response
    when Net::HTTPSuccess then
        data = JSON.parse(response.body)
        coordinates = data['Feature'][0]['Geometry']['Coordinates'].split(/,\s?/)
    end
    return coordinates
end

coordinates = geosearch("東京都中央区日本橋蛎殻町1-14-14")

これで、中心となる緯度経度を取得することができるようになりました。

駅データ.jpから駅の緯度経度を抽出する

次は駅の緯度経度情報を用意します。
調べたところ、駅データ.jpさんで日本の鉄道駅情報のデータセットが配布されていました。

配布されている駅データの仕様書はこちらで公開されています。
ちゃんと緯度経度が含まれてますね。これらを取り込んであげれば圏内の判定に使えます。

require 'csv'
station_list = CSV.read("StationInfo.csv")

これで絞り込むための要素は揃いました。

nメートル圏内の駅をリストアップする

次に圏内の駅を絞り込む処理を書いていきます。
緯度経度を使って圏内判定できるライブラリはRUBY GEOCODERなどがありましたが、折角なので今回は自分で計算部分の処理を書いてみたいと思います。

楕円体上にある円の内外判定は計算がややこしいので、会社から駅までの距離が3キロメートル以内かを確認することにしました。

まず中心から駅までの距離を算出します。
緯度経度で計算するのは複雑なため、中心から駅までの距離をメートルに変換します。

変換にあたって1mあたりの緯度経度が必要になります。
今回は日本に限定して計算するため、北緯35度における1mあたりの緯度経度を使うことにしました。

中心から駅までの距離は(駅の緯度経度 - 中心の緯度経度) / 1mあたりの緯度経度で計算することができます。
そのため、駅が3キロメートル以内にあるかを判定するための計算式は下記のようになります。

(中心から駅までの緯度方向メートル)^2 + (中心から駅までの経度方向メートル)^2 <= 3000^2

全駅に対してこの判定を適用すれば、圏内にある駅を抽出することができます。
実際に処理を書くと下記のようになりました。

LatMeter = 0.000008983148616 # 1m当たりの緯度
LngMeter = 0.000010966382364 # 1m当たりの経度

def extract(range, station_list, cordinates)
    # 駅から3キロ以内の駅を抽出する。
    results = Array.new
    lat = cordinates[1].to_f #中心点の緯度
    lng = cordinates[0].to_f #中心点の経度

    station_list.each do |station|
        station_lat = station[10].to_f
        station_lng = station[9].to_f

        # 緯度座標の距離(メートル)
        distance_lat = (station_lat - lat) / LatMeter
        # 経度座標の距離(メートル)
        distance_lng = (station_lng - lng) / LngMeter

        in_area = distance_lat ** 2 + distance_lng ** 2 <= range ** 2

        if (in_area && station[0]!="station_cd")
            results.push(station[2]) # station[2]は駅名
        end
    end
    return results
end

results = extract(3000, station_list, coordinates)

これで、圏内にある駅だけを抽出することができました。

抽出結果を整形する

スクリプトの内容をまとめると下記のようになります。

require "net/http"
require "json"
require 'csv'

BASE_URL_YOLP_GEOCODER = "https://map.yahooapis.jp/geocode/V1/geoCoder"
APP_ID_YAHOO = # APIキー
LatMeter = 0.000008983148616 # 1m当たりの緯度
LngMeter = 0.000010966382364 # 1m当たりの経度

def geosearch(address)
    #「Yahoo!ジオコーダAPIで中心の緯度経度を求める」の内容
end

def extract(range, station_list, coordinates)
    #「nメートル圏内の駅をリストアップする」の内容
end

coordinates = geosearch("東京都中央区日本橋蛎殻町1-14-14")

# 駅の情報をインポートする
station_list = CSV.read("StationInfo.csv")

results = extract(3000, station_list, coordinates)

puts results.join(',')

実行すると下記のように出力されます。

東京,新橋,御徒町,秋葉原,神田,東京,有楽町,新橋,東京,新橋,東京,東京,神田,御茶ノ水,御茶ノ水,秋葉原,浅草橋,両国,東京,新日本橋,馬喰町,東京,八丁堀,越中島,東京,御徒町,秋葉原,神田,東京,有楽町,新橋,東京,上野広小路,末広町,神田,三越前,日本橋,京橋,銀座,新橋,御茶ノ水,淡路町,大手町,東京,銀座,仲御徒町,秋葉原,小伝馬町,人形町,茅場町,八丁堀,築地,東銀座,銀座,日比谷,竹橋,大手町,日本橋,茅場町,門前仲町,木場,湯島,新御茶ノ水,大手町,二重橋前,日比谷,桜田門,有楽町,銀座一丁目,新富町,月島,神保町,大手町,三越前,水天宮前,清澄白河,上野御徒町,新御徒町,蔵前,両国,森下,清澄白河,門前仲町,月島,勝どき,築地市場,汐留,新橋,東銀座,宝町,日本橋,人形町,東日本橋,浅草橋,蔵前,内幸町,日比谷,大手町,神保町,神保町,小川町,岩本町,馬喰横山,浜町,森下,菊川,秋葉原,新御徒町,新橋

駅データ.jpさんのデータセットでは路線ごとに駅のデータがあるため、複数路線に跨っている駅は重複して出力されてしまっています。
この状態だと重複が多くて見づらかったり、どの路線の駅かわからなかったりで賃貸検索サイトでの検索がやりづらいですね。

駅データ.jpさんでは路線のデータセットも配布されており、駅のデータセット内にある路線番号と照らし合わせると、路線名ごとに整理することができます。

圏内にある駅を抽出する際に、路線番号と路線内での順番も抽出するように変更します。

if (in_eclipse && station[0]!="station_cd")
    results.push([station[2],station[5].to_i,station[14].to_i]) # stationのうち2は駅名、5は路線番号 14は路線内での順版
end

路線番号と路線内の順番を使って抽出した駅を整理します。

def fix(results)
    line_list = CSV.read("StationLineInfo.csv")
    results_fix = Array.new
    prev_i = 0
    results.each_with_index do |station,i|
        if i!=0
            if(results[i][1] != results[i-1][1])
            line_stations = results[prev_i..i-1].sort_by{|station| station[2]}
            results_fix.push(line_stations)
            prev_i = i
            end
        end

    end
    line_name = ""
    results_fix.size.times do |i|
        line_id = results_fix[i][0][1].to_s
        line_list.each do |line|
            if line[0] == line_id
                line_name = line[2]
                break
            end
        end
        results_fix[i].unshift(line_name)
    end
    return results_fix
end

results = fix(results)

puts ""
puts "結果: "
results.each do |line|
    line.each_with_index do |stations,i|
        if i == 0
            puts line[0]
        else
            puts line[i][0]
        end
    end
    puts ""
end

整理した結果を出力すると下記のようになりました。

結果:
JR東海道本線(東京~熱海)
東京
新橋

JR山手線
御徒町
秋葉原
神田
東京
有楽町
新橋

JR横須賀線
東京
新橋

JR中央本線(東京~塩尻)
東京

JR中央線(快速)
東京
神田
御茶ノ水

JR中央・総武線
御茶ノ水
秋葉原
浅草橋
両国

JR総武本線
東京
新日本橋
馬喰町

JR京葉線
東京
八丁堀
越中島

JR成田エクスプレス
東京

JR京浜東北線
御徒町
秋葉原
神田
東京
有楽町
新橋

上野東京ライン
東京

東京メトロ銀座線
上野広小路
末広町
神田
三越前
日本橋
京橋
銀座
新橋

東京メトロ丸ノ内線
御茶ノ水
淡路町
大手町
東京
銀座

東京メトロ日比谷線
仲御徒町
秋葉原
小伝馬町
人形町
茅場町
八丁堀
築地
東銀座
銀座
日比谷

東京メトロ東西線
竹橋
大手町
日本橋
茅場町
門前仲町
木場

東京メトロ千代田線
湯島
新御茶ノ水
大手町
二重橋前
日比谷

東京メトロ有楽町線
桜田門
有楽町
銀座一丁目
新富町
月島

東京メトロ半蔵門線
神保町
大手町
三越前
水天宮前
清澄白河

都営大江戸線
上野御徒町
新御徒町
蔵前
両国
森下
清澄白河
門前仲町
月島
勝どき
築地市場
汐留

都営浅草線
新橋
東銀座
宝町
日本橋
人形町
東日本橋
浅草橋
蔵前

都営三田線
内幸町
日比谷
大手町
神保町

都営新宿線
神保町
小川町
岩本町
馬喰横山
浜町
森下
菊川

つくばエクスプレス
秋葉原
新御徒町

ここまで整形すれば、賃貸検索サイトでの駅名検索は簡単です。

おわりに

今回は会社の近くの部屋を探すために、3キロ圏内に存在する駅をリストアップするスクリプトを書いてみました。
一回リストアップすれば、いろんなサイトで使えるのが便利でした。
また、不動産賃貸仲介会社にこのリストを持っていくのも有効でした。不動産のみが使えるサイトも駅検索が主流のようです。

この圏内駅リストを有効活用した結果、最終的には補助制度の圏外に引っ越しました。
理由としては、私が探していた2LDK以上の部屋の家賃が補助の2万円を鑑みても圏外より大幅に高かったためです。
一人暮らし向けの部屋の場合はそこまで値段が変わらなかったのですが、家族向けの場合は5万円以上の差があることが多かったです(´・ω・`)

私の場合は家族がいたため圏外への引っ越しになりましたが、一人暮らしをする方は圏内で部屋を探すとオトクに住めると思います!

結果的には圏内に引っ越すことはありませんでしたが、このリストのおかげで圏内の部屋を網羅的に調べることが出来たと思います。
会社の近くに住むとなんらかの補助が出るという方はぜひ制度圏内にある駅のリストアップを試してみてください!

ラクーングループではエンジニア・デザイナーを絶賛大募集中です。もしご興味を持っていただけましたら、こちらからエントリーお待ちしています!
リンク先の「新卒採用/キャリア採用」→「各募集職種」→「基本情報(全職共通)」に住宅補助制度以外の福利厚生の記載がありますので、ご興味がありましたらぜひご覧ください!

一緒にラクーンのサービスを作りませんか? 採用情報を詳しく見る

関連記事

運営会社:株式会社ラクーンホールディングス(c)2000 RACCOON HOLDINGS, Inc