【NLP學習筆記】Gensim基本使用方法

安裝: pip install gensim
本文內容主要翻譯自https://radimrehurek.com/gensim/tut1.html#from-strings-to-vectors,中間加了些自己的理解,不理解之處大家可以直接看原文檔。

1、第一步、準備訓練語料

爲了簡單起見,我們假設列表documents代表語料庫,每一句話代表一個文檔,documents中有9個元素,也就是說該語料庫由九個文檔組成。

from gensim import corpora
documents = ["Human machine interface for lab abc computer applications",
          "A survey of user opinion of computer system response time",
              "The EPS user interface management system",
              "System and human system engineering testing of EPS",
              "Relation of user perceived response time to error measurement",
              "The generation of random binary unordered trees",
              "The intersection graph of paths in trees",
              "Graph minors IV Widths of trees and well quasi ordering",
             "Graph minors A survey"]

2、第二步、預處理

分詞(tokenize the documents)、去除停用詞和在語料中只出現一次的詞。處理語料的方式有很多,這裏只是簡單地通過空格(whitespace)去分詞,然後把每個詞變爲小寫,最後去除一些常用的詞和只出現一次的詞。

# remove common words and tokenize
stoplist = set('for a of the and to in'.split())
#遍歷documents,將其每個元素的words置爲小寫,然後通過空格分詞,並過濾掉在stoplist中的word。
texts = [[word for word in document.lower().split() if word not in stoplist]
for document in documents]
# remove words that appear only once,collection是python的一個工具庫
from collections import defaultdict
frequency = defaultdict(int)
for text in texts:
    for token in text:
        frequency[token] += 1
texts = [[token for token in text if frequency[token] > 1]
               for text in texts]

from pprint import pprint  # pprint可以使輸出更易觀看。
pprint(texts)
#輸出結果:
[['human', 'interface', 'computer'],
 ['survey', 'user', 'computer', 'system', 'response', 'time'],
 ['eps', 'user', 'interface', 'system'],
 ['system', 'human', 'system', 'eps'],
 ['user', 'response', 'time'],
 ['trees'],
 ['graph', 'trees'],
 ['graph', 'minors', 'trees'],
 ['graph', 'minors', 'survey']]

3、第三步、文本向量化

如何從文檔中提取特徵有很多方法。這裏簡單使用詞袋模型(bag-of- words)來提取文檔特徵,該模型通過計算每個詞在文檔中出現的頻率,然後將這些頻率組成一個向量,從而將文檔向量化。首先我們需要用語料庫訓練一個詞典,詞典包含所有在語料庫中出現的單詞。

#定義一個詞典,裏面包含所有語料庫中的單詞,這裏假設上文中輸出的texts就是經過處理後的語料庫。
dictionary = corpora.Dictionary(texts)
dictionary.save('/tmp/deerwester.dict')  # 因爲實際運用中該詞典非常大,所以將訓練的詞典保存起來,方便將來使用。
print(dictionary) # 輸出:Dictionary(35 unique tokens: ['abc', 'applications', 'computer', 'human', 'interface']...)
# dictionary有35個不重複的詞,給每個詞賦予一個id
print(dictionary.token2id)#輸出:{'abc': 0, 'applications': 1, 'computer': 2, 'human': 3, 'interface': 4, 'lab': 5, 'machine': 6, 'opinion': 7, 'response': 8, 'survey': 9, 'system': 10, 'time': 11, 'user': 12, 'eps': 13, 'management': 14, 'engineering': 15, 'testing': 16, 'error': 17, 'measurement': 18, 'perceived': 19, 'relation': 20, 'binary': 21, 'generation': 22, 'random': 23, 'trees': 24, 'unordered': 25, 'graph': 26, 'intersection': 27, 'paths': 28, 'iv': 29, 'minors': 30, 'ordering': 31, 'quasi': 32, 'well': 33, 'widths': 34}

