1. 程式人生 > >無監督學習筆記

無監督學習筆記

end who 配送 names core 用例 wid mil -m

無監督學習

1、簡介

無監督學習是一種對不含標記的數據建立模型的機器學習範式。最常見的無監督學習方法是聚類,就是講無標記的數據分成幾種集群,這些集群通常是根據某種相似度指標進行的,如歐氏距離(Euclidean distance),常用領域有:數據挖掘、醫學影像、股票市場分析、計算機視覺、市場細分等。

2、用k-means算法聚類數據

k-means算法常用數據的不同屬性將輸入數據劃分成k組。分組是使用最優化的技術實現的,即讓各組的數據點與該組中心點的距離平方和最小化。例子如下:

import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans

def load_data(input_file):
    X = []
    with open(input_file, ‘r‘) as f:
        for line in f.readlines():
            data = [float(x) for x in line.split(‘,‘)]
            X.append(data)
    return np.array(X)


# 1、獲取數據並可視化
input_file = ‘data_multivar.txt‘
data = load_data(input_file)
x_min,x_max=min(data[:,0])-1,max(data[:,0])+1
y_min,y_max=min(data[:,1])-1,max(data[:,1])+1
‘‘‘
plt.figure()
plt.scatter(data[:,0], data[:,1],
        facecolors=‘none‘, edgecolors=‘k‘)
plt.xlim(x_min,x_max)
plt.ylim(y_min,y_max)
plt.show()
‘‘‘
# 2、獲取k-means對象,並訓練
kmeans=KMeans(n_clusters=4,init=‘k-means++‘,n_init=10)
kmeans.fit(data)
# 3、獲取邊界
step_size=0.01
x_values,y_values=np.meshgrid(np.arange(x_min,x_max,step_size),np.arange(y_min,y_max,step_size))
predict_labels=kmeans.predict(np.c_[x_values.ravel(),y_values.ravel()])
predict_labels=predict_labels.reshape(x_values.shape)
# 4、畫出邊界
plt.figure()
plt.clf()
plt.imshow(predict_labels, interpolation=‘nearest‘,
           extent=(x_values.min(), x_values.max(), y_values.min(), y_values.max()),
           cmap=plt.cm.Paired,
           aspect=‘auto‘, origin=‘lower‘)
plt.scatter(data[:,0], data[:,1],
        facecolors=‘none‘, edgecolors=‘k‘)

centero=kmeans.cluster_centers_
plt.scatter(centero[:,0],centero[:,1],linewidths=5,facecolor=‘black‘)

plt.xlim(x_min,x_max)
plt.ylim(y_min,y_max)
plt.show()

圖片顯示如下:

技術分享圖片

3、用矢量量化壓縮圖片

k-means聚類的主要應用之一就是矢量量化。矢量量化就是“四舍五入”(rounding off)的N維版本。在處理數字等一維數據時,會用四舍五入技術減少存儲空間。矢量量化被廣泛應用於圖片壓縮,用比原始圖像更少的比特數來存儲每個像素,從而實現圖像圖片。
import argparse

# 1、創建一個函數,用來解析輸入參數,輸入參數為圖片和每個像素被壓縮的比特數。
def build_arg_parser():
    parser = argparse.ArgumentParser(description=‘輸入圖片‘)
    parser.add_argument(‘--input-file‘, dest=‘input_file‘, required=True, help=‘輸入圖片‘)
    parser.add_argument(‘--num-bits‘, dest=‘num_bits‘, type=int, required=False, help=‘比特數‘)
    return parser


# 2、壓縮輸入圖片
def compress_img(img, num_cluster):
    print(img)
    X = img.reshape(-1, 1)
    print(X)
    kmeans = KMeans(n_clusters=num_cluster, n_init=4, random_state=5)
    kmeans.fit(X)
    contrid = kmeans.cluster_centers_.squeeze()
    labels = kmeans.labels_
    input_compress = np.choose(labels, contrid).reshape(img.shape)
    return input_compress

