【ぐるなびAPI】よしなにランチを決めてほしい


こんにちは。B4のサッチーです。これは[MYJLab Advent Calendar 2020](https://qiita.com/advent-calendar/2020/myjlab)の12日目の記事です。
昨日まではM2の先輩, 同輩, 後輩が繋いでくださいました。ありがとうございます。
去年にひき続き、アドベントカレンダー頑張ります!!

## これは
最近インターンやら卒論やらで忙しく、自分の勉強や開発が全くできていなかったので、あまりアウトプットすることがありません。
そこで何か困りごとがないかを考えてみたのですが、幸せなことに、出社したときにランチに何を食べるか悩むくらいしか困りごとがありませんでした。
なので今回は適当にランチで何を食べるか提案してくれるプログラムを書いてみました。

## 計画
- [ぐるなびAPI](https://api.gnavi.co.jp/api/)を使って会社から半径500m以内にある飲食店の口コミを収集
- キーワードを入力して、レビューコメントにキーワードが含まれているお店を返す

## クチコミを収集
ぐるなびのAPIを使います。[ここ](https://ssl.gnavi.co.jp/api/regist/?p=input)からAPIの利用登録をします。
まず「レストラン検索API」で会社から半径500m以内にある飲食店を集めます。次に「応援口コミAPI」使って、集めた飲食店の口コミを収集します。


```python
class Gnavi:
    def __init__(self, keyid, latitude, longtitude):
        self.keyid = keyid,
        self.latitude = latitude,
        self.longitude = longtitude, 
        
    # レストラン検索API
    def get_shop_info(self, url):
        shop_info_list = []
        
        params = {
            'keyid': self.keyid,
            'latitude': self.latitude,
            'longitude': self.longitude,
            'offset_page': 1
        }
        
        while True:
            result = requests.get(url, params).json()
            if 'error' in result:
                print(result['error'])
                return shop_info_list
            
            shop_info_list += result['rest']
            params['offset_page'] += 1
        
        return shop_Info_list
   
    # 応援口コミAPI
    def get_shop_review(self, url, shop_ids):
        shop_review_list = []

        params = {
            'keyid': self.keyid,
        }

        window_count = len(shop_ids) // 10 + 1
        
        for window_id in range(0, window_count):
            if window_id == window_count - 1:
                shop_id = ",".join(shop_ids[10*window_id:])
            else:
                shop_id = ",".join(shop_ids[10*window_id:10*window_id+10])
                
            params['shop_id'] = shop_id
            result = requests.get(url, params).json()

            if 'gnavi' in result:
                for error in result['gnavi']['error']:
                    if error['code'] == 429:
                        return error['message']
            else:
                shop_review_list.append(result)

        return shop_review_list


keyid = '<APIキー>'
lat, lon = '<会社の>', '<緯度経度>'
gnavi = Gnavi(keyid, lat, lon)
```

レストラン検索APIは1リクエストで10店舗分の情報しか返ってこないので、offset_pageを増やしながら店舗の取得ができなくなるまでリクエストしました。


```python
url = "https://api.gnavi.co.jp/RestSearchAPI/v3/" ##レストラン検索APIのエンドポイント
shop_info_list = gnavi.get_shop_info(url)
```


構造が複雑なのでデータフレームにしてしまいます


```python
import pandas as pd

df_shopinfo = pd.DataFrame(shop_info_list)
```


```python
df_shopinfo.head()
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>@attributes</th>
      <th>id</th>
      <th>update_date</th>
      <th>name</th>
      <th>name_kana</th>
      <th>latitude</th>
      <th>longitude</th>
      <th>category</th>
      <th>url</th>
      <th>url_mobile</th>
      <th>...</th>
      <th>access</th>
      <th>parking_lots</th>
      <th>pr</th>
      <th>code</th>
      <th>budget</th>
      <th>party</th>
      <th>lunch</th>
      <th>credit_card</th>
      <th>e_money</th>
      <th>flags</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>{'order': 0}</td>
      <td>gd39700</td>
      <td>2020-12-08T01:20:02+09:00</td>
      <td>言の葉</td>
      <td>コトノハ</td>
      <td>35.647908</td>
      <td>139.712719</td>
      <td>鉄板個室ダイニング</td>
      <td>https://r.gnavi.co.jp/gd39700/?ak=m%2Bqqz7dSuc...</td>
      <td>http://mobile.gnavi.co.jp/shop/gd39700/?ak=m%2...</td>
      <td>...</td>
      <td>{'line': 'ＪＲ', 'station': '恵比寿駅', 'station_exi...</td>
      <td></td>
      <td>{'pr_short': '平素より、言の葉をご利用頂き誠にありがとうございます。 当店の閉...</td>
      <td>{'areacode': 'AREA110', 'areaname': '関東', 'pre...</td>
      <td>8000</td>
      <td>8000</td>
      <td></td>
      <td>VISA,MasterCard,ダイナースクラブ,アメリカン・エキスプレス,JCB</td>
      <td></td>
      <td>{'mobile_site': 1, 'mobile_coupon': 0, 'pc_cou...</td>
    </tr>
    <tr>
      <th>1</th>
      <td>{'order': 1}</td>
      <td>ggn6001</td>
      <td>2020-12-07T09:35:09+09:00</td>
      <td>Bistro Ame</td>
      <td>ビストロアム</td>
      <td>35.647953</td>
      <td>139.712559</td>
      <td>肩肘張らないビストロ</td>
      <td>https://r.gnavi.co.jp/1uczv90e0000/?ak=m%2Bqqz...</td>
      <td>http://mobile.gnavi.co.jp/shop/ggn6001/?ak=m%2...</td>
      <td>...</td>
      <td>{'line': 'ＪＲ', 'station': '恵比寿駅', 'station_exi...</td>
      <td></td>
      <td>{'pr_short': '肩肘張らないビストロで旬のお料理を味わう ６月２日より営業を再開...</td>
      <td>{'areacode': 'AREA110', 'areaname': '関東', 'pre...</td>
      <td>7000</td>
      <td></td>
      <td>5000</td>
      <td></td>
      <td></td>
      <td>{'mobile_site': 1, 'mobile_coupon': 0, 'pc_cou...</td>
    </tr>
    <tr>
      <th>2</th>
      <td>{'order': 2}</td>
      <td>7669791</td>
      <td>2020-04-01T05:39:53+09:00</td>
      <td>ガーデンテラス×イタリアン decollo デッコーロ 恵比寿</td>
      <td>ガーデンテラスイタリアン デッコーロエビス</td>
      <td>35.647956</td>
      <td>139.712806</td>
      <td>ビアガーデン</td>
      <td>https://r.gnavi.co.jp/p23gahsv0000/?ak=m%2Bqqz...</td>
      <td>http://mobile.gnavi.co.jp/shop/7669791/?ak=m%2...</td>
      <td>...</td>
      <td>{'line': 'ＪＲ', 'station': '恵比寿駅', 'station_exi...</td>
      <td></td>
      <td>{'pr_short': '', 'pr_long': ''}</td>
      <td>{'areacode': 'AREA110', 'areaname': '関東', 'pre...</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td>{'mobile_site': 1, 'mobile_coupon': 0, 'pc_cou...</td>
    </tr>
    <tr>
      <th>3</th>
      <td>{'order': 3}</td>
      <td>6421849</td>
      <td>2020-12-11T05:06:47+09:00</td>
      <td>EBISU蓮</td>
      <td>エビスレン</td>
      <td>35.647943</td>
      <td>139.712825</td>
      <td>そば</td>
      <td>https://r.gnavi.co.jp/phuv78xj0000/?ak=m%2Bqqz...</td>
      <td>http://mobile.gnavi.co.jp/shop/6421849/?ak=m%2...</td>
      <td>...</td>
      <td>{'line': 'JR埼京線', 'station': '恵比寿（東京都）駅', 'sta...</td>
      <td></td>
      <td>{'pr_short': '', 'pr_long': ''}</td>
      <td>{'areacode': 'AREA110', 'areaname': '関東', 'pre...</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td>{'mobile_site': 1, 'mobile_coupon': 0, 'pc_cou...</td>
    </tr>
    <tr>
      <th>4</th>
      <td>{'order': 4}</td>
      <td>1046494</td>
      <td>2020-12-12T05:17:38+09:00</td>
      <td>炉ばた 陣や</td>
      <td>ロバタジンヤ</td>
      <td>35.647473</td>
      <td>139.712244</td>
      <td>居酒屋</td>
      <td>https://r.gnavi.co.jp/knyezswz0000/?ak=m%2Bqqz...</td>
      <td>http://mobile.gnavi.co.jp/shop/1046494/?ak=m%2...</td>
      <td>...</td>
      <td>{'line': 'ＪＲ山手線', 'station': '恵比寿駅', 'station_...</td>
      <td></td>
      <td>{'pr_short': '', 'pr_long': ''}</td>
      <td>{'areacode': 'AREA110', 'areaname': '関東', 'pre...</td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td></td>
      <td>{'mobile_site': 1, 'mobile_coupon': 0, 'pc_cou...</td>
    </tr>
  </tbody>
</table>
<p>5 rows × 28 columns</p>
</div>



情報として使えそうなカラムだけ残します. prとimage_urlはさらに入れ子になっているので、pr_shortとshop_iamge1を残そうと思います


```python
df_shopinfo = df_shopinfo[['id', 'name', 'longitude', 'latitude', 'holiday', 'opentime', 'category','pr', 'url_mobile', 'image_url']]
df_shopinfo['pr'] = df_shopinfo['pr'].apply(lambda x: x['pr_short'])
df_shopinfo['image_url'] = df_shopinfo['image_url'].apply(lambda x: x['shop_image1'])
```


```python
df_shopinfo.head()
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>id</th>
      <th>name</th>
      <th>longitude</th>
      <th>latitude</th>
      <th>holiday</th>
      <th>opentime</th>
      <th>category</th>
      <th>pr</th>
      <th>url_mobile</th>
      <th>image_url</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>gd39700</td>
      <td>言の葉</td>
      <td>139.712719</td>
      <td>35.647908</td>
      <td>毎週日曜日\n年末年始（2019年1月1日）</td>
      <td>月～土・祝前日・祝日 ディナー：18:00～24:00(L.O.23:00)(臨時休業有。)</td>
      <td>鉄板個室ダイニング</td>
      <td>平素より、言の葉をご利用頂き誠にありがとうございます。 当店の閉店時間は深夜0時とさせて頂きます。</td>
      <td>http://mobile.gnavi.co.jp/shop/gd39700/?ak=m%2...</td>
      <td>https://rimage.gnst.jp/rest/img/h10d1ss30000/t...</td>
    </tr>
    <tr>
      <th>1</th>
      <td>ggn6001</td>
      <td>Bistro Ame</td>
      <td>139.712559</td>
      <td>35.647953</td>
      <td>毎週月曜日 第3火曜日\n※※月曜祝日の場合、翌日火曜は休み</td>
      <td>ディナー：18:00～23:00\n土・日・祝日 ランチ：12:00～15:00</td>
      <td>肩肘張らないビストロ</td>
      <td>肩肘張らないビストロで旬のお料理を味わう ６月２日より営業を再開させていただきます。</td>
      <td>http://mobile.gnavi.co.jp/shop/ggn6001/?ak=m%2...</td>
      <td>https://rimage.gnst.jp/rest/img/1uczv90e0000/t...</td>
    </tr>
    <tr>
      <th>2</th>
      <td>7669791</td>
      <td>ガーデンテラス×イタリアン decollo デッコーロ 恵比寿</td>
      <td>139.712806</td>
      <td>35.647956</td>
      <td></td>
      <td>金・土 ディナー：17:30～翌2:00(L.O.1:30)\n月～金 ランチ：11:30～...</td>
      <td>ビアガーデン</td>
      <td></td>
      <td>http://mobile.gnavi.co.jp/shop/7669791/?ak=m%2...</td>
      <td></td>
    </tr>
    <tr>
      <th>3</th>
      <td>6421849</td>
      <td>EBISU蓮</td>
      <td>139.712825</td>
      <td>35.647943</td>
      <td>毎週日曜日 祝日</td>
      <td>月～金 ランチ：11:30～14:30(L.O.14:00)\n土 ランチ：12:00～17...</td>
      <td>そば</td>
      <td></td>
      <td>http://mobile.gnavi.co.jp/shop/6421849/?ak=m%2...</td>
      <td></td>
    </tr>
    <tr>
      <th>4</th>
      <td>1046494</td>
      <td>炉ばた 陣や</td>
      <td>139.712244</td>
      <td>35.647473</td>
      <td></td>
      <td>月～金 ランチ：11:30～14:00(L.O.13:30)、ディナー：17:00～23:3...</td>
      <td>居酒屋</td>
      <td></td>
      <td>http://mobile.gnavi.co.jp/shop/1046494/?ak=m%2...</td>
      <td></td>
    </tr>
  </tbody>
</table>
</div>



次に取得した飲食店の口コミを収集します。shop_idは1リクエストにつき10個までカンマ区切りにして送ることができます。APIのリクエスト制限が開発モードでは1日に1000回なので、10個ずつ送ってリクエスト数を節約しました。返り値が少し複雑、、エラーが返ってくるときはキーが「gnavi」になって返ってくるので、gnaviが含まれる場合にエラーをキャッチして、それ以外は結果をとりあえず残すようにしました


```python
shop_ids = df_shopinfo.id.values.tolist() ## 取得した飲食店のidのリスト
url = 'https://api.gnavi.co.jp/PhotoSearchAPI/v3/' ## 応援口コミAPIのエンドポイント 
reviews = gnavi.get_shop_review(url, shop_ids)
```


```python
reviews[0]
```




    {'response': {'@attributes': {'api_version': 'v3'},
      'total_hit_count': 12,
      'hit_per_page': 15,
      '0': {'photo': {'vote_id': '97774',
        'photo_genre_id': '1',
        'photo_genre_name': '料理・ドリンク',
        'photo_scene_id': '',
        'photo_scene_name': '',
        'nickname': 'cocoronron',
        'shop_id': '5237768',
        'shop_name': 'IL BOCCALONE',
        'shop_url': 'https://r.gnavi.co.jp/j9x8tn8b0000/?ak=m%2Bqqz7dSuc6%2FTCXqzE3tXC%2FHVysBRwNGyp5Ud0dSNe8%3D',
        'prefname': 'PREF13:東京都',
        'menu_id': 92658,
        'menu_name': '黒キャベツのパスタ',
        'menu_finish_flag': 0,
        'areaname_l': '恵比寿・中目黒・目黒',
        'areaname_m': '恵比寿',
        'areaname_s': '恵比寿（広尾・ガーデンプレイス方面）',
        'image_url': {'url_1024': 'https://mr.gnavi.co.jp/cont/menu_image/ce/83/97774_l.jpeg',
         'url_320': 'https://mr.gnavi.co.jp/cont/menu_image/ce/83/97774.jpeg',
         'url_250': 'https://mr.gnavi.co.jp/cont/menu_image/ce/83/97774_m.jpeg',
         'url_200': 'https://mr.gnavi.co.jp/cont/menu_image/ce/83/97774_s.jpeg'},
        'comment': 'フィットチーネが濃厚ソースに絡んでて美味しかったです！\r\n黒キャベツとはいえども、思ったより、重たい。',
        'total_score': '3.0',
        'category': 'イタリアン',
        'latitude': '35.647784',
        'longitude': '139.712111',
        'umaso_count': 0,
        'update_date': '2011-01-04T16:26:40+09:00',
        'messages': {'user_message_count': 0,
         'shop_message_count': 0,
         'first_shop_message': {'message_body': '', 'send_date': ''}}}},
      '1': {'photo': {'vote_id': '300779',
        'photo_genre_id': '1',
        'photo_genre_name': '料理・ドリンク',
        'photo_scene_id': '',
        'photo_scene_name': '',
        'nickname': 'yukikos',
        'shop_id': '5237768',
        'shop_name': 'IL BOCCALONE',
        'shop_url': 'https://r.gnavi.co.jp/j9x8tn8b0000/?ak=m%2Bqqz7dSuc6%2FTCXqzE3tXC%2FHVysBRwNGyp5Ud0dSNe8%3D',
        'prefname': 'PREF13:東京都',
        'menu_id': 29952,
        'menu_name': 'パルメザンチーズのリゾット',
        'menu_finish_flag': 0,
        'areaname_l': '恵比寿・中目黒・目黒',
        'areaname_m': '恵比寿',
        'areaname_s': '恵比寿（広尾・ガーデンプレイス方面）',
        'image_url': {'url_1024': 'https://mr.gnavi.co.jp/cont/menu_image/ce/83/300779_l.jpeg',
         'url_320': 'https://mr.gnavi.co.jp/cont/menu_image/ce/83/300779.jpeg',
         'url_250': 'https://mr.gnavi.co.jp/cont/menu_image/ce/83/300779_m.jpeg',
         'url_200': 'https://mr.gnavi.co.jp/cont/menu_image/ce/83/300779_s.jpeg'},
        'comment': '定番のパルメザンチーズのリゾットは、\r\nチーズ丸ごとの迫力だけじゃなく、濃い味もクセになる。',
        'total_score': '3.0',
        'category': 'イタリアン',
        'latitude': '35.647784',
        'longitude': '139.712111',
        'umaso_count': 0,
        'update_date': '2011-01-31T17:56:25+09:00',
        'messages': {'user_message_count': 0,
         'shop_message_count': 0,
         'first_shop_message': {'message_body': '', 'send_date': ''}}}},・・・以下省略}}



数字がキーになっているところがひとつひとつのお店の情報になっているっぽいので、強引ですが「attributes」、 「total_hit_count」、「hit_per_page」を避けてshop_idとcommentだけを取得します。(total_hit_countやhit_per_pageの値分、お店の情報があるわけでもなさそうでした)


```python
shop_id_comment_list = []

for shop_reviews in reviews:
    for k, v in shop_reviews['response'].items():
        if k in ['@attributes', 'total_hit_count', 'hit_per_page']:
            continue
            
        shop_id = v['photo']['shop_id']
        comment = v['photo']['comment']
        
        shop_id_comment_list.append({
            'shop_id':shop_id,
            'comment':comment,
        })
```


```python
df_shop_review = pd.DataFrame(shop_id_comment_list)
df_shop_review = df_shop_review.dropna(subset=['comment']) ## コメントがないところは削除
df_shop_review = df_shop_review.query('comment != ""') ## コメントがないところは削除
df_shop_review.head()
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>shop_id</th>
      <th>comment</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>5237768</td>
      <td>フィットチーネが濃厚ソースに絡んでて美味しかったです！\r\n黒キャベツとはいえども、思った...</td>
    </tr>
    <tr>
      <th>1</th>
      <td>5237768</td>
      <td>定番のパルメザンチーズのリゾットは、\r\nチーズ丸ごとの迫力だけじゃなく、濃い味もクセになる。</td>
    </tr>
    <tr>
      <th>2</th>
      <td>1046494</td>
      <td>かき氷の上に小さな小瓶がさしてあり、しっかりと冷やしてあります。\r\nうにとオクラが入った...</td>
    </tr>
    <tr>
      <th>3</th>
      <td>g818801</td>
      <td>サラダの取り放題がついてます！パエリヤなのに出てくるのが早くて、忙しい方にもオススメ！</td>
    </tr>
    <tr>
      <th>4</th>
      <td>1046494</td>
      <td>食べごたえのある唐揚げと、温玉がのった鶏そぼろ丼でボリューム満点でした！</td>
    </tr>
  </tbody>
</table>
</div>



## 軽くクレンジング
そんなに汚いデータではなさそうですが、記号やurlの削除はしておきます


```python
import re

def cleansing(text):
    text= re.sub(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-…]+', "", text)#URL
    text = re.sub(r"[0-9]+", "0", text)#数字を0に
    text = re.sub(r"[!-/]", "", text)#半角記号
    text = re.sub(r"[:-@]", "", text)#半角記号
    text = re.sub(r"[[-`]", "", text)#半角記号
    text = re.sub(r"[{|}-]", "", text)#半角記号
    text = re.sub(r"[”’（）【】〔〕《》＝〜『』「」＋＊、。・＿？！／◀▲：]", "", text)#全角記号
    text = re.sub("\n", "", text)#改行
    text = re.sub("\r", "", text)#改行
    
    return text

df_shop_review['comment'] = df_shop_review['comment'].apply(lambda x: cleansing(x))
```

## 形態素解析
これはなくてもよかったかもしれませんが、入力されたキーワードがコメントに含まれているかだけだと、言葉が揺れそうなので念のため単語の原形のリストも作ってみます。原形にしたいだけなので品詞の選択とかもしません。


```python
import MeCab

mecab = MeCab.Tagger("-d /usr/local/lib/mecab/dic/mecab-ipadic-neologd")

def tokenizer(text):
    node = mecab.parseToNode(text)
    res = []
    
    while node:
        base = node.feature.split(",")[6]
        if base != '*':
            res.append(base)
            
        node = node.next
        
    return res
```


```python
df_shop_review['wakati'] = df_shop_review['comment'].apply(lambda x: tokenizer(x))
df_shop_review.head()
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>shop_id</th>
      <th>comment</th>
      <th>wakati</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>5237768</td>
      <td>フィットチーネが濃厚ソースに絡んでて美味しかったです黒キャベツとはいえども思ったより重たい</td>
      <td>[フィットチーネ, が, 濃厚, ソース, に, 絡む, で, てる, 美味しい, た, で...</td>
    </tr>
    <tr>
      <th>1</th>
      <td>5237768</td>
      <td>定番のパルメザンチーズのリゾットはチーズ丸ごとの迫力だけじゃなく濃い味もクセになる</td>
      <td>[定番, の, パルメザンチーズ, の, リゾット, は, チーズ, 丸ごと, の, 迫力,...</td>
    </tr>
    <tr>
      <th>2</th>
      <td>1046494</td>
      <td>かき氷の上に小さな小瓶がさしてありしっかりと冷やしてありますうにとオクラが入ったものうにとゆ...</td>
      <td>[かき氷, の, 上, に, 小さな, 小瓶, が, さして, ある, しっかり, と, 冷...</td>
    </tr>
    <tr>
      <th>3</th>
      <td>g818801</td>
      <td>サラダの取り放題がついてますパエリヤなのに出てくるのが早くて忙しい方にもオススメ</td>
      <td>[サラダ, の, 取る, 放題, が, つく, て, ます, パエリヤ, だ, の, に, ...</td>
    </tr>
    <tr>
      <th>4</th>
      <td>1046494</td>
      <td>食べごたえのある唐揚げと温玉がのった鶏そぼろ丼でボリューム満点でした</td>
      <td>[食べる, ごたえ, の, ある, 唐, 揚げ, と, オンセンタマゴ, が, のる, た,...</td>
    </tr>
  </tbody>
</table>
</div>



少し無理やり店舗ごとのデータにします


```python
df_shop_review = df_shop_review.groupby('shop_id').sum().reset_index()
df_shop_review.head()
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>shop_id</th>
      <th>comment</th>
      <th>wakati</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>0036388</td>
      <td>ほんのりラムの香りが広がるたたき柔らかくて美味ですお店がオススメとうたうだけのことはあります...</td>
      <td>[ほんのり, ラム, の, 香り, が, 広がる, たたき, 柔らかい, て, 美味, です...</td>
    </tr>
    <tr>
      <th>1</th>
      <td>0222320</td>
      <td>ボリューム満点</td>
      <td>[ボリューム, 満点]</td>
    </tr>
    <tr>
      <th>2</th>
      <td>1005712</td>
      <td>雰囲気がとても落ち着いていて大人な空間ですおそばはコシがあってとってもおいしいです鴨汁はとて...</td>
      <td>[雰囲気, が, とても, 落ち着く, て, いる, て, 大人, だ, 空間, です, お...</td>
    </tr>
    <tr>
      <th>3</th>
      <td>1009522</td>
      <td>お肉や魚介をはじめ0種類以上の季節の野菜を花椒や四川特産の朝天唐辛子で香り高く炒めつつさらに...</td>
      <td>[お肉。, や, 魚介, を, はじめ, 0種類, 以上, の, 季節, の, 野菜, を,...</td>
    </tr>
    <tr>
      <th>4</th>
      <td>1012998</td>
      <td>さっぱりとした薫りの蕎麦は濃いめのつゆと併せてすっきりした美味しさでしたこりこりしてておいし...</td>
      <td>[さっぱり, と, する, た, 薫り, の, 蕎麦, は, 濃いめ, の, つゆ, と, ...</td>
    </tr>
  </tbody>
</table>
</div>



最初に取得した店舗情報とマージします


```python
df_shop_data = pd.merge(df_shopinfo, df_shop_review.rename(columns={'shop_id':'id'}), on='id', how='inner')
df_shop_data
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>id</th>
      <th>name</th>
      <th>longitude</th>
      <th>latitude</th>
      <th>holiday</th>
      <th>opentime</th>
      <th>category</th>
      <th>pr</th>
      <th>url_mobile</th>
      <th>image_url</th>
      <th>comment</th>
      <th>wakati</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>1046494</td>
      <td>炉ばた 陣や</td>
      <td>139.712244</td>
      <td>35.647473</td>
      <td></td>
      <td>月～金 ランチ：11:30～14:00(L.O.13:30)、ディナー：17:00～23:3...</td>
      <td>居酒屋</td>
      <td></td>
      <td>http://mobile.gnavi.co.jp/shop/1046494/?ak=m%2...</td>
      <td></td>
      <td>かき氷の上に小さな小瓶がさしてありしっかりと冷やしてありますうにとオクラが入ったものうにとゆ...</td>
      <td>[かき氷, の, 上, に, 小さな, 小瓶, が, さして, ある, しっかり, と, 冷...</td>
    </tr>
    <tr>
      <th>1</th>
      <td>5237768</td>
      <td>IL BOCCALONE</td>
      <td>139.712111</td>
      <td>35.647784</td>
      <td></td>
      <td>月～土 17:30～24:00(L.O.23:00)\n日 17:30～23:00(L.O....</td>
      <td>イタリアン</td>
      <td></td>
      <td>http://mobile.gnavi.co.jp/shop/5237768/?ak=m%2...</td>
      <td></td>
      <td>フィットチーネが濃厚ソースに絡んでて美味しかったです黒キャベツとはいえども思ったより重たい定...</td>
      <td>[フィットチーネ, が, 濃厚, ソース, に, 絡む, で, てる, 美味しい, た, で...</td>
    </tr>
    <tr>
      <th>2</th>
      <td>g818801</td>
      <td>サラ・アンダルーサ</td>
      <td>139.713295</td>
      <td>35.647946</td>
      <td>毎週土・日曜日 祝日</td>
      <td>月～金 ランチ：11:30～15:00(L.O.14:30)(イベント開催時は営業時間を短縮...</td>
      <td>貸切スペインダイニング</td>
      <td>[JR恵比寿駅 徒歩5分] 常設ステージあり！本格フラメンコショーも楽しめるスペインレストラ...</td>
      <td>http://mobile.gnavi.co.jp/shop/g818801/?ak=m%2...</td>
      <td>https://rimage.gnst.jp/rest/img/mdayd13d0000/t...</td>
      <td>サラダの取り放題がついてますパエリヤなのに出てくるのが早くて忙しい方にもオススメ</td>
      <td>[サラダ, の, 取る, 放題, が, つく, て, ます, パエリヤ, だ, の, に, ...</td>
    </tr>
    <tr>
      <th>3</th>
      <td>5351809</td>
      <td>アンクルトム</td>
      <td>139.711817</td>
      <td>35.647634</td>
      <td></td>
      <td></td>
      <td>パスタ</td>
      <td></td>
      <td>http://mobile.gnavi.co.jp/shop/5351809/?ak=m%2...</td>
      <td></td>
      <td>少なくとも１５年以上前からやってる恵比寿を代表するスパゲティ屋さんですイタリアレストランでは...</td>
      <td>[少なくとも, 15年, 以上, 前, から, やる, てる, 恵比寿, を, 代表, する...</td>
    </tr>
    <tr>
      <th>4</th>
      <td>5828891</td>
      <td>瞠　－miharu－　恵比寿店</td>
      <td>139.711572</td>
      <td>35.647729</td>
      <td>無</td>
      <td>月～日 ランチ・ディナー：11:00～22:00</td>
      <td>ラーメン店</td>
      <td>あのグルメランキング番組の「池袋ラーメン」で第2位。雑誌掲載30誌以上。絶品の濃厚魚介豚骨ス...</td>
      <td>http://mobile.gnavi.co.jp/shop/5828891/?ak=m%2...</td>
      <td></td>
      <td>おいしいです節系のスープが美味わりとシンプルなので飽きずに食べられそう濃いめのスープもっちり...</td>
      <td>[おいしい, です, 節, 系, の, スープ, が, 美味, わりと, シンプル, だ, ...</td>
    </tr>
    <tr>
      <th>...</th>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
      <td>...</td>
    </tr>
    <tr>
      <th>204</th>
      <td>6075267</td>
      <td>ura ebis．</td>
      <td>139.707195</td>
      <td>35.648345</td>
      <td>無</td>
      <td></td>
      <td>ビストロ</td>
      <td></td>
      <td>http://mobile.gnavi.co.jp/shop/6075267/?ak=m%2...</td>
      <td></td>
      <td>とろ～りチーズのとろけたハンバーグトマトソースで酸味があってわりとさっぱり味お肉はあいびきで...</td>
      <td>[とろーり, チーズ, の, とろける, た, ハンバーグ, トマトソース, で, 酸味, ...</td>
    </tr>
    <tr>
      <th>205</th>
      <td>7714899</td>
      <td>ライオンのいるサーカス</td>
      <td>139.707796</td>
      <td>35.645582</td>
      <td></td>
      <td></td>
      <td>イタリアン</td>
      <td></td>
      <td>http://mobile.gnavi.co.jp/shop/7714899/?ak=m%2...</td>
      <td></td>
      <td>ツケナポライオンのいるサーカス　ライオンはいないです笑恵比寿駅西口から恵比寿銀座を歩いて信号...</td>
      <td>[の, いる, サーカス, 　, ライオン, は, いる, ない, です, 笑, 恵比寿駅,...</td>
    </tr>
    <tr>
      <th>206</th>
      <td>g212700</td>
      <td>Ｌｅ Ｐａｒｃ 恵比寿店</td>
      <td>139.707129</td>
      <td>35.646899</td>
      <td>年中無休\n年末年始（2020年12月31日～2021年1月2日）</td>
      <td>月～金 ランチ：11:30～15:00(L.O.14:30)、ディナー：17:00～22:0...</td>
      <td>香港飲茶・広東料理</td>
      <td>本場香港の点心師が作るヌーベルシノワ 四季を感じる洋風な店内でワインと共に本格中華を！ ラン...</td>
      <td>http://mobile.gnavi.co.jp/shop/g212700/?ak=m%2...</td>
      <td>https://rimage.gnst.jp/rest/img/9nfw23cg0000/t...</td>
      <td>甘めのマヨネーズがちょっと重いですエビの量は多くて満足エビ餃子ニラ餃子カニ焼売他にも揚げもの...</td>
      <td>[甘い, め, の, マヨネーズ, が, ちょっと, 重い, です, エビ, の, 量, は...</td>
    </tr>
    <tr>
      <th>207</th>
      <td>5429747</td>
      <td>串いろいろとわっぱ飯 民家</td>
      <td>139.707606</td>
      <td>35.645810</td>
      <td>毎週月曜日</td>
      <td>火～日 16:00～24:00(L.O.23:00)</td>
      <td>串揚げ居酒屋</td>
      <td>【恵比寿徒歩3分】民家黄金伝説コース★料理2,500円当日もOK\n　　＋1,800円で飲み...</td>
      <td>http://mobile.gnavi.co.jp/shop/5429747/?ak=m%2...</td>
      <td></td>
      <td>鮭とイクラの入ったわっぱ飯ですこれは美味けっこうボリュームがありました♪午後７時までのお得な...</td>
      <td>[鮭, と, イクラ, の, 入る, た, わっぱ, 飯, です, これ, は, 美味, け...</td>
    </tr>
    <tr>
      <th>208</th>
      <td>7385242</td>
      <td>俺のBakery＆Cafe</td>
      <td>139.713192</td>
      <td>35.643260</td>
      <td>不定休日あり</td>
      <td>カフェ：8:00～21:00(L.O.20:00)(食パン販売　10：00～21：00)</td>
      <td>俺のシリーズのカフェ</td>
      <td>俺のシリーズの新業態『俺のBakery&amp;Cafe』\n当店の自慢の食パンを是非、お召し上がり...</td>
      <td>http://mobile.gnavi.co.jp/shop/7385242/?ak=m%2...</td>
      <td></td>
      <td>ふわふわのたまごですが食べたら濃く濃くとたまごの旨味が染み渡りますパンも生食パン仕様でめっち...</td>
      <td>[ふわふわ, の, たまご, です, が, 食べる, た, 濃い, 濃い, と, たまご, ...</td>
    </tr>
  </tbody>
</table>
<p>209 rows × 12 columns</p>
</div>



レビューコメントがあるお店が少なかったので、結構減りました

## 単語を入力して単語がレビューコメントに含まれる店を出力
入力を受け取って、受け取った単語がレビューコメントに含まれているお店を出力します。
個人的にいろんなお店や行ったことないお店を開拓したいので、検索条件は緩めにORにします。条件に引っかかるお店が3つ以上ある場合はランダムで3個返します


```python
while True:
    input_words = input("単語をカンマ区切りで入力してね>  ").replace(' ', '').split(',')
    
    selected = []
    
    if input_words[0] == 'exit' or input_words[0] == "":
        break
            
    for shop_id, wakati, comment in df_shop_data[['id', 'wakati','comment']].values:
        for word in input_words:
            if word in wakati or word in comment:
                selected.append(shop_id)
                break
                
    if df_shop_data.query('id in @selected').empty:
        print('そんな店はない')
    else:
        for name, category, pr in df_shop_data.query('id in @selected').sample(n=3)[['name', 'category', 'pr']].values:
            print("店名: " + name)
            print('カテゴリー: ' + category)
            print('PR: ' + pr)
            print('')
```

    単語を入力してね>  馬, イタリアン
    店名: Mother earth cafe restaurant 【マザーアースカフェレストラン】
    カテゴリー: カフェ
    PR: 
    
    店名: 肉寿司 恵比寿横丁店
    カテゴリー: 肉寿司
    PR: 牛・馬肉を中心とした肉専門の握り寿司それが肉寿司!!！
    
    朝５時まで元気に営業中！
    名物さしとろは食べるしかない！
    
    店名: 九州 熱中屋 恵比寿 LIVE
    カテゴリー: 恵比寿 九州 居酒屋
    PR: 【恵比寿】西口徒歩1分の駅近九州料理居酒屋 ■最大32名様 活豊後サバ刺し・鉄板餃子が自慢の一品!! ■当日予約OK!!各種ご宴会に…飲み放題付コース多数あり!!
    
    単語を入力してね>  


## 終わりに
雑めな感じになってしまいましたが、とりあえず会社の近くにあるお店をたくさん知ることができて満足です。APIネタ被りしてしまってすみませんでした。ぐるなびのクチコミは思ったより少ないですね。
次回の記事ではこれをサーバーレスなwebアプリにできたらいいなと思います。

## 参考にさせていただいたサイト
- [ぐるなびAPIをpythonで呼び出してみた](https://houdoukyokucho.com/2020/04/21/post-772/)
- [Google Colaboratoryでword2vec②](https://deepblue-ts.co.jp/%E8%87%AA%E7%84%B6%E8%A8%80%E8%AA%9E%E5%87%A6%E7%90%86/google-colaboratory%E3%81%A7word2vec%E2%91%A1/)