4、无监督学习笔记

无监督学习

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()
posted @ 2018-02-14 09:38  NSGUF  阅读(685)  评论(0编辑  收藏  举报