前回の記事で、アメリカでは健康局が定期的に飲食店に立ち入っていること、そしてその結果が公表されていることを説明しました。
今回は、この公開されている「立ち入り検査の成績」を可視化したいと思います。
最後まで読むと、立ち入り結果を地図上にプロットする方法が学べます。
事前準備
データ分析にはGoogle Colaboratoryを使います。まだ、Google Colaboratoryを使ったことがない方は、下の記事をご覧になってください。
APIでデータを入手する
まずは今回使用するライブラリをインポートします。
Google Colaboratoryのノートブック(chicago_results.ipynb
という名前にしました。)のセルに以下のコードを入力し実行してください。
import requests #APIを利用する
import pandas as pd #データを前処理する
import plotly.express as px #地図の描画する
requests
という見慣れないライブラリをインポートしています。これはAPIを利用する際に必要になります。
API? 初めて聞くけど、何のこと?
APIとは「アプリケーション・プログラミング・インターフェース(Application Programing Interface)」の頭文字をとったものです。(別に覚えなくても大丈夫です。)
簡単に言うと「他の人が提供しているサービスを利用させてもらう」ことです。
例えば株価を分析するアプリを作りたいと思ったとします。
そのときに、何千もの会社の株価を新聞を見ながら毎日自分の手で入力するのは、時間と手間がかかり大変です。
そこで、日本取引所グループが公開しているAPIを利用すると、自分のアプリに簡単に最新のデータを取り込むことができます。
つまり、他の人が提供しているサービス(株価情報)を利用することで、効率的にアプリを作ることができます。
株価以外にも、天気、画像認識、電車乗り換え案内や、最近ではChatGPTなど、様々なAPIが有償・無償で提供されています。私たちが利用しているアプリの中には、こうしたAPIを使ったサービスが多くあります。
今回はシカゴ市健康局の立ち入り結果を使いたいので、シカゴ市が無償で提供しているAPIを使用します(データの利用規約はこちら)。
まず「シカゴ データポータル」にアクセスします。そして右側にあるActions
をクリックし、その中にあるAPI
を選びます。
以下の画面が現れるので、API Endpointをコピーします。(矢印の部分をクリックします。)
API Endpointのアドレスが、サービスを使う際の接続先になります。
次に、ノートブックのセルに下のコードを書き、実行します。
response = requests.get('https://data.cityofchicago.org/resource/4ijn-s7e5.json')
data = response.json()
1行目は、インポートした「requestsライブラリ」を使って、先ほどコピーしたAPI Endpointのアドレスから、データを入手(get)し、response
に格納しています。
2行目では、入手した情報(response
)に「jsonメソッド」を使い、data
に格納しています。これは何をしているのでしょうか。
実は先ほどコピーしたAPI Endpointのアドレスを、ブラウザのアドレスバーに直接張り付けると、入手(get)できるデータを見ることができます。
しかし、この状態だと非常に見にくいです。そのため、jsonメソッドを使い、Python上で見やすい形に変換しています。
実際に、データの1番目を見てみましょう。Pythonの場合0が1番目になるのでしたね。
data[0]
# 結果
{'inspection_id': '2584428',
'dba_name': 'TWISTED TACO',
'aka_name': 'TWISTED TACO',
'license_': '2840069',
'facility_type': 'Restaurant',
'risk': 'Risk 1 (High)',
'address': '1967-69 W LAWRENCE AVE ',
'city': 'CHICAGO',
'state': 'IL',
'zip': '60640',
'inspection_date': '2023-11-01T00:00:00.000',
'inspection_type': 'Canvass',
'results': 'Out of Business',
'latitude': '41.968650679928686',
'longitude': '-87.67885727462351',
'location': {'latitude': '41.968650679928686',
'longitude': '-87.67885727462351'},
':@computed_region_awaf_s7ux': '13',
':@computed_region_6mkv_f3dw': '21849',
':@computed_region_vrxf_vc4k': '6',
':@computed_region_bdys_3d7i': '225',
':@computed_region_43wa_7qmu': '18'}
項目数は多いですが、カンマや改行で非常に見やすい形になっていますね。(先ほどのアドレスバーに張り付けたものと比較してみてください。)
この { } や : で区切ったデータの書き方はJSONと呼ばれるファイル形式です。JSONは軽量で加工がしやすいため、データをやり取りする際によく使われるファイル形式です。
JSONの他にも、CSVやXMLもデータをやり取りする際によく使われるファイル形式です。
ちなみに、このAPIを使って入手できるデータは直近1000件分となっています。
日々情報が更新されていくため、皆さんが上記のコードを実行した際は、違ったお店の情報が出てきますが、この後の作業に支障はありませんので、安心してください。
さらに、先ほどの結果から「お店の名前」だけを見てみましょう。先ほどの結果の3行目dba_name
のdbaは「Doing Business As」のことで、お店の名前のことです。
data[0]['dba_name']
# 結果
'TWISTED TACO'
先ほどの結果とも一致します。
JSON形式をデータフレーム形式に変換する
JSON形式を、データ分析により適した「データフレーム形式」に変換していきます。データフレームをよく知らない方はこちらの記事をご覧ください。
今回の分析では入手したデータから「お店の名前(dba_name)」、「立ち入りの結果(results)」、「緯度(latitude)」、「経度(longitude)」を使用することとします。
まず事前準備として、JSON形式から必要なデータを取り出すために、まず空のリストを4つ作ります。
# 事前準備としてリスト型でデータを保存するため、空のリストをつくる。
dba_name_list = []
results_list = []
latitude_list = []
longitude_list = []
次に入手したデータの1番目から順番に、「お店の名前(dba_name)」、「立ち入りの結果(results)」、「緯度(latitude)」、「経度(longitude)」だけを抜き出して、先ほど作った空のリストにそれぞれを入れていきます。
for x in data:
try:
dba_name_list.append(x['dba_name'])
results_list.append(x['results'])
latitude_list.append(x['latitude'])
longitude_list.append(x['longitude'])
except KeyError:
dba_name_list.append(None)
results_list.append(None)
latitude_list.append(None)
longitude_list.append(None)
1行目にfor x in data:
とあります。これは「for文」と呼ばれ、同じことを繰り返し行う際によく使われるテクニックです。
何が起こっているかというと、まずdataから1番目のデータを取り出し、それをxに入れます。そして、xに対しセミコロン( : )より下の命令を実行します。for文の詳細な説明をすると長くなってしまうため、こちらの記事などを参考にしてください。
今回の場合は、dataから1番目のデータ(先ほどの'TWISTED TACO'
のデータ)が取り出され、dba_name_list.append(x['dba_name'])
が実行されます。
dba_name_list
は先ほど作った空のリストです。それに「appendメソッド」を使っています。appendはリストに値を追加するメソッドで、x['dba_name']
の値をdba_name_list
に追加します。x['dba_name']
が何かというと、さっき試しにやってみた'TWISTED TACO'
のことです。
その後results_list.append(x['results'])
、latitude_list.append(x['latitude'])
、longitude_list.append(x['longitude'])
が順番に実行され、空のリストにそれぞれの値が追加されていきます。
そして、2番目、3番目のデータで同じことを繰り返しながら、1,000番目まで続けます。
元のコードを実行すると「KeyError」のエラーになるとの情報が寄せられたため、上記コードを一部修正しました。
KeyErrorになる原因は、元のデータに値が空欄の箇所があるためだと考えられます。そのため、エラーが起こった際の例外処理を行うため「try-except」を追加し、「KeyError」が発生した場合(値が空欄の場合)はNone
を代わりに代入するようにしました。
例外処理についてはSAMURAI様のこちらの記事(外部サイト)などを参考にしてください。
それぞれのリストに1,000件分のデータが格納できました。
次に、それぞれのリストをデータフレームに変換します。そして最後にそれらを結合し、1つのデータフレームにします。
# それぞれのリストをデータフレームに変換
df_dba = pd.DataFrame(dba_name_list, columns=['dba'])
df_results = pd.DataFrame(results_list, columns=['results'])
df_latitude = pd.DataFrame(latitude_list, columns=['latitude'])
df_longitude = pd.DataFrame(longitude_list, columns=['longitude'])
# 一つにまとめる
df = pd.concat([df_dba, df_results, df_latitude, df_longitude], axis=1, join='inner')
pd.DataFrame
で、dba_name_list
をデータフレームに変換しています。その際に、columns=['dba']
とすることで、列名を「dba」にしています。そして結果をdf_dba
に格納しています。
同じことを別のリストでも行ったら、pd.concat
で結合し、一つにまとめています。
最終的にできたdf
の中身を見てみましょう。
df
「TWISTED TACO」が一番最初にあり、必要な列がきちんと含まれていますね。
データを可視化する前の、最後の準備を行います。
先ほどdf
に必要なデータが格納できたことを確認しました。念のため、それぞれの列のデータの型がどうなっているかチェックしてみましょう。データの型についてよく知らない方はこちらの記事をご覧ください。
df.dtypes
#結果
dba object
results object
latitude object
longitude object
dtype: object
object(文字列)となっています。「お店の名前(dba)」と「立ち入りの結果(results)」は文字列でよいのですが、「緯度(latitude)」と「経度(longitude)」は数値でないと、地図上にプロットする際にエラーになってしまいます。
そのため、「緯度(latitude)」と「経度(longitude)」を数値に変換します。ここではastype(float)
メソッドを使っています。
#小数点を含むため「浮動小数点(float型)」に変換する
df['latitude'] = df['latitude'].astype(float)
df['longitude'] = df['longitude'].astype(float)
もう一度データの型を確認します。
df.dtypes
#結果
dba object
results object
latitude float64
longitude float64
dtype: object
「緯度(latitude)」と「経度(longitude)」が数値になりましたね。
立ち入り結果を地図上にプロットする
データの前処理ができました。
最後に、データの可視化として、立ち入り結果を地図上にプロットしてみましょう。地図の描画には最初にインポートしたplotly
を使います。
fig = px.scatter_mapbox(df, #使用するデータとしてdfを使う
lat="latitude", lon="longitude", #緯度、経度でプロットする
zoom=11, #地図の拡大の程度
color='results', #立ち入り結果で色分けする
hover_name='dba', #カーソルを合わせたときにお店の名前を表示
hover_data='results', #カーソルを合わせたときに立ち入り結果を表示
height=600, #地図の高さ
width=800 #地図の幅
)
fig.update_layout(mapbox_style= 'open-street-map', margin={'r':0, 't':0, 'l':0, 'b':0})
fig.show()
上記のコードを実行した結果が下の地図になります。
地図上のマルにカーソルを合わせると、その店の情報を見ることができます。Pass(合格)は🔵、Fail(不合格)は🔴などと、立ち入り結果に応じて色分けしています。
また、地図にカーソルを合わせて、左クリックしボタンを押したままで地図を移動できます。同様に地図上でマウスのコロコロ(マウスホイール)を動かすと、拡大・縮小が行えます。
意外とFail(不合格)のお店が多くて驚きますね。
このように立ち入り結果が見えると、自分が飲食店を経営していたら、「なんとしても合格しなければ!」と思ってしまいます。
前回の記事で学んだ「立ち入り検査の成績」を使って、今回はAPI、JSON、for文、地図にプロットする方法を学びました。
新しいことを、いろいろ学ぶことができました。
今回のコードを少し変えると、さらにいろいろなことが行えます。
その他にも、APIを使って「〇〇したい」、「〇〇できるかな」と思った方は、ぜひプログラミングでそれができるか検索してみてください。
プログラミングができると、「食品安全」と「データサイエンス」を掛け合わせることができます。できることの幅が広がり、楽しいですね!
コメント