# 3、查看壓縮算法對圖片質量的影響
def plot_image(img,title):
    vmin=img.min()
    vmax=img.max()
    plt.figure()
    plt.title(title)
    plt.imshow(img,cmap=plt.cm.gray,vmin=vmin,vmax=vmax)

if __name__ == ‘__main__‘:
    args = build_arg_parser().parse_args()
    input_file=args.input_file
    num_bits=args.num_bits
    if not 1<=num_bits<=8:
        raise TypeError(‘比特數應該在1和8之間‘)
    num_clusters=np.power(2,num_bits)
    compression_rate=round(100*(8.0-args.num_bits)/8.0,2)
    input_image=misc.imread(input_file,True).astype(np.uint8)
    plot_image(input_image,‘image‘)
    input_compress=compress_img(input_image,num_clusters)
    plot_image(input_compress,‘rate=‘+str(compression_rate)+‘%‘)
    plt.show()

4、建立均值漂移聚類模型

均值漂移是一種非常強大的無監督學習算法,用於集群數據點。該算法把數據點的分布看成是概率密度函數(probability-density function),希望在特征空間中根據函數分布特征找出數據點的“模式”(mode),這些“模式”就對應於一群群局部最密集(local maxima)分布的點。該算法的優點在於它無需事先確定集群的數量。例子如下:

# 均值漂移聚類模型
from sklearn.cluster import MeanShift,estimate_bandwidth
# 1、獲取數據
X=load_data(‘data_multivar.txt‘)
# 2、通過指定輸入參數創建均值漂移模型
bandwidth=estimate_bandwidth(X,quantile=0.1,n_samples=len(X))
meanshift=MeanShift(bandwidth=bandwidth,bin_seeding=True)
# 3、訓練模型
meanshift.fit(X)
# 4、提取標記
labels=meanshift.labels_
# 5、獲取集群中心點,並打印數量
centroids=meanshift.cluster_centers_
num_clusters=len(np.unique(labels))
print(labels)
print(centroids)
print(num_clusters,len(centroids))
# 6、可視化
markers=‘.*xv‘
plt.figure()
for i,marker in zip(range(len(markers)),markers):
    plt.scatter(X[labels==i,0],X[labels==i,1],marker=marker,color=‘k‘)
    centroid=centroids[i]
    plt.plot(centroid[0],centroid[1],marker=‘o‘,markersize=15,markeredgecolor=‘k‘,markerfacecolor=‘k‘)
plt.title(‘顯示‘)
plt.show()

5、用凝聚層次聚類進行分組

層次聚類:一組聚類算法,通過不斷的分解或合並集群來構建樹狀集群(tree-like clusters),其結構可用一棵樹表示。該算法可自上而下,也可自下而上。
凝聚層次聚類:即自下而上的算法,每一個數據點被看做一個單獨的子集,而讓這些子集不斷的合並,直到所有集合合並為一個巨型集群。相反,自上而下則是分解。直到所有集群變為一個單獨的數據點。

def get_spiral(t,noise_amplitude=0.5):# 獲取呈螺旋狀的數據
    r=t
    x=r*np.cos(t)
    y=r*np.sin(t)
    return add_noise(x,y,noise_amplitude)
def get_rose(t,noise_amplitude=0.02):# 獲取呈螺旋狀的數據
    k=5
    r=np.cos(k*t)+0.25
    x=r*np.cos(t)
    y=r*np.sin(t)
    return add_noise(x,y,noise_amplitude)
def get_hypotrochoid(t, noise_amplitude=0):
    a, b, h = 10.0, 2.0, 4.0
    x = (a - b) * np.cos(t) + h * np.cos((a - b) / b * t) 
    y = (a - b) * np.sin(t) - h * np.sin((a - b) / b * t) 

    return add_noise(x, y, 0)
