當前位置: 首頁>>技術教程>>正文


在Python中從零開始構建一個簡單的聊天機器人(使用NLTK)

什麽是聊天機器人?

一個聊天機器人(ChatBot)是一個基於人工智能的軟件設備(例如,Siri,Alexa,Google Assistant等)。在應用程序,網站或其他網絡中,ChatBot通常用於理解消費者的需求,然後協助他們執行特定的任務,如商業交易,酒店預訂,表格提交等。今天幾乎每家公司都部署了一個聊天機器人與用戶互動。公司使用聊天機器人的一些方式是:

  • 提供航班信息
  • 連接客戶和他們的財務
  • 作為客戶支持

不一而足,有無限種應用可能性。

聊天機器人的曆史可以追溯到1966年,當時Weizenbaum發明了一種名為ELIZA的計算機程序。它隻用200行代碼模仿心理治療師的語言。你仍然可以在這裏與它交談:伊麗莎

源: Cognizant

Chatbots如何運作?

大致有兩種變體聊天機器人:基於規則的(Rule-Based)自學習(Self Learning)。

  1. Rule-based方法,機器人根據訓練的一些規則來回答問題。定義的規則可以從非常簡單到非常複雜。這類方法,機器人可以處理簡單的查詢,但無法管理複雜的查詢。
  2. 自學習機器人基於機器學習方法,並且肯定比rule-based機器人更有效。這種機器人是另外兩種類型:檢索型 (Retrieval Based)或者 生成型(Generative)。

i)Retrieval-based型:聊天機器人使用一些啟發式方法從預定義響應庫中選擇響應。聊天機器人使用對話的消息和上下文,從預定義的機器人消息列表中選擇最佳響應。上下文可以包括對話樹中的當前位置,對話中的所有先前消息,先前保存的變量(例如,用戶名)。用於選擇響應的啟發式方法可以以多種不同方式設計,從rule-based if-else條件邏輯到機器學習分類器都是可以的。

II)Generative機器人可以生成答案,而並不總是回複一組已固定答案中的某一個。這使得它們更加智能,因為它從查詢中逐字逐句地生成答案。

在本文中,我們將在python中基於NLTK庫構建一個簡單的基於檢索的聊天機器人。

建立機器人

準備工作

了解scikit Library 和NLTK。但是,如果您不熟悉NLP,您仍然可以閱讀該文章,然後再參考資源進行理解。

NLP

專注於人類語言和計算機之間相互作用的研究領域稱為自然語言處理(簡稱NLP)。它位於計算機科學,人工智能和計算語言學的交叉點。NLP是計算機以智能和有用的方式分析,理解和從人類語言中獲得意義的一種方式。通過利用NLP,開發人員可以組織和構建知識,以執行自動摘要,翻譯,命名實體識別,關係提取,情感分析,語音識別和主題分割等任務。

NLTK:簡介

NLTK(自然語言工具包)是用於構建Python程序以使用人類語言數據的領先平台。它提供易於使用的接口,超過50個語料庫和詞匯資源,例如WordNet,以及用於分類,分詞,詞幹化,標記,解析和語義推理的一套文本處理庫,是非常優秀的NLP工具包。

NLTK被稱為“一個很好的教學和工作工具,使用Python的計算語言學”,以及“一個玩自然語言的神奇 Library ”。

Python的自然語言處理提供了語言處理編程的實用介紹。我強烈推薦這本書給那些開始使用Python學習NLP的人。

下載並安裝NLTK

  1. 安裝NLTK:運行pip install nltk
  2. 測試安裝:運行python然後鍵入import nltk

有關platform-specific的說明,請閱讀這裏

安裝NLTK包

導入NLTK並運行nltk.download().這將打開NLTK下載器,您可以從中選擇要下載的語料庫和模型。您也可以一次下載所有包。

使用NLTK進行文本預處理

文本數據的主要問題是它都是文本格式(字符串)。但是,機器學習算法需要某種數值特征向量才能執行任務。因此,在我們開始任何NLP項目之前,我們需要使用預處理(pre-processing)。基本文字pre-processing包括:

  • 將整個文本轉換為大寫或小寫。因此,算法不會將不同情況下的相同單詞視為不同。
  • 符號化(Tokenization):Token化隻是用於描述將普通文本字符串轉換為Token列表(即我們實際需要的單詞)的過程的術語。 Sentence tokenizer可用於查找句子列表,Word tokenizer可用於查找字符串中的單詞列表。

