閱讀984 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Feature extraction - sklearn文本特征提取

文本特征提取

詞袋(Bag of Words)表征

文本分析是機器學習算法的主要應用領域。但是,文本分析的原始數據無法直接丟給算法,這些原始數據是一組符號,因為大多數算法期望的輸入是固定長度的數值特征向量而不是不同長度的文本文件。為了解決這個問題, scikit-learn 提供了一些實用工具可以用最常見的方式從文本內容中抽取數值特征,比如說:

  • 標記(tokenizing) 文本以及為每一個可能的標記(token)分配的一個整型ID ,例如用白空格和標點符號作為標記的分割符(中文的話涉及到分詞的問題)
  • 計數(counting) 標記在每個文本中的出現頻率
  • 正態化(nomalizating) 降低在大多數樣本/文檔中都出現的標記的權重

在這個方案中,特征和樣本的定義如下:

將 每個標記出現的頻率 (無論是否正態化)作為 特征 。

給定 文件 中所有標記的出現頻率所構成的向量作為多元 樣本 。

因此,語料文件可以用一個詞文檔矩陣代表,每行是一個文檔,每列是一個標記(即詞)。

將文檔文件轉化為數值特征的一般過程被稱為 向量化 。這個特殊的策略(標記,計數和正態化)被稱為 詞袋 或者Bag of n-grams表征。用詞頻描述文檔,但是完全忽略詞在文檔中出現的相對位置信息。

稀疏性

大多數文檔通常隻會使用語料庫中所有詞的一個子集,因而產生的矩陣將有許多特征值是0(通常99%以上都是0)。

例如,一組10,000個短文本(比如email)會使用100,000的詞匯總量,而每個文檔會使用100到1,000個唯一的詞。

為了能夠在內存中存儲這個矩陣,同時也提供矩陣/向量代數運算的速度,通常會使用稀疏表征例如在scipy.sparse包中提供的表征。

通用向量使用

CountVectorizer 在一個類中實現了標記和計數:

from sklearn.feature_extraction.text import CountVectorizer

這個模型有許多參數,不過默認值已經非常合理(具體細節請見 參考文檔 ):

vectorizer = CountVectorizer(min_df=1)
vectorizer
CountVectorizer(analyzer=...'word', binary=False, charset=None,
	charset_error=None, decode_error=...'strict',
	dtype=<... 'numpy.int64'>, encoding=...'utf-8', input=...'content',
	lowercase=True, max_df=1.0, max_features=None, min_df=1,
	ngram_range=(1, 1), preprocessor=None, stop_words=None,
	strip_accents=None, token_pattern=...'(?u)\\b\\w\\w+\\b',
	tokenizer=None, vocabulary=None)

讓我們用它來標記和計算一個簡單語料的詞頻:

corpus = [
	'This is the first document.',
	'This is the second second document.',
	'And the third one.',
	'Is this the first document?',
 ]
X = vectorizer.fit_transform(corpus)
X						
<4x9 sparse matrix of type '<... 'numpy.int64'>'
    with 19 stored elements in Compressed Sparse Column format>

默認設置通過抽取2個字符以上的詞標記字符。完成這個步驟的具體函數可以直接調用:

analyze = vectorizer.build_analyzer()
analyze("This is a text document to analyze.") == (
     ['this', 'is', 'text', 'document', 'to', 'analyze'])

True

在擬合過程中,每一個分析器找到的詞都會分配一個在結果矩陣中對應列的整型索引。列的含義可以用下麵的方式獲得:

vectorizer.get_feature_names() == (
     ['and', 'document', 'first', 'is', 'one',
      'second', 'the', 'third', 'this'])

True

X.toarray()
array([[0, 1, 1, 1, 0, 0, 1, 0, 1],
       [0, 1, 0, 1, 0, 2, 1, 0, 1],
       [1, 0, 0, 0, 1, 0, 1, 1, 0],
       [0, 1, 1, 1, 0, 0, 1, 0, 1]]...)

特征名稱與列索引的轉化映射被存儲在向量器(vectorizer)的vocabulary_屬性中:

vectorizer.vocabulary_.get('document')

1

因此,在訓練語料中沒有出現的詞在後續調用轉化方法時將被完全忽略:

vectorizer.transform(['Something completely new.']).toarray()

array([[0, 0, 0, 0, 0, 0, 0, 0, 0]]...)

注意在前麵的語料中,第一個和最後一個文檔的詞完全相同因此被編碼為等價的向量。但是,我們丟失了最後一個文檔是疑問形式的信息。為了保留一些局部順序信息,我們可以在抽取詞的1-grams(詞本身)之外,再抽取2-grams:

bigram_vectorizer = CountVectorizer(ngram_range=(1, 2),
							  token_pattern=r'\b\w+\b', min_df=1)
analyze = bigram_vectorizer.build_analyzer()
analyze('Bi-grams are cool!') == (
	['bi', 'grams', 'are', 'cool', 'bi grams', 'grams are', 'are cool'])
True

因此,由這個向量器抽取的詞表非常大,現在可以解決由於局部位置模型編碼的歧義問題:

X_2 = bigram_vectorizer.fit_transform(corpus).toarray()
X_2
...                           
array([[0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0],
       [0, 0, 1, 0, 0, 1, 1, 0, 0, 2, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0],
       [1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0],
       [0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1]]...)

特別是疑問形式“Is this”隻出現在最後一個文檔:

feature_index = bigram_vectorizer.vocabulary_.get('is this')
X_2[:, feature_index]     

array([0, 0, 0, 1]...)

Tf-idf詞權重

在較低的文本語料庫中,一些詞非常常見(例如,英文中的“the”,“a”,“is”),因此很少帶有文檔實際內容的有用信息。

最後更新:2017-04-27 11:00:51

  上一篇:go 使用99元一年的256MB高性能阿裏雲Redis加速Discuz論壇
  下一篇:go MongoDB 配置PHP 擴展