def uint2vec(n,Leng=8,Radix=2):
創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于做網(wǎng)站、成都做網(wǎng)站、順義網(wǎng)絡(luò)推廣、成都小程序開(kāi)發(fā)、順義網(wǎng)絡(luò)營(yíng)銷、順義企業(yè)策劃、順義品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供順義建站搭建服務(wù),24小時(shí)服務(wù)熱線:13518219792,官方網(wǎng)址:www.cdcxhl.com
s = []
for i in range(Leng):
s = [n % Radix] +s
n //= Radix
return s
詞向量(word2vec)原始的代碼是C寫(xiě)的,python也有對(duì)應(yīng)的版本,被集成在一個(gè)非常牛逼的框架gensim中。
我在自己的開(kāi)源語(yǔ)義網(wǎng)絡(luò)項(xiàng)目graph-mind(其實(shí)是我自己寫(xiě)的小玩具)中使用了這些功能,大家可以直接用我在上面做的進(jìn)一步的封裝傻瓜式地完成一些操作,下面分享調(diào)用方法和一些code上的心得。
1.一些類成員變量:
[python]?view plain?copy
def?__init__(self,?modelPath,?_size=100,?_window=5,?_minCount=1,?_workers=multiprocessing.cpu_count()):
self.modelPath?=?modelPath
self._size?=?_size
self._window?=?_window
self._minCount?=?_minCount
self._workers?=?_workers
modelPath是word2vec訓(xùn)練模型的磁盤(pán)存儲(chǔ)文件(model在內(nèi)存中總是不踏實(shí)),_size是詞向量的維度,_window是詞向量訓(xùn)練時(shí)的上下文掃描窗口大小,后面那個(gè)不知道,按默認(rèn)來(lái),_workers是訓(xùn)練的進(jìn)程數(shù)(需要更精準(zhǔn)的解釋,請(qǐng)指正),默認(rèn)是當(dāng)前運(yùn)行機(jī)器的處理器核數(shù)。這些參數(shù)先記住就可以了。
2.初始化并首次訓(xùn)練word2vec模型
完成這個(gè)功能的核心函數(shù)是initTrainWord2VecModel,傳入兩個(gè)參數(shù):corpusFilePath和safe_model,分別代表訓(xùn)練語(yǔ)料的路徑和是否選擇“安全模式”進(jìn)行初次訓(xùn)練。關(guān)于這個(gè)“安全模式”后面會(huì)講,先看代碼:
[python]?view plain?copy
def?initTrainWord2VecModel(self,?corpusFilePath,?safe_model=False):
'''''
init?and?train?a?new?w2v?model
(corpusFilePath?can?be?a?path?of?corpus?file?or?directory?or?a?file?directly,?in?some?time?it?can?be?sentences?directly
about?soft_model:
if?safe_model?is?true,?the?process?of?training?uses?update?way?to?refresh?model,
and?this?can?keep?the?usage?of?os's?memory?safe?but?slowly.
and?if?safe_model?is?false,?the?process?of?training?uses?the?way?that?load?all
corpus?lines?into?a?sentences?list?and?train?them?one?time.)
'''
extraSegOpt().reLoadEncoding()
fileType?=?localFileOptUnit.checkFileState(corpusFilePath)
if?fileType?==?u'error':
warnings.warn('load?file?error!')
return?None
else:
model?=?None
if?fileType?==?u'opened':
print('training?model?from?singleFile!')
model?=?Word2Vec(LineSentence(corpusFilePath),?size=self._size,?window=self._window,?min_count=self._minCount,?workers=self._workers)
elif?fileType?==?u'file':
corpusFile?=?open(corpusFilePath,?u'r')
print('training?model?from?singleFile!')
model?=?Word2Vec(LineSentence(corpusFile),?size=self._size,?window=self._window,?min_count=self._minCount,?workers=self._workers)
elif?fileType?==?u'directory':
corpusFiles?=?localFileOptUnit.listAllFileInDirectory(corpusFilePath)
print('training?model?from?listFiles?of?directory!')
if?safe_model?==?True:
model?=?Word2Vec(LineSentence(corpusFiles[0]),?size=self._size,?window=self._window,?min_count=self._minCount,?workers=self._workers)
for?file?in?corpusFiles[1:len(corpusFiles)]:
model?=?self.updateW2VModelUnit(model,?file)
else:
sentences?=?self.loadSetencesFromFiles(corpusFiles)
model?=?Word2Vec(sentences,?size=self._size,?window=self._window,?min_count=self._minCount,?workers=self._workers)
elif?fileType?==?u'other':
#?TODO?add?sentences?list?directly
pass
model.save(self.modelPath)
model.init_sims()
print('producing?word2vec?model?...?ok!')
return?model
首先是一些雜七雜八的,判斷一下輸入文件路徑下訪問(wèn)結(jié)果的類型,根據(jù)不同的類型做出不同的文件處理反應(yīng),這個(gè)大家應(yīng)該能看懂,以corpusFilePath為一個(gè)已經(jīng)打開(kāi)的file對(duì)象為例,創(chuàng)建word2vec model的代碼為:
[python]?view plain?copy
model?=?Word2Vec(LineSentence(corpusFilePath),?size=self._size,?window=self._window,?min_count=self._minCount,?workers=self._workers)
其實(shí)就是這么簡(jiǎn)單,但是為了代碼健壯一些,就變成了上面那么長(zhǎng)。問(wèn)題是在面對(duì)一個(gè)路徑下的許多訓(xùn)練文檔且數(shù)目巨大的時(shí)候,一次性載入內(nèi)存可能不太靠譜了(沒(méi)有細(xì)研究gensim在Word2Vec構(gòu)造方法中有沒(méi)有考慮這個(gè)問(wèn)題,只是一種習(xí)慣性的警惕),于是我設(shè)定了一個(gè)參數(shù)safe_model用于判斷初始訓(xùn)練是否開(kāi)啟“安全模式”,所謂安全模式,就是最初只載入一篇語(yǔ)料的內(nèi)容,后面的初始訓(xùn)練文檔通過(guò)增量式學(xué)習(xí)的方式,更新到原先的model中。
上面的代碼里,corpusFilePath可以傳入一個(gè)已經(jīng)打開(kāi)的file對(duì)象,或是一個(gè)單個(gè)文件的地址,或一個(gè)文件夾的路徑,通過(guò)函數(shù)checkFileState已經(jīng)做了類型的判斷。另外一個(gè)函數(shù)是updateW2VModelUnit,用于增量式訓(xùn)練更新w2v的model,下面會(huì)具體介紹。loadSetencesFromFiles函數(shù)用于載入一個(gè)文件夾中全部語(yǔ)料的所有句子,這個(gè)在源代碼里有,很簡(jiǎn)單,哥就不多說(shuō)了。
3.增量式訓(xùn)練更新word2vec模型
增量式訓(xùn)練w2v模型,上面提到了一個(gè)這么做的原因:避免把全部的訓(xùn)練語(yǔ)料一次性載入到內(nèi)存中。另一個(gè)原因是為了應(yīng)對(duì)語(yǔ)料隨時(shí)增加的情況。gensim當(dāng)然給出了這樣的solution,調(diào)用如下:
[python]?view plain?copy
def?updateW2VModelUnit(self,?model,?corpusSingleFilePath):
'''''
(only?can?be?a?singleFile)
'''
fileType?=?localFileOptUnit.checkFileState(corpusSingleFilePath)
if?fileType?==?u'directory':
warnings.warn('can?not?deal?a?directory!')
return?model
if?fileType?==?u'opened':
trainedWordCount?=?model.train(LineSentence(corpusSingleFilePath))
print('update?model,?update?words?num?is:?'?+?trainedWordCount)
elif?fileType?==?u'file':
corpusSingleFile?=?open(corpusSingleFilePath,?u'r')
trainedWordCount?=?model.train(LineSentence(corpusSingleFile))
print('update?model,?update?words?num?is:?'?+?trainedWordCount)
else:
#?TODO?add?sentences?list?directly?(same?as?last?function)
pass
return?model
簡(jiǎn)單檢查文件type之后,調(diào)用model對(duì)象的train方法就可以實(shí)現(xiàn)對(duì)model的更新,這個(gè)方法傳入的是新語(yǔ)料的sentences,會(huì)返回模型中新增詞匯的數(shù)量。函數(shù)全部執(zhí)行完后,return更新后的model,源代碼中在這個(gè)函數(shù)下面有能夠處理多類文件參數(shù)(同2)的增強(qiáng)方法,這里就不多介紹了。
4.各種基礎(chǔ)查詢
當(dāng)你確定model已經(jīng)訓(xùn)練完成,不會(huì)再更新的時(shí)候,可以對(duì)model進(jìn)行鎖定,并且據(jù)說(shuō)是預(yù)載了相似度矩陣能夠提高后面的查詢速度,但是你的model從此以后就read only了。
[python]?view plain?copy
def?finishTrainModel(self,?modelFilePath=None):
'''''
warning:?after?this,?the?model?is?read-only?(can't?be?update)
'''
if?modelFilePath?==?None:
modelFilePath?=?self.modelPath
model?=?self.loadModelfromFile(modelFilePath)
model.init_sims(replace=True)
可以看到,所謂的鎖定模型方法,就是init_sims,并且把里面的replace參數(shù)設(shè)定為T(mén)rue。
然后是一些word2vec模型的查詢方法:
[python]?view plain?copy
def?getWordVec(self,?model,?wordStr):
'''''
get?the?word's?vector?as?arrayList?type?from?w2v?model
'''
return?model[wordStr]
[python]?view plain?copy
def?queryMostSimilarWordVec(self,?model,?wordStr,?topN=20):
'''''
MSimilar?words?basic?query?function
return?2-dim?List?[0]?is?word?[1]?is?double-prob
'''
similarPairList?=?model.most_similar(wordStr.decode('utf-8'),?topn=topN)
return?similarPairList
[python]?view plain?copy
def?culSimBtwWordVecs(self,?model,?wordStr1,?wordStr2):
'''''
two?words?similar?basic?query?function
return?double-prob
'''
similarValue?=?model.similarity(wordStr1.decode('utf-8'),?wordStr2.decode('utf-8'))
return?similarValue
上述方法都很簡(jiǎn)單,基本上一行解決,在源代碼中,各個(gè)函數(shù)下面依然是配套了相應(yīng)的model文件處理版的函數(shù)。其中,getWordVec是得到查詢?cè)~的word2vec詞向量本身,打印出來(lái)是一個(gè)純數(shù)字的array;queryMostSimilarWordVec是得到與查詢?cè)~關(guān)聯(lián)度最高的N個(gè)詞以及對(duì)應(yīng)的相似度,返回是一個(gè)二維list(注釋里面寫(xiě)的蠻清楚);culSimBtwWordVecs是得到兩個(gè)給定詞的相似度值,直接返回double值。
5.Word2Vec詞向量的計(jì)算
研究過(guò)w2v理論的童鞋肯定知道詞向量是可以做加減計(jì)算的,基于這個(gè)性質(zhì),gensim給出了相應(yīng)的方法,調(diào)用如下:
[python]?view plain?copy
def?queryMSimilarVecswithPosNeg(self,?model,?posWordStrList,?negWordStrList,?topN=20):
'''''
pos-neg?MSimilar?words?basic?query?function
return?2-dim?List?[0]?is?word?[1]?is?double-prob
'''
posWordList?=?[]
negWordList?=?[]
for?wordStr?in?posWordStrList:
posWordList.append(wordStr.decode('utf-8'))
for?wordStr?in?negWordStrList:
negWordList.append(wordStr.decode('utf-8'))
pnSimilarPairList?=?model.most_similar(positive=posWordList,?negative=negWordList,?topn=topN)
return?pnSimilarPairList
由于用的是py27,所以之前對(duì)傳入的詞列表數(shù)據(jù)進(jìn)行編碼過(guò)濾,這里面posWordList可以認(rèn)為是對(duì)結(jié)果產(chǎn)生正能量的詞集,negWordList則是對(duì)結(jié)果產(chǎn)生負(fù)能量的詞集,同時(shí)送入most_similar方法,在設(shè)定return答案的topN,得到的返回結(jié)果形式同4中的queryMostSimilarWordVec函數(shù),大家可以這樣數(shù)學(xué)地理解這個(gè)操作:
下面一個(gè)操作是我自創(chuàng)的,假設(shè)我想用上面詞向量topN“詞-關(guān)聯(lián)度”的形式展現(xiàn)兩個(gè)詞或兩組詞之間的關(guān)聯(lián),我是這么做的:
[python]?view plain?copy
def?copeMSimilarVecsbtwWordLists(self,?model,?wordStrList1,?wordStrList2,?topN_rev=20,?topN=20):
'''''
range?word?vec?res?for?two?wordList?from?source?to?target
use?wordVector?to?express?the?relationship?between?src-wordList?and?tag-wordList
first,?use?the?tag-wordList?as?neg-wordList?to?get?the?rev-wordList,
then?use?the?scr-wordList?and?the?rev-wordList?as?the?new?src-tag-wordList
topN_rev?is?topN?of?rev-wordList?and?topN?is?the?final?topN?of?relationship?vec
'''
srcWordList?=?[]
tagWordList?=?[]
srcWordList.extend(wordStr.decode('utf-8')?for?wordStr?in?wordStrList1)
tagWordList.extend(wordStr.decode('utf-8')?for?wordStr?in?wordStrList2)
revSimilarPairList?=?self.queryMSimilarVecswithPosNeg(model,?[],?tagWordList,?topN_rev)
revWordList?=?[]
revWordList.extend(pair[0].decode('utf-8')?for?pair?in?revSimilarPairList)
stSimilarPairList?=?self.queryMSimilarVecswithPosNeg(model,?srcWordList,?revWordList,?topN)
return?stSimilarPairList
這個(gè)操作的思路就是,首先用兩組詞中的一組作為negWordList,傳入上面的queryMSimilarVecswithPosNeg函數(shù),得到topN一組的中轉(zhuǎn)詞,在使用這些中轉(zhuǎn)詞與原先的另一組詞進(jìn)行queryMSimilarVecswithPosNeg操作,很容易理解,第一步得到的是一組詞作為negWordList的反向結(jié)果,再通過(guò)這個(gè)反向結(jié)果與另一組詞得到“負(fù)負(fù)得正”的效果。這樣就可以通過(guò)一組topN的“詞-關(guān)聯(lián)度”配對(duì)List表示兩組詞之間的關(guān)系。
vec一般是vector的縮寫(xiě),中文名是向量
不過(guò)Python更嚴(yán)格的說(shuō)法是列表
聲明的函數(shù),需要調(diào)用。例如
def fun()
……………
fun()#調(diào)用才可執(zhí)行函數(shù)里的代碼