NLTK數據包包括用於英語語境的預訓練的Punkt標記器。

  • 刪除噪聲即所有不符合標準數字或字母的東西。
  • 刪除停用詞(Stop Words)有時,一些非常常見的單詞在幫助選擇符合用戶需求的文檔時似乎沒什麽價值,完全從詞匯表中排除。這些話被稱為停用詞。
  • 詞幹:詞幹是將變形(或有時衍生)的詞減少到它們的詞幹,詞根或詞形的過程 – 通常是書麵文字形式。例如,如果我們對以下次做詞幹化處理的話:“Stems”,“Stemming”,“Stemmed”,“and Stemtization”,結果將是單字“stem”。
  • 詞形還原:詞幹化的一個輕微變體是詞形還原。二者主要區別在於,詞幹通常可以創建不存在的詞,而詞詞形還原得到的是實際詞。詞形還原的示例是“run”是諸如“running”或“ran”之類的單詞的基本形式,或者單詞“better”和“good”有相同的詞形,因此它們被認為是相同的。

詞袋(Bag of Words)

在初始預處理階段之後,我們需要將文本轉換為有意義的數字向量(或數組)。 bag-of-words是文本的表示,用於描述文檔中單詞的出現。它涉及兩件事:

•已知單詞的詞匯表。

•衡量已知單詞的存在。

為什麽稱它為詞袋(Bag-Of-Words)?這是因為關於文檔中單詞的順序或結構的任何信息都被丟棄,而模型隻關注已知單詞是否出現在文檔中,而不是出現在文檔中的位置。

Bag of Words背後的直覺是,如果文檔具有相似的內容詞,則它們是相似的。

例如,如果我們的字典包含單詞{Learning,is,the,not,great},並且我們想要對文本“Learning is great”進行矢量化,那麽我們將得到以下向量:(1,1,0,0,1)。

TF-IDF方法

Bag of Words方法的一個問題是高頻率的單詞在文檔中開始占主導地位(例如,得分較高),但可能包含的信息量有限。此外,與較短的文檔相比,詞袋使更長的文檔權重更高。

一種方法是通過它們在所有文檔中出現的頻率來重新調整單詞的頻率,使得在所有文檔中頻繁出現的頻繁單詞(如“the”)的分數受到懲罰。這種評分方法被稱為詞頻率逆文檔頻率(Term Frequency-Inverse Document Frequency), 即TF-IDF,其中:

單詞頻率:是當前文檔中單詞頻率的得分。

TF = (Number of times term t appears in a document)/(Number of terms in the document)

逆文檔頻率:這是該單詞在文檔中的罕見程度得分。

IDF = 1+log(N/n), where, N is the number of documents and n is the number of documents a term t has appeared in.

Tf-idf權重是經常用於信息檢索和文本挖掘的權重。此權重是用於評估單詞對集合或語料庫中的文檔的重要程度的統計度量,

例:

考慮一個包含100個單詞的文檔,其中“phone”一詞出現5次。

然後,phone的單詞頻率(即,tf)是(5/100)= 0.05。現在,假設我們有1000萬個文檔,其中一千個文字出現“phone”。然後,逆文檔頻率(即IDF)被計算為log(10,000,000 /1,000)= 4.因此,Tf-IDF權重是這些量的乘積:0.05 * 4 = 0.20。

Tf-IDF可以使用scikit Learn實現:

從sklearn.feature_extraction.text導入TfidfVectorizer

餘弦相似度

TF-IDF是應用於文本的變換,以在向量空間中獲得兩個實數向量。然後我們可以獲得餘弦:通過獲取它們的點積並將其除以它們的標準化的乘積來表示任何一對矢量的相似性。使用以下公式,我們可以找出任何兩個文件d1和d2之間的相似性。

Cosine Similarity (d1, d2) =  Dot product(d1, d2) / ||d1|| * ||d2||

其中d1,d2是兩個非零向量。

有關TF-IDF和餘弦相似性的詳細說明和實際示例,請參閱以下文檔《Tf-Idf and Cosine similarity》。

 

現在我們對NLP流程有了一個初步的了解。現在是我們實現真正任務的時候了,即Chatbot的創建。下文中將聊天機器人命名為’ROBO’

導入(import)必須的庫


import nltk
import numpy as np
import random
import string # to process standard python strings

語料

對於我們的示例,我們將使用維基百科Chatbot頁麵作為我們聊天機器人的語料庫。複製頁麵中的內容並將其放在名為“chatbot.txt”的文本文件中。但是,您也可以使用您選擇的任何語料庫。

讀取數據

我們將讀入corpus.txt文件並將整個語料庫轉換為句子列表和單詞列表以供進一步預處理。


f=open('chatbot.txt','r',errors = 'ignore')
raw=f.read()
raw=raw.lower()# converts to lowercase
nltk.download('punkt') # first-time use only
nltk.download('wordnet') # first-time use only
sent_tokens = nltk.sent_tokenize(raw)# converts to list of sentences 
word_tokens = nltk.word_tokenize(raw)# converts to list of words

