感謝上一期能夠進入csdn“每日推薦看”,那必然帶著熱情寫下第二期《從n-gram到TFIDF》,這里引入一本《Speach and Language Processing》第三版翻譯版本(語音與語言處理(SLP)),前半部分寫的很好!里面連編輯距離(海明距離)都講了,所以算很詳細的了。那本期末尾留一個坑,利用編輯距離計算文本相似度!
上一節(jié)精彩回顧 原文鏈接
- 我們學習了詞袋模型,并且僅使用了jieba庫就完成了兩段文本的相似度的比較
上一節(jié)todo
- 做jieba的詳細介紹。目標:能制作自己需要的詞典,讓jieba能根據自身需求進行“改變”。
第二節(jié) n-gram
1. 基本概念
N是一個具體的數字,將長文本處理成一個個的N個字節(jié)的片段序列,然后對出現頻度進行統計。
2. 舉例理解
將我的理解通俗易懂的講解一波:理解n-gram,那必然得從1-gram,2-gram,3-gram開始入手,1-gram就是指one by one,一個詞一個詞的統計,我們接著用上一節(jié)的舉例:
1-gram
- 我喜歡看電影
用單詞出現次數來表示:【“我”:1.“喜歡”:1,“看”:1,“電影”,1】 - 我喜歡看電影尤其好看的電影(為了方便演示,我去了標點)
用單詞出現次數來表示:【“我”:1,“喜歡”:1,“看”:1,“電影”:2,“尤其”:1,“好看的”:1】
對于中文,其實這個詞的概念是模糊的,英文中,for 循環(huán)就能輕易做到,而我們恰恰多出來的,就是前文中用jieba庫讓它分成詞(特指:自然語言處理的最小單位)
2-gram(Bigram)
- 我喜歡看電影。
用2-詞片段出現次數來表示:【“我喜歡”:1.“喜歡看”:1,“看電影”:1】 - 我喜歡看電影尤其好看的電影。
用2-詞片段出現次數來表示:【“我喜歡”:1,“喜歡看”:1,“看電影”:1,“電影尤其”:1,”尤其好看的”:1,“好看的電影”:1】
顯然,在以兩個詞為切片的情況下,“看電影”與“好看的電影”從有一半相似,變成了完全不同的兩個內容,思考一下,這合理嗎?,
- 從語法層面,一個是動詞詞組,一個是名詞詞組,分成兩個完全不同的內容是合理的”。
- 從語義層,“看電影”與“好看的電影”仿佛又有千絲萬縷的關系。
3. 動手理解n-gram
input 一段文本
input n
output n-gram切片后的文本
#todo
大模型給的參考案例(參考下面的代碼寫出上面的內容):
import jieba # 導入jieba庫
def generate_2grams(words): # 定義一個名為generate_2grams的函數,用于生成2-gram序列
ngrams = [] # 初始化一個空列表ngrams,用于存儲2-gram序列
for i in range(len(words) - 1): # 對于單詞列表中的每個單詞,執(zhí)行以下操作
ngrams.append((words[i], words[i+1])) # 將當前單詞和下一個單詞組成一個元組,并將其添加到ngrams列表中
return ngrams # 返回生成的2-gram序列
text = "我愛自然語言處理技術" # 定義要進行分詞的文本
words = jieba.lcut(text) # 使用jieba庫對文本進行分詞,并將結果存儲在變量words中
ngrams = generate_2grams(words) # 調用generate_2grams函數生成2-gram序列,并將結果存儲在變量ngrams中
print(list(ngrams)) # 將2-gram序列轉換為列表類型并打印出來
inscode給的案例,在代碼寫作上肉眼可見的厲害!
import jieba
text = "今天天氣很好,適合出去散步"
tokens = list(jieba.cut(text)) # 使用jieba的分詞工具對文本進行分詞,并將結果轉換為列表
trigrams = zip(tokens, tokens[1:], tokens[2:]) # 使用zip函數將列表中三個連續(xù)元素組成一個三元組
for trigram in trigrams:
print(trigram)
4. n-gram相似度
輸入1:文本1
輸入2:文本2
輸出:文本的n-gram相似度
5. n-gram的應用場景
6. 項目案例(自創(chuàng)easy項目,埋下伏筆,提高興趣,沒興趣不看也不影響后續(xù)閱讀)
魯迅風格的一句話補全。
準備:一個txt文件,jieba庫的使用,2-gram基/3-gram礎知識,馬爾科夫鏈(一句話:下一個狀態(tài)只與當前狀態(tài)有關。)
參考:
輸入:世上本沒有路,走的人多了
輸出:世上本沒有路,走的人多了也便成了路。
代碼思路:
① 通過一個txt文件,生成2-gram/3-gram的概率,即(“1”,“2”,(“3”),出現次數/出現概率),按頻次或概率排序。② 給出新的文本內容,jieba得到最后一個詞,然后依次排列到文本最后(限定長度)。
#todo 下午寫
大模型的參考寫法(只給了參考內容和一些描述)
import jieba
from collections import Counter
import os
# 定義一個函數,用于從文件夾中獲取文件列表
def get_file_list(path):
file_list = []
for root, dirs, files in os.walk(path):
for file in files:
if file.endswith('.txt'): # 只獲取以。txt結尾的文件
file_list.append(os.path.join(root, file))
return file_list
# 定義一個函數,用于從文件中提取文本內容
def extract_text(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
text = f.read()
return text
# 定義一個函數,用于生成n-gram序列并統計每個n-gram出現的次數
def generate_ngrams(text, n):
ngram_sequences = list(ngrams(text.split(), n))
ngram_counts = Counter(ngram_sequences)
return ngram_counts
# 定義一個函數,用于找到出現次數最多的n-gram序列并補全缺失的單詞
def complete_ngram(ngram, text):
ngram_list = list(ngram)
for i in range(len(ngram_list)-1):
if ngram_list[i] not in text:
ngram_list[i] = '*' # 用星號代替缺失的單詞
return tuple(ngram_list)
# 定義一個函數,用于將補全后的句子輸出到控制臺或文件中
def print_result(result, output_file=None):
if output_file is not None:
with open(output_file, 'w', encoding='utf-8') as f:
f.write("補全后的句子: " + str(result) + "\n")
print("補全后的句子已保存到文件中")
else:
print("補全后的句子:", result)
# 定義一個函數,用于讀取魯迅全集并生成文本內容和n-gram序列
def read_luxun_books():
luxun_books_path = "path/to/luxun/books" # 請?zhí)鎿Q為實際路徑
ngrams = {} # 將所有書籍的文本內容和n-gram序列存儲在一個字典中,方便后續(xù)處理和比較
for book in os.listdir(luxun_books_path): # 對于每個書籍文件進行處理
book_path = os.path.join(luxun_books_path, book) # 獲取書籍文件的完整路徑
if book.endswith('.txt'): # 只獲取以。txt結尾的文件
text = extract_text(book_path) # 從文件中提取文本內容
ngram_counts = generate_ngrams(text, n=3) # 生成3-gram序列并統計每個序列出現的次數
ngrams[book] = (tuple(ngram), ngram_counts) # 將當前書籍的文本內容和3-gram序列存儲在字典中,方便后續(xù)處理和比較
max_count = max([v[1]['*'] for v in ngrams.values()]) # 找到出現次數最多的單詞出現次數,即缺失單詞最多的情況
max_book = [k for k, v in ngrams.items() if v[1]['*'] == max_count][0] # 找到出現次數最多的單詞所在的書籍名稱,即缺失單詞最多的書籍名稱
max_ngram = [v[0] for v in ngrams[max_book]] # 將缺失單詞最多的書籍的所有3-gram序列存儲在一個列表中,方便進行補全操作
max_ngram.sort() # 對3-gram序列進行排序,以便后面的處理操作可以按照一定的順序進行
max_ngram = max([v for v in max_ngram if v != '*']) # 將所有用星號代替的單詞刪除,只保留需要補全的單詞列表中的單詞
max_result = complete_ngram(tuple('*'.join(max_ngram)), text) # 將缺失單詞列表中的單詞按照原來的順序組合成一個新的3-gram序列,然后調用complete_ngram函數進行補全操作,得到最終結果
print("魯迅全集中缺失單詞最多的情況是:") # 在控制臺輸出提示信息
print("缺失單詞最多的書籍名稱是:", max_book) # 在控制臺輸出缺失單詞最多的書籍名稱和對應的3-gram序列列表
print("缺失單詞最多的情況補全后的結果是:", max_result) # 在控制臺輸出補全后的結果
print("將補全后的句子輸出到控制臺或文件中") # 在控制臺輸出提示信息,告訴用戶可以將結果輸出到控制臺或文件中進行查看或保存操作
InsCode 提供的案例,參考價值更高
import jieba # 導入分詞庫jieba
import random # 導入隨機數生成庫random
# 讀取文本內容
with open("input.txt", "r", encoding="utf-8") as f:
corpus = f.read()
# 使用jieba分詞對文本進行處理
tokens = list(jieba.cut(corpus))
# 定義n-gram模型的n值
n = 3
# 構建n-gram模型
ngrams = []
for i in range(len(tokens) - n + 1):
ngrams.append("".join(tokens[i:i+n]))
# 定義隱馬爾可夫模型的參數
states = ["路", "人"] # 狀態(tài)集合,包括“路”和“人”兩種狀態(tài)
observations = list(set(ngrams)) # 所有可能的觀測值集合,即所有可能的n-gram序列
start_probability = {"路": 1.0, "人": 0.0} # “路”和“人”兩種狀態(tài)的初始概率,其中“路”的概率為1.0,“人”的概率為0.0
transition_probability = {
"路": {"路": 0.5, "人": 0.5}, # 從“路”狀態(tài)轉移到“路”狀態(tài)的概率為0.5,從“路”狀態(tài)轉移到“人”狀態(tài)的概率為0.5
"人": {"路": 0.5, "人": 0.5} # 從“人”狀態(tài)轉移到“路”狀態(tài)的概率為0.5,從“人”狀態(tài)轉移到“人”狀態(tài)的概率為0.5
}
emission_probability = {}
for token in observations:
probs = {
"路": 1.0 if token.startswith("路") else 0.0, # 如果觀測值以“路”開頭,則認為是從“路”狀態(tài)發(fā)出的,概率為1.0;否則概率為0.0
"人": 1.0 if token.startswith("人") else 0.0
}
emission_probability[token] = probs
# 生成魯迅風格的一句話
result = "世上本沒有路,走的人多了,"
while len(result) < 30:
# 從當前狀態(tài)出發(fā),根據隱馬爾可夫模型的參數隨機生成下一個狀態(tài)
current_state = result[-1]
next_state = random.choices(states, [transition_probability[current_state][s] for s in states])[0]
# 從下一個狀態(tài)出發(fā),根據隱馬爾可夫模型的參數隨機生成下一個觀測值
next_token = random.choices(observations, [emission_probability[o][next_state] for o in observations])[0]
# 將生成的觀測值添加到結果中
result += next_token[1:]
print(result)
上文提到的馬爾科夫模型和隱馬爾科夫模型回頭會進行深入的了解,我們暫且先使用最簡單的理解方式——代碼實現,來應用它,弱化其理論細節(jié)。后續(xù)會在《第二章 文本生成》進行詳細講解。歡迎關注,這里就是將n-gram拓展一下。
總結:
- n-gram基本概念,但它實際上將詞語詞之間構建了聯系,初步擁有了上下文,這實際上是文本匹配在語義層面邁出的重要一步!
- n-gram相似度的實際應用,個人感覺這是最基礎的部分,只有有了n-gram的概念,才能做出詞典,傳統方式中的文本才能向量化。
第三節(jié) tfidf
1. 概念
2.理解
2.1 TF的理解
我們的面前有很多篇文章,是“計算機組成原理”、“計算機視覺”、“計算機網絡”三個領域的文章若干,并沒有事先告知我們每篇文章的類別,依托我們的經驗,我們明白在“組成原理“”中,單詞頻次較高的有:存儲器、微指令等;以此類推,計算機視覺中有卷積神經網絡;計算機網絡中有協議等。
我們如何讓計算機能分辨出來這三類文章呢?
我們通過詞出現頻次統計:
第一篇高頻詞:計算機:20次,微指令:20次;
第二篇高頻詞:計算機:20次,卷積神經網絡:20次;
第三篇高頻詞:標準:20次,TCP協議:20次;
…
TF 就是上述每一篇文章中出現這個詞的次數,這個也是第一節(jié)詞袋模型與第二節(jié)n-gram是一脈相承的知識內容,可以是單個詞的統計,也是可以2-gram的統計…
當然也有很多改進方法,例如:① 該單詞出現次數/這篇文章的總詞數 ② 該單詞出現次數/這篇文章出現頻次最多的詞出現的次數,這里的詞包括后續(xù)都是切片后的n-gram詞。
2.2 IDF的理解
如果依靠“計算機”來劃分這篇文章屬于哪一類,是顯然不合理的。那我們自然而然會想到找到只在這一類文章中頻繁出現,在其他文章中很少出現的詞作為判斷依據就好了。,由于其他文章是沒有提前告知的,我們轉換為在所有文章中的出現頻率較低替代它。
可以理解為某詞xxx在100篇文檔里中出現在了25篇文檔里,那么該詞出現的文檔頻率為25%
考慮到TF是高頻詞,肯定是越大越相關,在文檔頻率中,少部分文檔里,高頻出現才是好的,因此我們取逆,即用 文檔總數÷出現該詞的文檔數,這樣也是讓IDF值越大越相關了。
再考慮計算方便,就使用log,同時,為了避免分母為0 (出現0的情況,即log(100/0)的情況:①調用別人的詞典,按別人詞典順序對系列文檔進行統計;② 抽樣幾篇文檔做成詞典,再應用到所有數據集等;)
以上述三篇文章為例,IDF計算
第一篇各個詞的IDF:計算機:log(3/3),微指令 :log(3/2)
第二篇各個詞的IDF:計算機:log(3/3),卷積神經網絡:log(3/2);
第三篇各個詞的IDF:標準:log(3/2),TCP協議:log(3/2);
不難發(fā)現,計算機的idf已經為0了,確實達到了出現的文檔數越少,則IDF越大的效果!
TFIDF就是TF*IDF得到的結果,越相關,值越大。
2.3 停用詞的理解
揭秘jieba的時候到啦!即將填坑??!
上文提到計算IDF時,有常常出現的詞,比如計算機,還有我們日常生活中使用的,“在”,“這”,“那”,“和”等,還有一些詞,這些詞最大的特性就是IDF值很低,也就是 log(總文章數)/(出現數+1)很低,即出現次數很多!
而停用詞,我們第一次遇見就是在講到jieba的時候
2. 代碼填空
制作文本數據集并輸出停用詞
step1:將幾篇文檔(合計超過一萬字)作為輸入數據
step2:利用jieba庫將文檔加工成1-gram詞典,保存為dictionary.csv(“序號”,“”)
step3:計算所有詞的IDF值,并從小到大排序,保存為idf.csv(“序號”,“詞”,“idf值”)
step4:輸出排名前100的詞以 及 idf值>log(100/51)過半的詞
# todo 明天吧!今天先溜啦!
大模型參考文章來源:http://www.zghlxwxcb.cn/news/detail-530622.html
3. 總結
可以發(fā)現,我們已經逐步從詞,走到句子相似,再到文章相關。但依然停留在基礎部分,甚至最常聽見的RNN、LSTM都沒有見到,別著急,別著急,馬上就要開始啦!文章來源地址http://www.zghlxwxcb.cn/news/detail-530622.html
到了這里,關于【如何用大語言模型快速深度學習系列】從n-gram到TFIDF的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!