【TF-IDF】传统方法TF-IDF解决短文本相似度问题
機器學習算法與自然語言處理出品
@公眾號原創專欄作者 劉聰NLP
學校 |?中國藥科大學 藥學信息學碩士
知乎專欄 | 自然語言處理相關論文
前幾天寫了一篇短文本相似度算法研究的文章,不過里面介紹的方法基本上都是基于詞向量生成句子向量的方法。今天在這里就介紹一下傳統算法TF-IDF是如何計算短文本相似度的。
TF-IDF是英文Term Frequency–Inverse Document Frequency的縮寫,中文叫做詞頻-逆文檔頻率。
那么,TF-IDF是怎么產生的?又是從何而來呢?
在一個文本中,當一個詞匯出現很多次時,我們往往認為這個詞是重要的,可以代表該文本。但是事實不是這樣的,比如:“的”這個詞,雖然在一個文本中出現很多次,但是它依然沒有什么實際意義。而人們想要給文本中每個詞在語義表達中,賦予一定的權重,就出現了TF-IDF算法。
它由TF(詞頻)和IDF(逆文檔頻率)組成,其中,TF(詞頻)計算如下:
理論上,詞匯出現的次數就應該是詞匯的頻率。我們這里除以文本詞匯總個數,是為了排除文本長度的影響,獲取到該詞在文本中的相對重要程度。
IDF(逆文檔頻率)計算如下:
上面我們說過,有一些雖然在一個文本中出現很多次,但是它依然沒有什么實際意義,比如:“的”。而IDF逆文檔頻率是衡量該詞匯是否可以充分表示該文本的參數。IDF值越大,說明包含該詞匯的文本越少,則該詞匯越能夠代表該文本。
TF-IDF則是由TF和IDF相乘得到,如下:
它的含義是,如果一個詞,在該文本中出現次數越多,而在其他文本中出現很少時,則該詞匯越能夠表示該文本的信息。
實踐是檢驗真理的唯一標準。講完理論之后,我來看看具體任務上,我們要如何去使用TF-IDF。上一篇短文本相似度算法研究?文章中,我們舉過這樣一個場景,在問答系統任務(問答機器人)中,我們往往會人為地配置一些常用并且描述清晰的問題及其對應的回答,我們將這些配置好的問題稱之為“標準問”。當用戶進行提問時,常常將用戶的問題與所有配置好的標準問進行相似度計算,找出與用戶問題最相似的標準問,并返回其答案給用戶,這樣就完成了一次問答操作。
根據上述例子,我們進行coding,TF-IDF類定義具體如下:
import numpy as np class TF_IDF_Model(object):def __init__(self, documents_list):self.documents_list = documents_listself.documents_number = len(documents_list)self.tf = []self.idf = {}self.init()def init(self):df = {}for document in self.documents_list:temp = {}for word in document:temp[word] = temp.get(word, 0) + 1/len(document)self.tf.append(temp)for key in temp.keys():df[key] = df.get(key, 0) + 1for key, value in df.items():self.idf[key] = np.log(self.documents_number / (value + 1))def get_score(self, index, query):score = 0.0for q in query:if q not in self.tf[index]:continuescore += self.tf[index][q] * self.idf[q]return scoredef get_documents_score(self, query):score_list = []for i in range(self.documents_number):score_list.append(self.get_score(i, query))return score_list其中,documents_list 表示需要輸入的文本列表,內部每個文本需要事先分好詞;documents_number表示文本總個數;tf 用于存儲每個文本中每個詞的詞頻;idf用于存儲每個詞匯的逆文檔頻率;init函數是類初始化函數,用于求解文本集合中的tf和idf變量;get_score函數是獲取一個文本與文本列表中一個文本的tf-idf相似度值;get_documents_score函數是獲取一個文本與文本列表中所有文本的tf-idf相似度值。
定義好的TF-IDF類如何去使用呢?具體如下:
首先,給出文本集合,也就是我們上文場景中提到的“標準問”庫;
document_list = ["行政機關強行解除行政協議造成損失,如何索取賠償?","借錢給朋友到期不還得什么時候可以起訴?怎么起訴?","我在微信上被騙了,請問被騙多少錢才可以立案?","公民對于選舉委員會對選民的資格申訴的處理決定不服,能不能去法院起訴嗎?","有人走私兩萬元,怎么處置他?","法律上餐具、飲具集中消毒服務單位的責任是不是對消毒餐具、飲具進行檢驗?"]然后,我們對其進行分詞操作;
import jieba document_list = [list(jieba.cut(doc)) for doc in document_list]得到結果如下:
[['行政', '機關', '強行', '解除', '行政', '協議', '造成', '損失', ',', '如何', '索取', '賠償', '?'], ['借錢', '給', '朋友', '到期', '不', '還', '得', '什么', '時候', '可以', '起訴', '?', '怎么', '起訴', '?'], ['我', '在', '微信', '上', '被', '騙', '了', ',', '請問', '被', '騙', '多少', '錢', '才', '可以', '立案', '?'], ['公民', '對于', '選舉', '委員會', '對', '選民', '的', '資格', '申訴', '的', '處理', '決定', '不服', ',', '能', '不能', '去', '法院', '起訴', '嗎', '?'], ['有人', '走私', '兩萬元', ',', '怎么', '處置', '他', '?'], ['法律', '上', '餐具', '、', '飲具', '集中', '消毒', '服務', '單位', '的', '責任', '是不是', '對', '消毒', '餐具', '、', '飲具', '進行', '檢驗', '?']]接下來,我們實例化TF-IDF類,生成一個對象;
tf_idf_model = TF_IDF_Model(document_list)通過參數調用,觀察示例化的對象中documents_list ,documents_number,tf 和idf變量具體存儲了什么;
結果如下:
documents_list: [['行政', '機關', '強行', '解除', '行政', '協議', '造成', '損失', ',', '如何', '索取', '賠償', '?'], ['借錢', '給', '朋友', '到期', '不', '還', '得', '什么', '時候', '可以', '起訴', '?', '怎么', '起訴', '?'], ['我', '在', '微信', '上', '被', '騙', '了', ',', '請問', '被', '騙', '多少', '錢', '才', '可以', '立案', '?'], ['公民', '對于', '選舉', '委員會', '對', '選民', '的', '資格', '申訴', '的', '處理', '決定', '不服', ',', '能', '不能', '去', '法院', '起訴', '嗎', '?'], ['有人', '走私', '兩萬元', ',', '怎么', '處置', '他', '?'], ['法律', '上', '餐具', '、', '飲具', '集中', '消毒', '服務', '單位', '的', '責任', '是不是', '對', '消毒', '餐具', '、', '飲具', '進行', '檢驗', '?']] documents_number: 6 tf: [{'行政': 0.15384615384615385, '機關': 0.07692307692307693, '強行': 0.07692307692307693, '解除': 0.07692307692307693, '協議': 0.07692307692307693, '造成': 0.07692307692307693, '損失': 0.07692307692307693, ',': 0.07692307692307693, '如何': 0.07692307692307693, '索取': 0.07692307692307693, '賠償': 0.07692307692307693, '?': 0.07692307692307693}, {'借錢': 0.06666666666666667, '給': 0.06666666666666667, '朋友': 0.06666666666666667, '到期': 0.06666666666666667, '不': 0.06666666666666667, '還': 0.06666666666666667, '得': 0.06666666666666667, '什么': 0.06666666666666667, '時候': 0.06666666666666667, '可以': 0.06666666666666667, '起訴': 0.13333333333333333, '?': 0.13333333333333333, '怎么': 0.06666666666666667}, {'我': 0.058823529411764705, '在': 0.058823529411764705, '微信': 0.058823529411764705, '上': 0.058823529411764705, '被': 0.11764705882352941, '騙': 0.11764705882352941, '了': 0.058823529411764705, ',': 0.058823529411764705, '請問': 0.058823529411764705, '多少': 0.058823529411764705, '錢': 0.058823529411764705, '才': 0.058823529411764705, '可以': 0.058823529411764705, '立案': 0.058823529411764705, '?': 0.058823529411764705}, {'公民': 0.047619047619047616, '對于': 0.047619047619047616, '選舉': 0.047619047619047616, '委員會': 0.047619047619047616, '對': 0.047619047619047616, '選民': 0.047619047619047616, '的': 0.09523809523809523, '資格': 0.047619047619047616, '申訴': 0.047619047619047616, '處理': 0.047619047619047616, '決定': 0.047619047619047616, '不服': 0.047619047619047616, ',': 0.047619047619047616, '能': 0.047619047619047616, '不能': 0.047619047619047616, '去': 0.047619047619047616, '法院': 0.047619047619047616, '起訴': 0.047619047619047616, '嗎': 0.047619047619047616, '?': 0.047619047619047616}, {'有人': 0.125, '走私': 0.125, '兩萬元': 0.125, ',': 0.125, '怎么': 0.125, '處置': 0.125, '他': 0.125, '?': 0.125}, {'法律': 0.05, '上': 0.05, '餐具': 0.1, '、': 0.1, '飲具': 0.1, '集中': 0.05, '消毒': 0.1, '服務': 0.05, '單位': 0.05, '的': 0.05, '責任': 0.05, '是不是': 0.05, '對': 0.05, '進行': 0.05, '檢驗': 0.05, '?': 0.05}] idf: {'行政': 1.0986122886681098, '機關': 1.0986122886681098, '強行': 1.0986122886681098, '解除': 1.0986122886681098, '協議': 1.0986122886681098, '造成': 1.0986122886681098, '損失': 1.0986122886681098, ',': 0.1823215567939546, '如何': 1.0986122886681098, '索取': 1.0986122886681098, '賠償': 1.0986122886681098, '?': -0.15415067982725836, '借錢': 1.0986122886681098, '給': 1.0986122886681098, '朋友': 1.0986122886681098, '到期': 1.0986122886681098, '不': 1.0986122886681098, '還': 1.0986122886681098, '得': 1.0986122886681098, '什么': 1.0986122886681098, '時候': 1.0986122886681098, '可以': 0.6931471805599453, '起訴': 0.6931471805599453, '怎么': 0.6931471805599453, '我': 1.0986122886681098, '在': 1.0986122886681098, '微信': 1.0986122886681098, '上': 0.6931471805599453, '被': 1.0986122886681098, '騙': 1.0986122886681098, '了': 1.0986122886681098, '請問': 1.0986122886681098, '多少': 1.0986122886681098, '錢': 1.0986122886681098, '才': 1.0986122886681098, '立案': 1.0986122886681098, '公民': 1.0986122886681098, '對于': 1.0986122886681098, '選舉': 1.0986122886681098, '委員會': 1.0986122886681098, '對': 0.6931471805599453, '選民': 1.0986122886681098, '的': 0.6931471805599453, '資格': 1.0986122886681098, '申訴': 1.0986122886681098, '處理': 1.0986122886681098, '決定': 1.0986122886681098, '不服': 1.0986122886681098, '能': 1.0986122886681098, '不能': 1.0986122886681098, '去': 1.0986122886681098, '法院': 1.0986122886681098, '嗎': 1.0986122886681098, '有人': 1.0986122886681098, '走私': 1.0986122886681098, '兩萬元': 1.0986122886681098, '處置': 1.0986122886681098, '他': 1.0986122886681098, '法律': 1.0986122886681098, '餐具': 1.0986122886681098, '、': 1.0986122886681098, '飲具': 1.0986122886681098, '集中': 1.0986122886681098, '消毒': 1.0986122886681098, '服務': 1.0986122886681098, '單位': 1.0986122886681098, '責任': 1.0986122886681098, '是不是': 1.0986122886681098, '進行': 1.0986122886681098, '檢驗': 1.0986122886681098}最后,我們給出一個用戶問題,通過tf-idf算法,計算出“標準問”庫中所有標準問的相似度值;
query = "走私了兩萬元,在法律上應該怎么量刑?" query = list(jieba.cut(query)) scores = tf_idf_model.get_documents_score(query)結果如下:
[0.002167, 0.025656, 0.171679, 0.001341, 0.364818, 0.081880]通過結果我們可以發現,第五個標準問“有人走私兩萬元,怎么處置他?”與用戶問題“走私了兩萬元,在法律上應該怎么量刑?”最為相似,符合我們的預期。
TF-IDF算法,計算較快,理解起來也比較簡單;但是存在著缺點,相較于使用詞向量生成句子向量的方法,由于它只考慮詞頻的因素,沒有體現出詞匯在文中上下文的地位,因此不能夠很好的突出語義信息,會造成相似度結果不理想的情況。
以上,就是本人對TF-IDF算法的總結,有錯誤地方還希望指出,歡迎大家交流。
代碼可見:https://github.com/liucongg/ZhiHu_Code/blob/master/tf_idf_code/
往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習在線手冊深度學習在線手冊AI基礎下載(pdf更新到25集)本站qq群1003271085,加入微信群請回復“加群”獲取一折本站知識星球優惠券,請回復“知識星球”喜歡文章,點個在看
總結
以上是生活随笔為你收集整理的【TF-IDF】传统方法TF-IDF解决短文本相似度问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [PLM专题] 十分钟了解文本分类通用训
- 下一篇: 智能推荐算法在直播场景中的应用