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

alexbyy發表於2018-12-11

安裝: 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(`./gensim_out/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(`./gensim_out/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(`./gensim_out/corpus.mm`, corpus)
#載入
corpus = corpora.MmCorpus(`./gensim_out/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)][]


相關文章