def add_noise(x,y,amplitude):# 添加噪音
    X=np.concatenate((x,y))
    X+=amplitude*np.random.randn(2,X.shape[1])
    return X.T
from sklearn.cluster import AgglomerativeClustering

def perform_clustering(X,connectivity,title,num_clusters=3,linkage=‘ward‘):# 設置層次凝聚模型
    plt.figure()
    model=AgglomerativeClustering(linkage=linkage,n_clusters=num_clusters,connectivity=connectivity)
    model.fit(X)

    labels=model.labels_

    markers=‘.vx‘

    for i,marker in zip(range(num_clusters),markers):
        plt.scatter(X[labels==i,0],X[labels==i,1],s=50,facecolor=‘none‘,marker=marker,color=‘k‘)
        plt.title(title)
from sklearn.neighbors import kneighbors_graph
if __name__==‘__main__‘:
    # 生成樣本數據
    n_samples=500
    np.random.seed(2)
    t=2.5*np.pi*(1+2*np.random.rand(1,n_samples))
    X=get_spiral(t)
    # X = get_rose(t)
    # X = get_hypotrochoid(t)
    connectivity=None
    perform_clustering(X,connectivity,‘沒有連接‘)


    connectivity=kneighbors_graph(X,10,include_self=False)
    perform_clustering(X,connectivity,‘knei連接‘)# 可讓連接在一起的數據組合在一起

    plt.show()

6、評價聚類算法的聚類效果

輪廓系數(Sihouette Coefficient)系數:得分=(x-y)/max(x,y),其中x表示在同一個集群中某個數據點與其他數據點的平均距離,y表示某個數據點與最近的另一個集群的所有點的平均距離,使用例子如下:

from sklearn import metrics
data=load_data(‘data_perf.txt‘)# 加載數據
scores=[]
range_values=np.arange(2,10)
for i in range_values:# 分別分i個集群
    kmean=KMeans(n_clusters=i,n_init=10,init=‘k-means++‘)
    kmean.fit(data)
    score=metrics.silhouette_score(data,kmean.labels_,metric=‘euclidean‘,sample_size=len(data))
    scores.append(score)

plt.figure()
plt.bar(range_values,scores,width=0.6,color=‘k‘,align=‘center‘)
plt.show()
plt.figure()
plt.scatter(data[:,0],data[:,1],color=‘k‘)
xmin,xmax=min(data[:,0])-1,max(data[:,0])+1
ymin,ymax=min(data[:,1])-1,max(data[:,1])+1
plt.xlim(xmin,xmax)
plt.ylim(ymin,ymax)
plt.show()

7、用DBSCAN算法自動估算集群數量

DBSCAN(Density-Based Spatial Clustering of Applications with Noise):帶噪聲的基於密度的聚類方法,將數據點看成是緊密集群的若幹組,若某個點屬於一個集群,那會有許多點也屬於同一個集群,該方法裏面有一個epsilon參數,可控制該點到其他點的最大距離。若兩點間距離超過epsilon,則他們不可能在一個集群中。該方法主要有點是它可以處理異常值,若某些點位於數據稀疏距離,則將其作為異常點,而不會強制將他們放入一個集群中。例子如下:

# 1、獲取數據
X=load_data(‘data_perf.txt‘)
# 2、初始化參數
eps_grid=np.linspace(0.3,1.2,num=10)
silhouette_scores=[]
eps_best=eps_grid[0]
silhouette_scores_max=-1
model_best=None
labels_best=None
# 3、以此執行所有參數
from sklearn.cluster import DBSCAN
from sklearn import metrics
for eps in eps_grid:
    model=DBSCAN(eps=eps,min_samples=5).fit(X)
    labels=model.labels_
    silhouette_score=round(metrics.silhouette_score(X,labels),4)
    silhouette_scores.append(silhouette_score)
    # 獲取指標的最佳得分
    if silhouette_score>silhouette_scores_max:
        silhouette_scores_max=silhouette_score
        eps_best=eps
        model_best=model
        labels_best=labels

# 4、畫出條形圖
plt.figure()
plt.bar(eps_grid,silhouette_scores,width=0.05,color=‘k‘,align=‘center‘)
plt.show()
# 5、由於可能會有某些點還沒有分配集群,所以這裏刪除未分配而獲取集群的數量
offset=0
if -1 in labels:
    offset=1
num_clusters=len(set(labels))-offset
# 6、提取核心樣本
model = model_best
labels = labels_best
mask_core=np.zeros(labels.shape,dtype=np.bool)# 初始化全部點的分配
mask_core[model.core_sample_indices_]=True# model.core_sample_indices_表示分配後的數據位置為True

# 7、數據可視化
from itertools import cycle
plt.figure()
labels_uniq=set(labels)
markers=cycle(‘vo^s<>‘)
for cur_label,marker in zip(labels_uniq,markers):
    if cur_label==-1:
        marker=‘.‘
    cur_mask=(labels==cur_label)# 獲取當前某個數據集的集合的索引
    cur_data=X[cur_mask&mask_core]# 當前數據集中正常的數據
    plt.scatter(cur_data[:,0],cur_data[:,1],marker=marker,edgecolors=‘black‘,s=96,facecolors=‘none‘)
    cur_data=X[cur_mask&-mask_core]# 當前數據集中異常數據
    plt.scatter(cur_data[:,0],cur_data[:,1],marker=marker,edgecolors=‘black‘,s=32)
plt.show()
                                    

8、近鄰傳播聚類

近鄰傳播聚類(Affinity Propagation):找出數據中每個集群的代表性數據點,找到數據點間的相似性度量值,並把所有數據點看成潛在的代表性數據點,也稱取樣器(exemplar)。具體查看如下鏈接:http://blog.csdn.net/u010161379/article/details/51636926

9、建立客戶細分模型

市場細分對廣告投放、庫存管理、配送策略的實施、大眾傳媒等市場行為都非常有用。在不同類型商品的銷售數據中,為客戶提供最優的銷售和分銷策略,例子如下:

# 1、獲取數據
import csv

input_file=‘wholesale.csv‘
file_reader=csv.reader(open(input_file,‘r‘),delimiter=‘,‘)
X=[]
for count,row in enumerate(file_reader):
    if not count:
        names=row[2:]
        continue
    X.append([float(x) for x in row[2:]])
X=np.array(X)
# 2、使用均值漂移訓練數據
from sklearn.cluster import MeanShift,estimate_bandwidth

bandwidth=estimate_bandwidth(X,quantile=0.8,n_samples=len(X))
model=MeanShift(bandwidth=bandwidth,bin_seeding=True)
model.fit(X)
labels=model.labels_
clucenters=model.cluster_centers_
num_centers=len(clucenters)
# 3、打印集群中心
print(‘\t‘.join([name[:3] for name in names]))
print(‘\t‘.join([str(clucenter) for clucenter in clucenters]))
# 4、把milk與groceries的聚類結果可視化
centriods_milk_groceries=clucenters[:,1:3]
plt.figure()
plt.scatter(centriods_milk_groceries[:,0],centriods_milk_groceries[:,1],color=‘k‘,s=100,facecolor=‘none‘)
offset=0.2
plt.xlim(centriods_milk_groceries[:,0].min()-offset*centriods_milk_groceries[:,0].ptp(),centriods_milk_groceries[:,0].max()+offset*centriods_milk_groceries[:,0].ptp())
plt.xlim(centriods_milk_groceries[:,1].min()-offset*centriods_milk_groceries[:,1].ptp(),centriods_milk_groceries[:,1].max()+offset*centriods_milk_groceries[:,1].ptp())
plt.show()

無監督學習筆記