讓我們看一下sent_tokens和word_tokens的例子


sent_tokens[:2]
['a chatbot (also known as a talkbot, chatterbot, bot, im bot, interactive agent, or artificial conversational entity) is a computer program or an artificial intelligence which conducts a conversation via auditory or textual methods.',
 'such programs are often designed to convincingly simulate how a human would behave as a conversational partner, thereby passing the turing test.']
word_tokens[:2]
['a', 'chatbot', '(', 'also', 'known']

預處理原始文本

我們現在將定義一個名為LemTokens的函數,該函數將Token作為輸入並返回規範化的Tokens。


lemmer = nltk.stem.WordNetLemmatizer()
#WordNet is a semantically-oriented dictionary of English included in NLTK.
def LemTokens(tokens):
    return [lemmer.lemmatize(token) for token in tokens]
remove_punct_dict = dict((ord(punct), None) for punct in string.punctuation)
def LemNormalize(text):
    return LemTokens(nltk.word_tokenize(text.lower().translate(remove_punct_dict)))

關鍵詞匹配

接下來,我們將為機器人定義一個問候函數,即如果用戶的輸入是問候語,機器人將返回問候語響應.ELIZA使用簡單的關鍵字匹配問候語。我們將在這裏使用相同的概念。


GREETING_INPUTS = ("hello", "hi", "greetings", "sup", "what's up","hey",)
GREETING_RESPONSES = ["hi", "hey", "*nods*", "hi there", "hello", "I am glad! You are talking to me"]
def greeting(sentence):
 
    for word in sentence.split():
        if word.lower() in GREETING_INPUTS:
            return random.choice(GREETING_RESPONSES)

生成響應

為了從我們的機器人生成輸入問題的響應,將使用文檔相似性的概念。所以我們首先導入必要的模塊。

從scikit learn庫中,導入TFidf矢量化器,將原始文檔集合轉換為TF-IDF特征矩陣。


from sklearn.feature_extraction.text import TfidfVectorizer
Also, import cosine similarity module from scikit learn library
from sklearn.metrics.pairwise import cosine_similarity

這將用於查找用戶輸入的單詞與語料庫中的單詞之間的相似性。這是聊天機器人最簡單的實現方式。

我們定義一個函數響應,它搜索用戶的話語中的一個或多個已知關鍵字,並返回幾個可能的響應之一。如果找不到與任何關鍵字匹配的輸入,則返回響應:“對不起!我不明白你的意思。“


def response(user_response):
    robo_response=''
    sent_tokens.append(user_response)
    TfidfVec = TfidfVectorizer(tokenizer=LemNormalize, stop_words='english')
    tfidf = TfidfVec.fit_transform(sent_tokens)
    vals = cosine_similarity(tfidf[-1], tfidf)
    idx=vals.argsort()[0][-2]
    flat = vals.flatten()
    flat.sort()
    req_tfidf = flat[-2]
    if(req_tfidf==0):
        robo_response=robo_response+"I am sorry! I don't understand you"
        return robo_response
    else:
        robo_response = robo_response+sent_tokens[idx]
        return robo_response


最後,我們將根據用戶的輸入,提供我們希望機器人在開始和結束對話時說出的行。


flag=True
print("ROBO: My name is Robo. I will answer your queries about Chatbots. If you want to exit, type Bye!")
while(flag==True):
    user_response = input()
    user_response=user_response.lower()
    if(user_response!='bye'):
        if(user_response=='thanks' or user_response=='thank you' ):
            flag=False
            print("ROBO: You are welcome..")
        else:
            if(greeting(user_response)!=None):
                print("ROBO: "+greeting(user_response))
            else:
                print("ROBO: ",end="")
                print(response(user_response))
                sent_tokens.remove(user_response)
    else:
        flag=False
        print("ROBO: Bye! take care..")


到這裏,我們在NLTK中編寫了我們的第一個聊天機器人。您可以在此處找到包含語料庫的完整代碼。現在,讓我們看看它如何與人類互動:

這並不算太糟糕。即使聊天機器人無法對某些問題給出滿意的答案,但其他問題的表現還不錯。

結論

雖然它是一個非常簡單的機器人,幾乎沒有任何認知技能,但它是進入NLP並了解聊天機器人的好方法。對於一個生產係統,你會想要考慮一個現有的機器人平台或框架,這個例子可以幫助你思考創建一個聊天機器人的設計和挑戰。

參考資料

本文由《純淨天空》出品。文章地址: https://vimsky.com/zh-tw/article/4130.html,未經允許,請勿轉載。