<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          不會真有人覺得聊天機器人難吧(二)

          共 9370字,需瀏覽 19分鐘

           ·

          2021-08-12 00:57


          引言

                  本文介紹傳統(tǒng)的檢索排名技術實現(xiàn)。教你如何實現(xiàn)輸入一個問句,快速查詢到最相關的文檔。

          單詞權重

                  假設你有很多文檔(稱為語料庫,corpus),你想實現(xiàn)輸入一個問句,快速查詢到最相關的文檔。

                  首先是要讓計算器理解文檔和問句,這里需要的是進行分詞,得到問句或每個文檔的單詞列表,然后去掉重復的單詞就可以得到單詞詞典。

                  根據(jù)單詞詞典利用下面介紹的TF-IDF算法可以得到每個問句或文檔的向量表示,接著可以利用余弦相似度計算問句和所有文檔的相似度,根據(jù)相似度排名可以找到最相似的文檔。 該方法可以參考TF-IDF文本表示。但是本文介紹的是另一種方法,通過計算問句和每篇文檔的相關度得分,根據(jù)得分就可以得到相似文檔排名。

                  不管是哪種方法都需要計算單詞的權重,所謂權重可以認為是某個單詞對該篇文章主題的貢獻度。比如談論體育的文章里面,多次出現(xiàn)了“籃球”和“的”?!暗摹背霈F(xiàn)的次數(shù)很有可能是超過“籃球”出現(xiàn)的次數(shù),我們不能說“的”比“籃球”對于該主題來說更重要。因此除了頻次還有其他指標需要考慮。

                  常用方法的是和它的變體BM25。

          TF-IDF

                  詞頻(term frequence) 反映了單詞的頻率,單詞在某篇文章中出現(xiàn)的越多,越可能由它反映文章的內容。通常會對詞頻取對數(shù),因為某個單詞出現(xiàn)了100次,并不見得它對文章的貢獻有100倍那么重要。因為是無意義的,因此我們加了一個:

                  詞頻有很多種計算方法,還有一種方法是用單詞在文章中出現(xiàn)的次數(shù),除以文章中單詞的總數(shù),這種方法其實更符合詞頻的字面意思。但是上面的方法也不錯。

                  文檔頻率(document frequence) 反映了出現(xiàn)單詞的文檔的數(shù)量?;诔@?,我們知道只在一小部分文檔中出現(xiàn)的單詞通常更助于這些文檔的區(qū)分度。而在整個集合中的文檔都出現(xiàn)的單詞通常是沒什么幫助的,比如“的”、“呢”這些詞。

                  逆文檔頻率(inverse document frequency) 單詞權重被定義為:

                  其中是集合中文檔的總數(shù);是單詞出現(xiàn)的文檔數(shù)量;

                  從公式可以看出,某個單詞出現(xiàn)的文檔數(shù)量越小,它的權重就越大;如果它在所有文檔中都出現(xiàn),那么,表示權重最低。

          就是用詞頻乘以逆文檔頻率,表示單詞在文檔中的權重:

                  下面我們重點介紹它的變體——BM25。

          BM25

                  一個的變體是BM25,它增加了兩個參數(shù):。其中用來平衡;控制文檔長度的重要性。給定計算文檔的BM25得分公式如下:

                  其中是文檔長度;是文檔集合中平均文檔長度。

                  假設,那么加權的就是,其中是用來控制的增速的,假設某篇文章單詞出現(xiàn)200次,它能帶來的相關性是出現(xiàn)100次的兩倍嗎?

                  假設出現(xiàn)了100次,那么該篇文章肯定是與有關的,如果再出現(xiàn)更多的次數(shù)帶來權重也不應該增加這種相關性了。使用就能避免它的無限增大,相當于達到某個閾值就飽和了。

                  上圖是不同的值得到的曲線,越大,曲線越緩和。當時,BM25就沒有計算,只是使用了。

                  引入的目的是考慮文檔長度,如果某篇文章很短,出現(xiàn)了某個單詞1次,和某篇文章特別長,但是也只出現(xiàn)了2次。我們就想讓文章的長度來控制的取值,如果文章很長,那么就取大一點,得到的就小一點;反之文章很短,那么就設小一點。如何才能知道文章是短是長呢?這里的做法就是用它的長度和平均長度作比較,如果大于平均,那么就是相對較長。

                  而引入就是為了控制文章長度的重要性,的取值范圍是。若,那么完全不考慮文章長度;若,如果文章較長,那么就增大;如果文章較短,那么就減少。下圖是相關的圖形:

                  從中可以看出,越大,對文章長度的懲罰也越大。

                  常用的取值。

                  關于也有一種變體叫作概率IDF(probabilistic IDF),它的公式為

                  這樣得到的對出現(xiàn)在較多文檔中的單詞來說是急劇下降的,但是它可能得到負值,Lucene的實現(xiàn)是在最后加,防止出現(xiàn)負值:

                  假設,代表的取值,上圖是原始的與它兩種變體的圖形??梢钥吹?,Lucene的實現(xiàn)的圖形和傳統(tǒng)的圖形類似。

          代碼實現(xiàn)

              def get_score(self, word, doc_id, doc_freq):
                  '''
                  計算bm25
                  :param word:
                  :param doc_id: 文檔在語料庫中的id
                  :param doc_freq: 出現(xiàn)單詞word的文檔數(shù)量
                  :return:
                  '''

                  tf = self.idx[word][doc_id]

                  if not tf:
                      return 0

                  tf = self._compute_weighted_tf(tf, self.dl[doc_id], self.dl.get_avg_len())
                  idf = self._compute_probabilistic_idf(doc_freq)
                  return tf * idf

              def _compute_weighted_tf(self, tf, doc_len, avg_doc_len):
                  return tf * (self.k + 1) / (self.k * (1 - self.b + self.b * doc_len / avg_doc_len) + tf)

              def _compute_probabilistic_idf(self, df):
                  return math.log((len(self.dl) + 1) / (df + 0.5))

              def get_scores(self, query):
                  query = self.tokenize(query) if self.tokenize else query

                  scores = np.zeros(len(self.dl))

                  for word in query:
                   # 利用倒排索引,提升查詢效率,我們可以不需要計算不出現(xiàn)查詢單詞的文檔
                      if word in self.idx:
                          for doc_id in self.idx[word].keys():
                              scores[doc_id] += self.get_score(word, doc_id, len(self.idx[word]))

                  return scores

          倒排索引

                  為了計算相似度,我們需要高效的找到包含查詢中單詞的文檔集合。

                  通常解決這個問題的方法是使用倒排索引(inverted index)。

          在倒排索引中,給定一個查詢詞,可以很快找到包含該查詢詞的文檔列表。

                  倒排索引包含兩部分,一個字典和ID列表。字典中包含了所有的單詞,每個單詞指向一個出現(xiàn)該單詞的文檔ID列表。其中還可以詞頻或甚至是單詞在文檔中出現(xiàn)的位置信息。

                  比如上面就是一個簡單的倒排索引,基于下面這4個簡單的文檔集合實現(xiàn)。其中包含了單詞的總數(shù),以及每個文檔中該單詞出現(xiàn)的次數(shù)。這樣可以很方便地計算。

          代碼實現(xiàn)

          import collections


          class Dictionary(dict):
              '''
              倒排索引用到的數(shù)據(jù)結構
              word -> postings(doc_id->word_count)
              '''


              def __missing__(self, key):
                  # Python中如果字典找不到key這個鍵,那么會調用該方法,我們在該方法中返回一個defaultdict
                  # 可以避免很多if else
                  postings = collections.defaultdict(int)
                  self[key] = postings
                  return postings


          class InvertedIndex:
              def __init__(self):
                  self.dictionary = Dictionary()

              def add(self, doc_id, doc):
                  for word in doc:
                      postings = self.dictionary[word]
                      postings[doc_id] += 1

              def __contains__(self, word):
                  return word in self.dictionary

              def __getitem__(self, word):
                  return self.dictionary[word]

              def __len__(self):
                  '''
                  :return: 語料庫中的單詞數(shù)量
                  '''

                  return len(self.dictionary)

              def get_doc_frequency(self, word):
                  '''
                  得到單詞出現(xiàn)的文檔數(shù)量
                  :param word:
                  :return:
                  '''

                  return len(self.dictionary[word])

          評估IR系統(tǒng)

                  我們評估排序的IR系統(tǒng)表現(xiàn)通過精確率(precision)和召回率(recall)指標。

                  精確率表示返回的文檔中屬于相關文檔的比例;

                  召回率表示返回相關的文檔占總相關文檔數(shù)的比例;

          是返回的文檔數(shù);

          是返回的文檔中相關文檔的數(shù)量;

          是返回的文檔中不相關文檔的數(shù)量;

          是所有文檔中相關文檔的數(shù)據(jù);

                  假設有50篇相關文檔,你的查詢算法返回了10篇,其中9篇是相關的,1篇是不相關的。

                  那么準確率就是,召回率是

          測試

                  數(shù)據(jù)使用的是網(wǎng)上找到的醫(yī)療問答數(shù)據(jù),它是長這個樣子的:

                  比如,我們查詢“醫(yī)生,我肛門處非常癢怎么辦”相關的相似問題。

          def main():
              data_path = './data/questions.csv'
              df = pd.read_csv(data_path, usecols=['content'])
              corpus = df['content'].tolist()
           # 傳入語料庫,和分詞方法
              bm25 = OkapiBM25(corpus, tokenize=jieba.lcut)

              query = "醫(yī)生,我肛門處非常癢怎么辦"

              result = bm25.get_top_k(query, corpus=corpus, k=5)

              for q in result:
                  print(q)

                  打印的結果如下:

          肛門處有濕疹,非常癢,怎么辦
          痔瘡,肛門處很癢,大便有點疼痔瘡,肛門處很癢,大便有點疼
          肛門非常癢怎么辦肛門很癢之前只是有意無意的感覺,可是現(xiàn)在特別癢有的地方用手碰還刺痛,嚴重癢時像被蚊子哎,特別是晚上,我該怎么辦?。?br>我有輕微的內痔,肛門處總是很癢怎么辦?。?br>我肛門癢,該怎么辦

                  這是返回最相似的5個問句,是不是像那么回事。

          完整代碼

          完整代碼:https://github.com/nlp-greyfoss/nlp-algorithms/tree/main/bm25


          最后一句:BUG,走你!

          沒有人比我更懂Redis(一)
          沒有人比我更懂Redis(二)
          不會真有人角色聊天機器人難吧(一)
          自然語言處理入門之分詞
          入門人工智能必備的線性代數(shù)基礎

          1.看到這里了就點個在看支持下吧,你的在看是我創(chuàng)作的動力。
          2.關注公眾號,每天為您分享原創(chuàng)或精選文章!
          3.特殊階段,帶好口罩,做好個人防護。

          瀏覽 60
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩AV中文字幕大香 | 做爱黄片免费观看 | 中国妓女一级A片 | 久久久久久久久久久本色 | 日韩一级在线 |