環境html
Python3,python
gensim,jieba,numpy ,pandasgit
原理:文章轉成向量,而後在計算兩個向量的餘弦值。github
Gensim數組
gensim是一個python的天然語言處理庫,可以將文檔根據TF-IDF, LDA, LSI 等模型轉化成向量模式,gensim還實現了word2vec功能,以便進行進一步的處理。app
具體API看官網:https://radimrehurek.com/gensim學習
中文分詞
中文須要分詞,英文就不須要了,分詞用的 jieba 。
def segment(doc: str):
"""中文分詞ui
Arguments: doc {str} -- 輸入文本 Returns: [type] -- [description] """ # 停用詞 stop_words = pd.read_csv("./data/stopwords_TUH.txt", index_col=False, quoting=3, names=['stopword'], sep="\n", encoding='utf-8') stop_words = list(stop_words.stopword) # 去掉html標籤數字等 reg_html = re.compile(r'<[^>]+>', re.S) doc = reg_html.sub('', doc) doc = re.sub('[0-9]', '', doc) doc = re.sub('\s', '', doc) word_list = list(jieba.cut(doc)) out_str = '' for word in word_list: if word not in stop_words: out_str += word out_str += ' ' segments = out_str.split(sep=" ") return segments
訓練 Doc2Vec 模型
模型參數下面說明,先上代碼
def train():
"""訓練 Doc2Vec 模型
"""spa
# 先把全部文檔的路徑存進一個 array中,docLabels: data_dir = "./data/corpus_words" docLabels = [f for f in listdir(data_dir) if f.endswith('.txt')] data = [] for doc in docLabels: ws = open(data_dir + "/" + doc, 'r', encoding='UTF-8').read() data.append(ws) print(len(data)) # 訓練 Doc2Vec,並保存模型: sentences = LabeledLineSentence(data, docLabels) # 實例化一個模型 model = gensim.models.Doc2Vec(vector_size=256, window=10, min_count=5, workers=4, alpha=0.025, min_alpha=0.025, epochs=12) model.build_vocab(sentences) print("開始訓練...") # 訓練模型 model.train(sentences, total_examples=model.corpus_count, epochs=12) model.save("./models/doc2vec.model") print("model saved")
保存成功後會有三個文件,分別是:doc2vec.model,doc2vec.model.trainables.syn1neg.npy,doc2vec.model.wv.vectors.npy
Doc2Vec參數說明:
· vector_size:是指特徵向量的維度,默認爲100。大的size須要更多的訓練數據,可是效果會更好.
· window:表示當前詞與預測詞在一個句子中的最大距離是多少
· alpha: 是學習速率
· min_count: 能夠對字典作截斷. 詞頻少於min_count次數的單詞會被丟棄掉, 默認值爲5
· workers參數控制訓練的並行數。
· epochs: 迭代次數,默認爲5code
文本轉換成向量
利用以前保存的模型,把分詞後的分本轉成向量,代碼以下
def sent2vec(model, words):
"""文本轉換成向量
Arguments: model {[type]} -- Doc2Vec 模型 words {[type]} -- 分詞後的文本 Returns: [type] -- 向量數組 """ vect_list = [] for w in words: try: vect_list.append(model.wv[w]) except: continue vect_list = np.array(vect_list) vect = vect_list.sum(axis=0) return vect / np.sqrt((vect ** 2).sum())
計算兩個向量餘弦值
餘弦類似度,又稱爲餘弦類似性,是經過計算兩個向量的夾角餘弦值來評估他們的類似度。餘弦類似度將向量根據座標值,繪製到向量空間中,如最多見的二維空間。
餘弦值的範圍在[-1,1]之間,值越趨近於1,表明兩個向量的方向越接近;越趨近於-1,他們的方向越相反;接近於0,表示兩個向量近乎於正交。
最多見的應用就是計算文本類似度。將兩個文本根據他們詞,創建兩個向量,計算這兩個向量的餘弦值,就能夠知道兩個文本在統計學方法中他們的類似度狀況。實踐證實,這是一個很是有效的方法。
公式:
def similarity(a_vect, b_vect):
"""計算兩個向量餘弦值
Arguments: a_vect {[type]} -- a 向量 b_vect {[type]} -- b 向量 Returns: [type] -- [description] """ dot_val = 0.0 a_norm = 0.0 b_norm = 0.0 cos = None for a, b in zip(a_vect, b_vect): dot_val += a*b a_norm += a**2 b_norm += b**2 if a_norm == 0.0 or b_norm == 0.0: cos = -1 else: cos = dot_val / ((a_norm*b_norm)**0.5) return cos
預測
def test_model():
print("load model")
model = gensim.models.Doc2Vec.load('./models/doc2vec.model')
st1 = open('./data/courpus_test/t1.txt', 'r', encoding='UTF-8').read() st2 = open('./data/courpus_test/t2.txt', 'r', encoding='UTF-8').read() # 分詞 print("segment") st1 = segment(st1) st2 = segment(st2) # 轉成句子向量 vect1 = sent2vec(model, st1) vect2 = sent2vec(model, st2) # 查看變量佔用空間大小 import sys print(sys.getsizeof(vect1)) print(sys.getsizeof(vect2)) cos = similarity(vect1, vect2) print("類似度:{:.4f}".format(cos))
看下效果:
徹底相同的文章
不相同的文章
數據太大,沒有上傳,本身網上找找應該有不少。
完整代碼:https://github.com/jarvisqi/nlp_learning/blob/master/gensim/doc2vector.py
參考: