scikit-learn點滴

scikit-learn點滴

scikit-learn是非常漂亮的一個機器學(xué)習(xí)庫,在某些時候,使用這些庫能夠大量的節(jié)省你的時間,至少,我們用python,應(yīng)該是很難寫出速度快如斯的代碼的.

scikit-learn官方出了一些文檔,但是個人覺得,它的文檔很多東西都沒有講清楚,它說算法原理的時候,只是描述一下,除非你對這種算法已經(jīng)爛熟于心,才會對它的描述會心一笑,它描述API的時候,很多時候只是講了一些常見用法,一些比較高級的用法就語焉不詳,雖然有很多人說,這玩意的文檔寫得不錯,但是我覺得特坑.所以這篇博文,會記錄一些我使用這個庫的時候碰到的一些坑,以及如何跨過這些坑.慢慢來更新吧,當(dāng)然,以后如果不用了,文章估計也不會更新了,當(dāng)然,我也沒有打算說,這篇文章有多少人能看.就這樣吧.

聚類

坑1: 如何自定義距離函數(shù)?

雖然說scikit-learn這個庫實現(xiàn)了很多的聚類函數(shù),但是這些算法使用的距離大部分都是歐氏距離或者明科夫斯基距離,事實上,根據(jù)我們教材上的描述,所謂的距離,可不單單僅有這兩種,為了不同的目的,我們可以用不同的距離來度量兩個向量之間的距離,但是很遺憾,我并沒有看見scikit-learn中提供自定義距離的選項,網(wǎng)上搜了一大圈也沒有見到.

但是不用擔(dān)心,我們可以間接實現(xiàn)這個東西.以DBSCAN算法為例,下面是類的一個構(gòu)造函數(shù):

class sklearn.cluster.DBSCAN(eps=0.5, min_samples=5, metric='euclidean', algorithm='auto', leaf_size=30, p=None, n_jobs=1)
# eps表示兩個向量可以被視作為同一個類的最大的距離
# min_samples表示一個類中至少要包含的元素數(shù)量,如果小于這個數(shù)量,那么不構(gòu)成一個類

我們要特別注意一下metric這個選項,我們來看一下選項:

metric : string, or callable
    The metric to use when calculating distance between instances in a feature array. If metric is a string or callable, it must be one of the options allowed by metrics.pairwise.calculate_distance for its metric parameter. 
    If metric is “precomputed”, X is assumed to be a distance matrix and must be square. X may be a sparse matrix, in which case only “nonzero” elements may be considered neighbors for DBSCAN.
    New in version 0.17: metric precomputed to accept precomputed sparse matrix.

這段描述其實透露了一個很重要的信息,那就是其實你可以自己提前計算各個向量的相似度,構(gòu)成一個相似度的矩陣,只要你設(shè)置metric='precomputedd'就行,那么如何調(diào)用呢?

我們來看一下fit函數(shù).

fit(X, y=None, sample_weight=None)
# X : array or sparse (CSR) matrix of shape (n_samples, n_features), or array of shape (n_samples, n_samples)
# A feature array, or array of distances between samples if metric='precomputed'.

上面的注釋是什么意思呢,我翻譯一下,如果你將metric設(shè)置成了precomputed的話,那么傳入的X參數(shù)應(yīng)該為各個向量之間的相似度矩陣,然后fit函數(shù)會直接用你這個矩陣來進(jìn)行計算.否則的話,你還是要乖乖地傳入(n_samples, n_features)形式的向量.

這意味著什么,同志們.這意味著我們可以用我們自定義的距離事先計算好各個向量的相似度,然后調(diào)用這個函數(shù)來獲得結(jié)果,是不是很爽.

具體怎么來編程,我給個例子,拋個磚.

import numpy as np
from sklearn.cluster import DBSCAN
if __name__ == '__main__':
    Y = np.array([[0, 1, 2],
                  [1, 0, 3],
                  [2, 3, 0]]) # 相似度矩陣,距離越小代表兩個向量距離越近
    # N = Y.shape[0]
    db = DBSCAN(eps=0.13, metric='precomputed', min_samples=3).fit(Y)
    labels = db.labels_
    # 然后來看一下分類的結(jié)果吧!
    n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0) # 類的數(shù)目
    print('類的數(shù)目是:%d'%(n_clusters_))

我們繼續(xù)來看一下AP聚類,其實也很類似:

class sklearn.cluster.AffinityPropagation(damping=0.5, max_iter=200, convergence_iter=15, copy=True, preference=None, affinity='euclidean', verbose=False)

關(guān)鍵在這個affinity參數(shù)上:

affinity : string, optional, default=``euclidean``
    Which affinity to use. At the moment precomputed and euclidean are supported. euclidean uses the negative squared euclidean distance between points.

這個東西也支持precomputed參數(shù).再來看一下fit函數(shù):

fit(X, y=None)
# Create affinity matrix from negative euclidean distances, then apply affinity propagation clustering.
# Parameters:   
#   X: array-like, shape (n_samples, n_features) or (n_samples, n_samples) :
#   Data matrix or, if affinity is precomputed, matrix of similarities / affinities.