上面已經構建了單詞詞典,我們可以通過該詞典用詞袋模型將其他的文本向量化.假設新文本是“Human computer interaction“,則輸出向量爲[(2, 1), (3, 1)],(2,1)中的“2”表示computer在詞典中的id爲2,“1”表示Human在該文檔中出現了1次,同理,(3,1)表示Human在詞典中的id爲3,出現次數爲1,輸出向量中元組的順序應該是按照id大小排序。interaction不在詞典中,所以直接被忽略了。

new_doc = "Human computer interaction"
#用dictionary的doc2bow方法將文本向量化
new_vec = dictionary.doc2bow(new_doc.lower().split())
corpora.MmCorpus.serialize('/tmp/deerwester.mm',new_vec)  # 講訓練結果存儲到硬盤中,方便將來使用。
print(new_vec)#輸出[(2, 1), (3, 1)]

4、優化

上面訓練過程中,語料庫完全駐留在內存中,如果語料庫很大,那將是個災難,假設硬盤中存儲着數百萬的語料,我們可以一次取出一個文檔,這樣同一時間只有一個文檔在內存中。獲取mycorpus.txt

#獲取語料
class MyCorpus(object):
    def __iter__(self):
        for line in open('mycorpus.txt'):
            #每一個line代表語料庫中的一個文檔
            yield dictionary.doc2bow(line.lower().split())
corpus_memory_friendly = MyCorpus()# 沒有將corpus加載到內存中
print(corpus_memory_friendly)#輸出:<__main__.MyCorpus object at 0x10d5690>

#遍歷每個文檔
for vector in corpus_memory_friendly:  # load one vector into memory at a time
    print(vector)
輸出結果:
[(0, 1), (1, 1), (2, 1)]
[(0, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1)]
[(2, 1), (5, 1), (7, 1), (8, 1)]
[(1, 1), (5, 2), (8, 1)]
[(3, 1), (6, 1), (7, 1)]
[(9, 1)]
[(9, 1), (10, 1)]
[(9, 1), (10, 1), (11, 1)]
[(4, 1), (10, 1), (11, 1)]

同樣的,構建詞典dictionary過程中也需要這種memory-friendly的方式訓練

# iteritems用來遍歷對象中的每個item
from six import iteritems
#初步構建所有單詞的詞典
dictionary = corpora.Dictionary(line.lower().split() for line in open('mycorpus.txt') )
#去出停用詞,stop_ids表示停用詞在dictionary中的id
stop_ids = [dictionary.token2id[stopword] for stopword in stoplist if stopword in dictionary.token2id]
#只出現一次的單詞id
once_ids = [tokenid for tokenid, docfreq in iteritem(dictionary.dfs) if docfreq ==1]
#根據stop_ids與once_ids清洗dictionary
dictionary.filter_token(stop_ids + once_ids)
# 去除清洗後的空位
dictionary.compactify()
print(dictionary)#輸出:Dictionary(12 unique tokens)

5、存儲訓練結果的幾種方式

  1. corpora.MmCorpus.serialize(path, result)
  2. corpora.SvmLightCorpus.serialize(path, result)
  3. corpora.BleiCorpus.serialize(path, result)
  4. corpora.LowCorpus.serialize(path, result)
    值得注意的時第一種,Market Matrix format,用法舉例
#假設訓練結果爲下面的corpus
corpus = [[(1, 0.5)], []]  # make one document empty, for the heck of it
#存儲
corpora.MmCorpus.serialize('/tmp/corpus.mm', corpus)
#加載
corpus = corpora.MmCorpus('/tmp/corpus.mm')
print(corpus)#輸出:MmCorpus(2 documents, 2 features, 1 non-zero entries)
#查看加載後的結果有兩種方法:1.轉成list2.遍歷corpus,這種方法堆內存更加友好。
print(list(corpus))  # calling list() will convert any sequence to a plain Python list
#輸出:[[(1, 0.5)], []]

for doc in corpus:
    print(doc)
#輸出:[(1, 0.5)][]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章