本文主要記錄使用sklearn庫對數據集進行特徵提取的相關操作,通過了解相關知識,運行已有的代碼來進行新內容的學習
-
pipeline
pipeline主要用於連接多個estimators使之成爲一個estimator,方便我們的構建更復雜的模型。
一般數據處理的流程如下:
feature selection–normalization–classification
除了最後的classification可以是任意類型(聚類器,分類器等)外,其餘各部分必須是變換器transformer,即必須有transform操作,而pipeline的性質取決於classification,即classification是聚類器則pipeline合成的estimator便是聚類器。
pipeline提供了兩個基本操作:- convenience:僅用一次fit或者predict就可在數據集上訓練一組estimator(從第一個一至訓練到組後一個)
- joint parameter selection:可以把grid search用在pipeline中所有的estimators的參數組合
pipeline使用(key,value)列表來創建estimator
常用方法舉例:
#以下程序在python的控制檯下運行
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
from sklearn.decomposition import PCA
estimators=[('reduce_dim',PCA()),('clf',SVC())]#創建兩個estimator
pipe=Pipeline(estimators)#調用pipeline指令創建pipe
pipe
Out[8]:
Pipeline(memory=None,
steps=[('reduce_dim', PCA(copy=True, iterated_power='auto', n_components=None, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)), ('clf', SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
kernel='rbf', max_iter=-1, probability=False, random_state=None,
shrinking=True, tol=0.001, verbose=False))])
pipe.steps[1]#調用pipe裏面的第二個estimator
Out[9]:
('clf', SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
kernel='rbf', max_iter=-1, probability=False, random_state=None,
shrinking=True, tol=0.001, verbose=False))
pipe.named_steps['reduce_dim']#也可以通過我們賦予estimator的名字來調用
Out[10]:
PCA(copy=True, iterated_power='auto', n_components=None, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)
#Pipeline中estimators的參數通過<estimator>__<parameter>語法來獲取
pipe.set_params(clf__C=10)
#注意此處——爲2個下劃線,字母C爲大寫!!!
Out[10]:
Pipeline(memory=None,
steps=[('reduce_dim', PCA(copy=True, iterated_power='auto', n_components=None, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)), ('clf', SVC(C=10, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
kernel='rbf', max_iter=-1, probability=False, random_state=None,
shrinking=True, tol=0.001, verbose=False))])
可以使用grid search來進行操作
from sklearn.model_selection import GridSearchCV
params = dict(reduce_dim__n_components=[2, 5, 10],
clf__C=[0.1, 10, 100])
grid_search = GridSearchCV(pipe, param_grid=params)
Out[15]:
GridSearchCV(cv='warn', error_score='raise-deprecating',
estimator=Pipeline(memory=None,
steps=[('reduce_dim', PCA(copy=True, iterated_power='auto', n_components=None, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)), ('clf', SVC(C=10, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
kernel='rbf', max_iter=-1, probability=False, random_state=None,
shrinking=True, tol=0.001, verbose=False))]),
fit_params=None, iid='warn', n_jobs=None,
param_grid={'reduce_dim__n_components': [2, 5, 10], 'clf__C': [0.1, 10, 100]},
pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',
scoring=None, verbose=0)
#通過對單個的estimator進行參數變化來達到整體參數優化的目的
#爲了更直觀我將這部分完整代碼重新展示一下
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
from sklearn.decomposition import PCA
from sklearn.model_selection import GridSearchCV
from sklearn.linear_model import LogisticRegression
estimators = [('reduce_dim', PCA()), ('clf', SVC())]
pipe = Pipeline(estimators)
params = dict(reduce_dim=[None, PCA(5), PCA(10)],
clf=[SVC(), LogisticRegression()],
clf__C=[0.1, 10, 100])
grid_search = GridSearchCV(pipe, param_grid=params)
pipe
Out[3]:
Pipeline(memory=None,
steps=[('reduce_dim', PCA(copy=True, iterated_power='auto', n_components=None, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)), ('clf', SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
kernel='rbf', max_iter=-1, probability=False, random_state=None,
shrinking=True, tol=0.001, verbose=False))])
使用make_pipeline指令
from sklearn.pipeline import make_pipeline
from sklearn.naive_bayes import MultinomialNB
from sklearn.preprocessing import Binarizer
make_pipeline(Binarizer(), MultinomialNB())
#運行後將主動給每個estimator賦予一個key關鍵字
Out[4]:
Pipeline(memory=None,
steps=[('binarizer', Binarizer(copy=True, threshold=0.0)), ('multinomialnb', MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True))])
2.FeatureUnion:用於整合特徵空間
可以將多個transformer object組合成爲新的transformer,其接受一個transformer的(key,value)列表。
提供兩個方法:
- convenience:同PIPELINE
- joint parameter selection:可把grid search用在feature union所有的estimator的參數組合上。
常用操作如下
from sklearn.pipeline import FeatureUnion
from sklearn.decomposition import PCA
from sklearn.decomposition import KernelPCA
estimators = [('linear_pca', PCA()), ('kernel_pca', KernelPCA())]
combined = FeatureUnion(estimators)
combined
Out[5]:
FeatureUnion(n_jobs=None,
transformer_list=[('linear_pca', PCA(copy=True, iterated_power='auto', n_components=None, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)), ('kernel_pca', KernelPCA(alpha=1.0, coef0=1, copy_X=True, degree=3, eigen_solver='auto',
fit_inverse_transform=False, gamma=None, kernel='linear',
kernel_params=None, max_iter=None, n_components=None, n_jobs=None,
random_state=None, remove_zero_eig=False, tol=0))],
transformer_weights=None)
#也可以如同pipeline一樣,使用make_union來創建feature union
#參數的更改設置也如同pipeline
combined.set_params(kernel_pca=None)
Out[7]:
FeatureUnion(n_jobs=None,
transformer_list=[('linear_pca', PCA(copy=True, iterated_power='auto', n_components=None, random_state=None,
svd_solver='auto', tol=0.0, whiten=False)), ('kernel_pca', None)],
transformer_weights=None)
#參數基本全部設爲None
3.特徵抽取(feature extraction)
基本語句形式:sklearn.feature_extraction.
可從原始數據集提取機器可以學習或者直接處理的特徵向量。
與feature selection不用,selection是在特徵向量中再次進行變換,最終形成特徵空間。
- loading feature from dict
DictVectorizer可以把標準的字典 表示的特徵數組轉換成numpy/scipy的表示形式以便於estimator使用,變換後形成one-hot編碼形式。
舉例如下
weather = [{'city': 'xuzhou', "temperature": 20},
{'city': 'guangzhou', 'temperature': 36}]
from sklearn.feature_extraction import DictVectorizer
vec = DictVectorizer()
table = vec.fit_transform(weather).toarray()
print(table)
[[ 0. 1. 20.]
[ 1. 0. 36.]]
#第一行0表示非徐州,1表示徐州,氣溫爲20°,第二行1表示廣州,0表示非廣州,氣溫爲36°
-
features hashing
特徵哈希變換接受的數據類型有mapping類似於dict,list,string
不能做單詞的切分,主要用於構建哈希表,爲了防止特徵之間的衝突,我們經常用有符號哈希函數(signed hash function),符號決定了被存儲到輸出矩陣中值的符號。
FeatureHasher支持三種輸入形式:1."dict"表示輸入數據是字典形式的[{feature_name: value}, …],
2."pair"表示輸入數據是pair形式的[[(feature_name1, value1), (feature_name2, value2)], …]
3."string"表示數據是字符串形式的[[feature_name1, feature_name1]],其中有個value1個feature_name1,value2個feature_name2
其中feature_name必須是字符串,value必須是數字。在"string"的情況下,每個feature_name隱含value是1。特徵名稱會進行hash處理,來計算該特徵名稱對應的hash列。value的符號在輸出的數據中可能會發生反轉。
from sklearn.feature_extraction import FeatureHasher
h = FeatureHasher(n_features=10, input_type='string', dtype=int, alternate_sign=True)#sign表示是否啓用符號,可以減少特徵衝突
d = [{'dog': 1, 'cat': 2, 'elephant': 4}, {'dog': 2, 'run': 5}]
f = h.transform(d)
print(f.toarray())
print(h.get_params())
[[ 0 0 -1 -1 0 0 0 0 0 1]
[ 0 0 0 -1 -1 0 0 0 0 0]]
{'alternate_sign': True, 'dtype': <class 'int'>, 'input_type': 'string', 'n_features': 10, 'non_negative': False}
d = [['dog', 'cat', 'cat', 'elephant', 'elephant', 'elephant', 'elephant', ],
["dog", "dog", "run", 'run', 'run', 'run', 'run'],
["run", "run"]]
f = h.transform(d)
print(f.toarray())
print(h.get_params())
[[ 0 0 -4 -1 0 0 0 0 0 2]
[ 0 0 0 -2 -5 0 0 0 0 0]
[ 0 0 0 0 -2 0 0 0 0 0]]
{'alternate_sign': True, 'dtype': <class 'int'>, 'input_type': 'string', 'n_features': 10, 'non_negative': False}
-
text feature extraction
文本分析是機器學習的重要領域,文本是由一系列符號構成,無法直接被計算機學習,所以我們在數值型特徵空間上,建立實當的特徵向量,便於機器去學習。
文本分析的一般步驟:
1.tokenizing劃分
將文本按照一定的規則劃分成數個獨立的部分
2.counting統計
統計每個部分出現的次數
3.normalizing歸一化加權
賦予每個部分不同的權值,弱化a,the等介詞的權重。The Bag of Words representation(字袋模型)
一個語料庫(corpus)中的所有文檔可以用一個特徵向量矩陣來建模:每一行文檔代表一行特徵向量,特徵向量的每一個分量是Token在文檔中出現的次數/頻率。但字袋模型缺少分析詞語前後的關聯性的能力。
由於文本的詞彙集合會很大,但是每次使用的僅有一部分,所以特徵向量大部分位置爲0,面對這種稀疏數據而不影響矩陣的運算速度,特徵向量矩陣通常會用係數矩陣來存儲。
常用方法如下:
from sklearn.feature_extraction.text import CountVectorizer
vec=CountVectorizer(min_df=1)
#展示vec的內部結構
CountVectorizer(analyzer='word', binary=False, decode_error='strict',
dtype=<class '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)
from sklearn.feature_extraction.text import CountVectorizer
vec = CountVectorizer(min_df=1)
cropus = [
'zzh is a diligent boy',
'zzh goes to library everyday',
'zzh makes to_do list and finishes it on purpose'
] # 創建語料庫
x = vec.fit_transform(cropus)
print(x.toarray())
#結果的最後一列均爲1,表示每一行的特徵向量的最後一個數值代表單詞zzh
[[0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 1]
[0 0 0 1 0 1 0 0 1 0 0 0 0 1 0 1]
[1 0 0 0 1 0 0 1 0 1 1 1 1 0 1 1]]
#但是字袋模型只支持2個字符以上的單詞爲一體
analyze = vec.build_analyzer()
print(analyze('zzh is a diligent boy') == (['zzh', 'is', 'diligent', 'boy']))
True
#次處不用單詞a也顯示True
print(vec.get_feature_names())#顯示特徵名稱
['and', 'boy', 'diligent', 'everyday', 'finishes', 'goes', 'is', 'it', 'library', 'list', 'makes', 'on', 'purpose', 'to', 'to_do', 'zzh']
print(vec.vocabulary_.get('zzh'))#告知特徵所在特徵向量的位置
15#通過上一條指令我們發現特徵zzh在第16個,即是正確的
#如果語料庫內不包含一些新的單詞那麼這些新單詞會被置零,表示單詞不在語料庫中
print(vec.transform(['zzh wants to relax today']).toarray())
[[0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1]]
#to和zzh在語料庫中,所以對應的特徵位置爲1
爲了解決上述提到的問題,即字袋模型無法區分單詞之間的聯繫,比如 go to和to go,在字袋模型裏面表示的是相同的特徵,即這兩個單詞所在的位置,對應的數均爲1,無法體現出區別,現在會採用2-grams of words 即兩個詞爲一組,這樣就可以區分了。
vec1=CountVectorizer(ngram_range=(1,2))
analyze1=vec1.build_analyzer()
print(analyze1('zzh are cool')==['zzh','are','cool','zzh are','are cool'])#唯一的區別就是我們的分組規格不再是(1,1)而是(1,2)即1行2列爲一組
True
#這樣既可以單字符區分,也可以按多字符區分,提高了詞語的相關性。
以上代碼有一個核心點我們在創建特徵向量的時候必須要賦予對應的語料庫,如果不按照這個要求先創建特徵向量的話,許多功能是無法直接進行的。
考慮到詞頻可以使用TfidfVectorizer()
用法同CountVectorizer一致,只不過這個語句是通過詞出現的次數,反應詞頻量(logn,n爲出現次數)
- image feature extraction