這里的X和前面是類似的,如果你將metric設(shè)置成了precomputed的話,那么傳入的X參數(shù)應(yīng)該為各個向量之間的相似度矩陣,然后fit函數(shù)會直接用你這個矩陣來進(jìn)行計算.否則的話,你還是要乖乖地傳入(n_samples, n_features)形式的向量.

例子1

"""
    目標(biāo):
    ~~~~~~~~~~~~~~~~
    在這個文件里面,我最想測試一下的是,我前面的那些聚類算法是否是正確的.
    首先要測試的是AP聚類.
"""
from sklearn.cluster import AffinityPropagation
from sklearn import metrics
from sklearn.datasets.samples_generator import make_blobs
from sklearn.metrics.pairwise import euclidean_distances
import matplotlib.pyplot as plt
from itertools import cycle

def draw_pic(n_clusters, cluster_centers_indices, labels, X):
    ''' 口說無憑,繪制一張圖就一目了然. '''
    colors = cycle('bgrcmykbgrcmykbgrcmykbgrcmyk')
    for k, col in zip(range(n_clusters), colors):
        class_members = labels == k
        cluster_center = X[cluster_centers_indices[k]] # 得到聚類的中心
        plt.plot(X[class_members, 0], X[class_members, 1], col + '.')
        plt.plot(cluster_center[0], cluster_center[1], 'o', markerfacecolor=col,
                 markeredgecolor='k', markersize=14)
        for x in X[class_members]:
            plt.plot([cluster_center[0], x[0]], [cluster_center[1], x[1]], col)

    plt.title('Estimated number of clusters: %d' % n_clusters)
    plt.show()


if __name__ == '__main__':
    centers = [[1, 1], [-1, -1], [1, -1]]
    # 接下來要生成300個點,并且每個點屬于哪一個中心都要標(biāo)記下來,記錄到labels_true中.
    X, labels_true = make_blobs(n_samples=300, centers=centers,
                                cluster_std=0.5, random_state=0)
    af = AffinityPropagation(preference=-50).fit(X) # 開始用AP聚類
    cluster_centers_indices = af.cluster_centers_indices_ # 得到聚類的中心點
    labels = af.labels_ # 得到label
    n_clusters = len(cluster_centers_indices) # 類的數(shù)目
    draw_pic(n_clusters, cluster_centers_indices, labels, X)

    #===========接下來的話提前計算好距離=================#
    distance_matrix = -euclidean_distances(X, squared=True) # 提前計算好歐幾里德距離,需要注意的是,這里使用的是歐幾里德距離的平方
    af1 = AffinityPropagation(affinity='precomputed', preference=-50).fit(distance_matrix)
    cluster_centers_indices1 = af1.cluster_centers_indices_ # 得到聚類的中心
    labels1 = af1.labels_ # 得到label
    n_clusters1 = len(cluster_centers_indices1) # 類的數(shù)目
    draw_pic(n_clusters1, cluster_centers_indices1, labels1, X)

兩種方法都將產(chǎn)生這樣的圖:

AP聚類

例子2

既然都到這里了,我們索性來測試一下DBSCAN算法好了.

"""
    目標(biāo):
    ~~~~~~~~~~~~~~
    前面已經(jīng)測試過了ap聚類,接下來測試DBSACN.
"""
import numpy as np
from sklearn.cluster import DBSCAN
from sklearn import metrics
from sklearn.datasets.samples_generator import make_blobs
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
from sklearn.metrics.pairwise import euclidean_distances

def draw_pic(n_clusters, core_samples_mask, labels, X):
    ''' 開始繪制圖片 '''
    # Black removed and is used for noise instead.
    unique_labels = set(labels)
    colors = plt.cm.Spectral(np.linspace(0, 1, len(unique_labels)))
    for k, col in zip(unique_labels, colors):
        if k == -1:
            # Black used for noise.
            col = 'k'

        class_member_mask = (labels == k)

        xy = X[class_member_mask & core_samples_mask]
        plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=col,
                 markeredgecolor='k', markersize=14)

        xy = X[class_member_mask & ~core_samples_mask]
        plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=col,
                 markeredgecolor='k', markersize=6)

    plt.title('Estimated number of clusters: %d' % n_clusters)
    plt.show()

if __name__ == '__main__':
    #=========首先產(chǎn)生數(shù)據(jù)===========#
    centers = [[1, 1], [-1, -1], [1, -1]]
    X, labels_true = make_blobs(n_samples=750, centers=centers,
                                cluster_std=0.4, random_state=0)
    X = StandardScaler().fit_transform(X)
    #=========接下來開始聚類==========#
    db = DBSCAN(eps=0.3, min_samples=10).fit(X)
    labels = db.labels_ # 每個點的標(biāo)簽
    core_samples_mask = np.zeros_like(db.labels_, dtype=bool)
    core_samples_mask[db.core_sample_indices_] = True
    n_clusters = len(set(labels)) - (1 if -1 in labels else 0) # 類的數(shù)目
    draw_pic(n_clusters, core_samples_mask, labels, X)
    #==========接下來我們提前計算好距離============#
    distance_matrix =  euclidean_distances(X)
    db1 = DBSCAN(eps=0.3, min_samples=10, metric='precomputed').fit(distance_matrix)
    labels1 = db1.labels_ # 每個點的標(biāo)簽
    core_samples_mask1 = np.zeros_like(db1.labels_, dtype=bool)
    core_samples_mask1[db1.core_sample_indices_] = True
    n_clusters1 = len(set(labels1)) - (1 if -1 in labels1 else 0) # 類的數(shù)目
    draw_pic(n_clusters1, core_samples_mask1, labels1, X)

