食品安全を可視化する:APIって知ってますか?

食品安全を可視化する:APIって知ってますか?

前回の記事で、アメリカでは健康局が定期的に飲食店に立ち入っていること、そしてその結果が公表されていることを説明しました。

今回は、この公開されている「立ち入り検査の成績」を可視化したいと思います。

最後まで読むと、立ち入り結果を地図上にプロットする方法が学べます。

目次

事前準備

データ分析には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

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)できるデータを見ることができます。

API Endpointをアドレスバーに張り付けた画像

しかし、この状態だと非常に見にくいです。そのため、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文の詳細な説明をすると長くなってしまうため、こちらの記事などを参考にしてください。

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番目まで続けます。

2023年11月25日コード追記

元のコードを実行すると「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
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()

上記のコードを実行した結果が下の地図になります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次