ラーメン屋は月曜日が休みが多い
HOT PEPPER とぐるなび がAPI を提供しているので、そこからラーメン店の情報を取得し、定休日を集計した。
データは2019年2月21日に取得し、HOT PEPPER からは2212件、ぐるなび からは4767件の店舗情報が集められた。これを元に、定休日を集計した。データはJSON 形式で、定休日もキーとして割り振られているので、抽出は簡単だった。
HOT PEPPER 、ぐるなび ともに、年中無休がもっと多く全体の30%から40%を占めている。曜日としては、月曜日が休みの店が多くHOT PEPPER では15%、ぐるなび では11%であった。次いで、火曜、水曜、日曜が10%前後である。金土休みの店はほとんどなく、0.5%程度である。それを除けば、木曜休みが5%と、他の曜日に比べて半分程度であった。
無休と曜日別の定休日はそれぞれのサービスで似たような傾向にあったが、その他は異なる結果になった。それぞれのサービスに登録する店舗の傾向を反映しているのだろう。たとえば、不定 休の店はHOT PEPPER では6%だが、ぐるなび では14%と倍近い違いがある。一方で、HOT PEPPER では祝日前が定休日の店舗が2%程度なのに、ぐるなび には殆どなかった。
HOT PEPPER ラーメン屋 定休日
ぐるなび ラーメン屋 定休日
曜日別でも割合を算出した。何曜日に休みが多いのかは、こちらの方が適当だろう。月曜日が定休日の店が25%から30%で、火曜、水曜、日曜が大体20%くらいとなる。月曜休みの未成は多いが、突出して多いわけではない。火、水、日はHOT PEPPER とぐるなび とでばらつきがあったので、月曜日の次に多い曜日を特定するのは難しい。一方で、木曜日は10%と下がる。金土は稼ぎ時のためか、定休日のお店は1%くらいである。むしろ、数%でも存在していることが意外であった。
日曜日が休みの店舗はオフィス街などにあるのだろう。平日に休む場合は、月曜日が多く、次いで火曜日と水曜日となる。月曜日が休みなのは多客日の後に休みたい心理的 な面と、日曜に市場が開いていないため食材調達上の問題もありそうだ。木曜日が定休の店が少ないのは、金曜日の仕込みなどがあるからだろうか。
HOT PEPPER ラーメン店 曜日別定休日
ぐるなび ラーメン屋 曜日別定休日
他の業態の飲食店と比較すべきだが、今回は本筋ではないのでやらない。恐らく、他の飲食店でも似たような傾向になるだろう。
HOT PEPPER とぐるなび のAPI を利用し、Python にてラーメン店の情報を取得しJSON として保存した。そのデータから定休日の情報を抜き出し、集計を行った。
取得したJSON データから直接定休日を集計した方が手順は省けるが、定休日以外の統計処理を見据えて店舗情報を保存することにした。
API の叩き方は経験が無かったので少々戸惑ったけども、一度取得できれば試行錯誤は用意だった。むしろ、JSON データや定休日を集計しCSV 形式で保存したデータが文字化けしまくって四苦八苦した。
食べログ のAPI があると便利そうだと思ってググったら、残念ながらかなり前に廃止されていることを知った。そこで、食べログAPI提供終了していたので代わりのAPIを探した(一覧) - エンジニアステップ を参考に、HOT PEPPER とぐるなび のAPI を使うことにした。それぞれに一長一短がある。
HOT PEPPER はメールアドレスのみでAPI キー取得でき、お試しにはもってこいだ。検索できる店舗数に上限がないのも扱いやすい。また、店舗のジャンルコードとして「ラーメン店」を指定できるため、今回の用途と相性もよい。ただし、ぐるなび と比較すると登録店舗数が圧倒的に少ない。
データ形式 はXML がデフォルトだが、JSON やJSONP も選択できる。
ぐるなび は、API を取得するために氏名などを入力する必要があるため、お試しで使う身としてはちょっと敷居が高い。一方で、自身でサービスを立ち上げる際にはぐるなび の方が案内がしっかりしており信頼感が高い。データはJSON 形式で出力される。
業態コードとして「ラーメン」が用意されているものの、それを指定して叩いても居酒屋のようなラーメン専門店以外もひっかかる。特定の業態を抽出するには工夫が必要となる。
一方でテストツールをウェブから利用でき、お試しで結果を得やすい。また登録店舗数が圧倒的に多い。たとえば、ラーメン店で検索するとHOT PEPPER では2,600店しかヒットしないが、ぐるなび だとその10倍の26,000店もヒットする。統計を取りたいならぐるなび の方に分があるだろう。ただし、取得上限が1,000件までのため、必要な情報を網羅的に得るのにも工夫が必要となる。
Python の requests を用いて API を叩き、JSON 形式で店舗情報を取得した。先にも述べたが、ラーメン店を絞り込むのにやや工夫が必要である。
HOT PEPPER はラーメン店のジャンルコードが G013 と指定されており、絞りこみが楽である。約2,600店がヒットした。取得上限はないが1ページ当たり100店舗までしか表示できないので、26回叩いて全店舗の情報をJSON として出力した。
ぐるなび にもラーメン店の業態コードがあるものの、それだけではラーメン店以外もヒットする。お好み焼 きやしゃぶしゃぶ店なども引っかかるため、ぐるなび の分類方法は難がありすぎに思う。対処は比較的簡単で、フリーワードに「ラーメン」を入れることでほぼラーメン店のみに絞れた。
ぐるなび では約26,000件ものラーメン店がヒットした。取得上限が1,000件なので、それ以上の店舗情報を得るには叩き方に工夫が必要となる。今回は、都道 府県毎に取得した。
東京には3,000店舗以上、都市圏では1,000店舗以上のラーメン店が登録されている。 1,000件以上ある都道 府県では上限の1,000件を取得するように設定した。ぐるなび の掲載順に取得すると、ラーメン店以外は検索結果の後ろの方に表示される。上位1,000件を取得した方が、ラーメン店以外を除外しやすい。
API の叩き方に少々手間取ったが、それ以上に四苦八苦したのがJSON データの保存である。エンコード にUTF-8 を指定しているのに、なぜか日本語がASCIIで描き込まれ uXXXXなどど保存される。それを回避するには、open() ではなく codecs.open() で開き、dumps() の引数に ensure_ascii=False と指定する必要があった。
import requests
import json
import codecs
apikey = ”{個々人のAPIKEYを入力する}”
api = 'http://webservice.recruit.co.jp/hotpepper/gourmet/v1/?key={key}&order=3&genre={genre}&count={count}&start={start}&format=json'
url = api.format (key=apikey, count=1 , start=1 , genre='G013' )
response = requests.get(url)
response.raise_for_status()
data = json.loads(response.text)
count_range = data['results' ]["results_available" ]
ramen_json = []
for i in range (0 , count_range, 100 ):
url = api.format (key=apikey, count=100 , start=i, genre='G013' )
response = requests.get(url)
response.raise_for_status()
data = json.loads(response.text)
data = data['results' ]['shop' ]
ramen_json += data
with codecs.open ('ramen_hot.json' , 'w' , 'utf-8' ) as obj:
dump = json.dumps(ramen_json, indent=4 , ensure_ascii=False )
obj.write(dump)
import requests
import json
import codecs
apikey = ”{個々人のAPIKEYを入力する}”
api = 'https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid={key}&category_s={categoly}&freeword={freeword}&offset={start}&hit_per_page={count}&pref={pref_code}'
w_ramen = '%e3%83%a9%e3%83%bc%e3%83%a1%e3%83%b3'
c_ramen = 'RSFST08008'
for num in range (1 , 48 ):
num = str (num).zfill(2 )
pref_num = 'PREF' + num
url = api.format (key=apikey, count=1 , start=1 , freeword=w_ramen, categoly=c_ramen, pref_code=pref_num)
response = requests.get(url)
response.raise_for_status()
data = json.loads(response.text)
count_range = data['total_hit_count' ]
if count_range > 1000 :
count_range = 1000
ramen_json = []
for i in range (1 , count_range, 100 ):
url = api.format (key=apikey, count=100 , start=i, freeword=w_ramen, categoly=c_ramen, pref_code=pref_num)
response = requests.get(url)
response.raise_for_status()
data = json.loads(response.text)
data = data['rest' ]
ramen_json += data
with codecs.open ('ramen_guru' + pref_num + '.json' , 'w' , 'utf-8' ) as obj:
dump = json.dumps(ramen_json, indent=4 , ensure_ascii=False )
obj.write(dump)
定休日を抽出する
HOT PEPPER 、ぐるなび ともに定休日がそれぞれ close や holiday としてキー登録されているので定休日の抽出は非常に簡単だ。
また、ラーメン専門店を抽出できているかを確認するため、店舗業態も抽出した。都道 府県毎の傾向を見ようと思い都道 府県も抽出したが、今回はそこまでやらなかった。
ぐるなび の定休日情報は細かく書かれており、たとえば「毎週月曜日、*元日は休み」など備考が含まれている。今回は定期的な休業日を知りたかったので備考を省くように処理した。
ちなみに、ぐるなび の店舗形態を確認すると「こだわりラーメン」に分類されているラーメン店があった。気になって調べてみると、北海道を拠点する山岡家が用いている業態名称である。チェーン店なのにこだわりラーメンと銘打つのは強気すぎないか。
結果を、1列目に都道 府県、2列目に店舗業態、3列目に定休日となるCSV ファイルとして保存した。
ぐるなび は都道 府県毎にCSV ファイルを出力した後に結合したファイルを作成した。
ちなみに、CSV ファイルを結合する時にもエンコード の問題が発生。結合したファイルを出力する際に encoding='utf-8 ' と指定しているにも拘わらず、なぜかJIS形式で保存されるため、UTF-8 で開こうとして文字化けした。結合するファイルを開く際に、engine='python ' と指定することで文字化けを回避した。
import os
import glob
import json
import codecs
import csv
def holiday_pickup_hot (path):
All_Files = glob.glob('{}*.json' .format (path))
for file in All_Files:
with codecs.open (file , 'r' , 'utf-8' ) as obj:
df = json.load(obj)
ramen_csv = []
for i in range (len (df)):
holiday_list = []
area = df[i]['large_area' ]['name' ]
genre = df[i]['genre' ]['name' ]
holiday = df[i]['close' ]
holiday_list = [area, genre, holiday]
ramen_csv.append(holiday_list)
name = file .rstrip('.json' )
with open (name + '_holiday.csv' , 'w' ) as obj:
writer = csv.writer(obj, lineterminator=' \n ' )
writer.writerows(ramen_csv)
def holiday_pickup_guru (path):
All_Files = glob.glob('{}*.json' .format (path))
for file in All_Files:
with codecs.open (file , 'r' , 'utf-8' ) as obj:
df = json.load(obj)
ramen_csv = []
for i in range (len (df)):
holiday_list = []
area = df[i]['category' ]
genre = df[i]['code' ]['prefname' ]
holiday = repr (df[i]['holiday' ])
holiday = holiday.split(r'\n' )
holiday = holiday[0 ].split("'" )
holiday_list = [area, genre, holiday[1 ]]
ramen_csv.append(holiday_list)
name = file .rstrip('.json' )
with open (name + '_holiday.csv' , 'w' ) as obj:
writer = csv.writer(obj, lineterminator=' \n ' )
writer.writerows(ramen_csv)
holiday_pickup_hot(path='./ramen_hot/' )
holiday_pickup_guru(path='./ramen_guru/' )
import os
import glob
import csv
import pandas as pd
DATA_PATH = "./ramen_guru/"
All_Files = glob.glob('{}*.csv' .format (DATA_PATH))
list = []
for file in All_Files:
list .append(pd.read_csv(file , engine='python' , header=None ))
df = pd.concat(list , sort=False )
df.to_csv('ramen_guruPREF01to47_holiday.csv' , encoding='utf-8' )
定休日を集計する
EXCEL でもできそうだが、折角なのでPython を使って集計した。CSV ファイルの3列目を読み込み、定休日をキーとする辞書形式でカウントした。定休日と頻出数のセットとしたリストを作り、それをソートした後に、結果をCSV ファイルとした出力した。
曜日は意図通りに集計されるが、「無」、「無休」などは別々に集計される。また、週に二日以上定休日がある場合も、異なるキーとなる。そのため、出力されたデータを手動で再集計した。集計方法には工夫の余地があるものの、結果としては大きな差異はないと思われる。
ぐるなび は定休日が記載されていない店舗が多かった。約20,000店舗の情報を取得したが、その内約16,000件は定休日の情報が「記載無し」であった。これは「null」や「nan」の意味での「記載無し」である。定休日がなく年中無休なのか、そもそも情報が記載されていないのか判断できない。「記載無し」の店舗は省き、残った4,000店舗から定休日を集計した。
import pandas as pd
def counter (file_name, read_column):
df = pd.read_csv(file_name, engine='python' , header=None )
data = df.iloc[:, read_column]
words = {}
for word in data:
words[word] = words.get(word, 0 ) + 1
dic = [(v,k) for k,v in words.items()]
dic.sort()
dic.reverse()
with open (file_name.strip('.csv' ) + '_count.csv' , 'w' ) as obj:
for count, word in dic:
obj.write(str (count) + ',' + str (word) + ' \n ' )
counter(file_name='ramen_holiday_hot.csv' , read_column=2 )
counter(file_name='ramen_guruPREF01to47_en.csv' , read_column=2 )