兩種方法都將產(chǎn)生這樣的圖:

DBSCAN聚類

好吧,暫時介紹到這里吧,但是有意思的是,最簡單的KMeans算法倒是不支持這樣的干活.

數(shù)據(jù)集切分

給定一個非常龐大的訓(xùn)練集,我們通常要將這個訓(xùn)練集進(jìn)行切分,比如說用80%的數(shù)據(jù)進(jìn)行參數(shù)的訓(xùn)練,然后20%的數(shù)據(jù)用來測試我們訓(xùn)練的模型,這個時候就可以用到sklearn中的數(shù)據(jù)切分函數(shù)train_test_split了.

舉一個例子,下面使用IPython進(jìn)行操作:

In [1]: from sklearn.cross_validation import train_test_split
In [2]: x = [['這是', '第一個', '測試']] * 100 + [['這是', '第二個', '測試']] * 100
In [3]: x  # 輸出x
Out[3]:
 ['這是', '第一個', '測試'],
 ['這是', '第一個', '測試'],
 ['這是', '第一個', '測試'],
...
 ['這是', '第二個', '測試'],
 ['這是', '第二個', '測試'],
 ['這是', '第二個', '測試'],
In [4]: y = [1] * 100 + [2] * 100
In [5]: y
Out[5]:
[1,
 1,
 1,

...
 2,
 2,
 2]
In [6]: x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)
In [7]: x_train
Out[7]: 
[['這是', '第一個', '測試'],
 ['這是', '第一個', '測試'],
 ['這是', '第二個', '測試'],
 ...
 ['這是', '第一個', '測試'],
 ['這是', '第二個', '測試'],
 ['這是', '第二個', '測試']]
In [8]: len(x_train)  # 求測試集的大小
Out[8]: 160
# 接下來驗證是否正確
In [9]: for i in range(len(x_test)):
    ..:      print("".join(x_test[i]), y_test[i])  
這是第一個測試 1
這是第二個測試 2
這是第一個測試 1
...
這是第二個測試 2
這是第二個測試 2
這是第一個測試 1
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末书妻,一起剝皮案震驚了整個濱河市鸯匹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌践图,老刑警劉巖球凰,帶你破解...
    沈念sama閱讀 212,332評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凛膏,死亡現(xiàn)場離奇詭異,居然都是意外死亡熊经,警方通過查閱死者的電腦和手機泽艘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,508評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镐依,“玉大人匹涮,你說我怎么就攤上這事』笨牵” “怎么了然低?”我有些...
    開封第一講書人閱讀 157,812評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長务唐。 經(jīng)常有香客問我雳攘,道長,這世上最難降的妖魔是什么枫笛? 我笑而不...
    開封第一講書人閱讀 56,607評論 1 284
  • 正文 為了忘掉前任吨灭,我火速辦了婚禮,結(jié)果婚禮上刑巧,老公的妹妹穿的比我還像新娘喧兄。我一直安慰自己,他們只是感情好啊楚,可當(dāng)我...
    茶點故事閱讀 65,728評論 6 386
  • 文/花漫 我一把揭開白布吠冤。 她就那樣靜靜地躺著,像睡著了一般恭理。 火紅的嫁衣襯著肌膚如雪拯辙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,919評論 1 290
  • 那天颜价,我揣著相機與錄音薄风,去河邊找鬼。 笑死拍嵌,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的循诉。 我是一名探鬼主播横辆,決...
    沈念sama閱讀 39,071評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了狈蚤?” 一聲冷哼從身側(cè)響起困肩,我...
    開封第一講書人閱讀 37,802評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎脆侮,沒想到半個月后锌畸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,256評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡靖避,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,576評論 2 327
  • 正文 我和宋清朗相戀三年潭枣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幻捏。...
    茶點故事閱讀 38,712評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡盆犁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出篡九,到底是詐尸還是另有隱情谐岁,我是刑警寧澤,帶...
    沈念sama閱讀 34,389評論 4 332
  • 正文 年R本政府宣布榛臼,位于F島的核電站伊佃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏沛善。R本人自食惡果不足惜航揉,卻給世界環(huán)境...
    茶點故事閱讀 40,032評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望路呜。 院中可真熱鬧迷捧,春花似錦、人聲如沸胀葱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抵屿。三九已至庆锦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間轧葛,已是汗流浹背搂抒。 一陣腳步聲響...
    開封第一講書人閱讀 32,026評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留尿扯,地道東北人求晶。 一個月前我還...
    沈念sama閱讀 46,473評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像衷笋,于是被迫代替她去往敵國和親芳杏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,606評論 2 350

推薦閱讀更多精彩內(nèi)容