GiNZA入門3（基本操作編2、チャットボット作成編）（基本的な使い方マスターを目指す方向け） 

こんにちにゃんです。
GiNZAに関する記事3本目です。
この記事では固有表現抽出と類似度計算、簡単なチャットボット作成について書いていこうと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2847349/77c431e2-e111-7968-fa84-51f8ec740471.png)
GiNZAで出来ること４つ目は固有表現抽出です。固有表現は固有名詞や人名のことです。

```ruby:ent.py
#④固有表現抽出
doc=nlp('今日は銀座で花さんと買い物をした。')
for ent in doc.ents:  #固有表現（エンティティ）群から固有表現を一つずつ抽出
    print(
        ent.text+', '+   #固有表現
        ent.label_+', '+  #固有表現の種類
        str(ent.start_char)+', '+  #開始位置
        str(ent.end_char)  #終了位置
    )
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2847349/d46a9597-e651-2901-d50d-91796fe2302f.png)

GiNZAでは一般名詞に近い人名は固有名詞として認識されない場合があります。例えば「花さん」という人名は固有表現と認識されていません。
GiNZA electraというGiNZAの改良版を用いると固有表現がうまく抽出できる場合が多くなります。しかし、GiNZA　electraは次に説明する類似度計算がうまく行えない場合があるのであまりお勧めできません。

GiNZAでできること５つ目は類似度計算です。類似度計算は文同士の類似度（どのくらい似ているか）を計算して表示します。

```ruby:simil.py
#⑤類似度計算
doc=nlp('今日は銀座で花さんと買い物をした。')  #GiNZAで解析
r= nlp('今日はすすき野で花さんとピクニックをした。')  #GiNZAで解析
num=doc.similarity(r)  #類似度を計算
print(num)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2847349/276a34e3-2324-2ddd-e08d-797cbbf7a4b5.png)
類似度計算を使うことで簡単なチャットボットを作ることが可能です。
入力した文章と最も類似度の高い文章を返すというプログラムを書くことで、簡単な質問に答えたりすることができます。

```ruby:nlp_science.py
#必要なモジュールをインポート
import spacy
import random
import tkinter as tk 

#tkinterを用いてGUIを作成
root = tk.Tk() #画面を表示
root.title(u'科学技術解説プログラムEIMI') #タイトルを表示
root.geometry('670x450') #画面サイズを定義
img=tk.PhotoImage(file='star.png') #背景の画像を選択。使う場合は画像名を変更してください。
cvs=tk.Canvas(width=670,height=400) #画像を表示するキャンバスを定義
cvs.pack() #キャンバスを表示
cvs.create_image(330,200,image=img) #キャンバスに画像を表示
txt='こんにちは。何か質問はある？' #最初に出力する文章
msg=tk.Label(text=txt,fg='black',bg='SeaGreen1') #文章を表示するためのラベルを定義
msg.place(x=670-len(txt)*11,y=10) #ラベルの表示

nlp = spacy.load('ja_ginza') #GiNZAのロード
t=1 #ラベルの位置を決定するための変数

#送信ボタンが押されると実行される関数
def ask_from_bot():
  global t
  s=textF.get() #入力された文章を取得
  msg=tk.Label(text=s,fg='black',bg='SeaGreen1') #文章を表示するためのラベルを定義
  msg.place(x=10,y=11.5+t*20) #ラベルの表示
  textF.delete(0,'end') #テキストボックス内の文章を削除
  i=0
  doc=nlp(s) #GiNZAで入力文章を解析
  with open('nlp_perfect.txt',encoding='utf-8_sig') as m: #想定返答集のロード（使う場合はファイル名を変更してください）
     r=m.read().split('\n') #\nで一つ一つの文章が区切られているので、\nごとに分解して配列化
  
  float_list=[] #計算した類似度を保持する配列
  for i in range(len(r)):
     k = nlp(r[i]) #想定返答集のi番目の文章の解析
     float_list.append(doc.similarity(k)) #類似度を計算し、float_listに格納
     i=i+1 
     j=float_list.index(max(float_list)) #最も類似度の高かった文章のインデックスを取得
  if max(float_list)<0.7: #類似度が低すぎる場合（ここの条件（０．７以上）は適宜変えてください）
     txt='僕はAIだからこういう時どう返せばいいかわからないかな。' 
     msg=tk.Label(text=txt,fg='black',bg='SeaGreen1')
     msg.place(x=670-len(txt)*10,y=10+(t+1)*20)
     
  if max(float_list)>0.7: #類似度がある程度高い場合
     txt=r[j]
     msg=tk.Label(text=txt,fg='black',bg='SeaGreen1')
     msg.place(x=670-len(txt)*11.5,y=10+(t+1)*20)  
  t=t+2

#ボタンとテキストボックスの定義
btn=tk.Button(root,text='送信',font=('utf-8_sig',10),bg='cyan',command=ask_from_bot)
btn.pack(side='right')
textF=tk.Entry(root,font=('utf-8_sig',15),width=50)
textF.pack(side='right')
#画面の保持
root.mainloop()
```

チャットボットのコードはこのような感じです。想定返答集と入力文章との類似度を計算し、最も類似度の高い返答を返すようにプログラムしてあります。詳しいことはプログラム内の説明を参照してください。
実行結果は次のような感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2847349/460cd5bf-25bf-a007-4a14-5353223998dd.png)
良い感じに返答ができています。皆さんもぜひチャットボットを作ってみてください。
もし記事が良いと思ってもらえたら、良いねボタンを押したり、twitterまで遊びに来てくれるとうれしいです❕

次は感情分析プログラムに関して書くつもりです。
では、ばいにゃん～


参考にさせていただいた記事
https://qiita.com/poyo46/items/7a4965455a8a2b2d2971