多维度分簇可视化

前言

前段时间做各种样本分簇,发现维度有很多,又很难在二位图形可视化中表达清楚。于是稍微总结了一些常用地可视化的方法,也就是对数据降维,将每个样本的特征刻画在一种二维图形中。

案例

背景:
某游戏公司收集每一位玩家的行为数据以及其属性,加工后制作数据集如下:
在这里插入图片描述
toy_id为每一位玩家用户的唯一识别id,a-l为加工出表示玩家属性的特征信息。
我们采取统计性图表分析+无监督学习的方式,将这N位玩家用户分成x个簇。

顺便分享下DBSCN模型和k-prototypes的代码,方便大家以后分簇使用😄
*注意连续变量要剔除量纲影响…

k-prototypes:
连续型变量+分类变量(欧式距离+汉明距离)

"""
k-prototypes
"""
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
%matplotlib inline
import pandas as pd
import numpy as np
from sklearn import preprocessing
from sklearn.cluster import KMeans
from sklearn.cluster import MiniBatchKMeans
from yellowbrick.cluster import KElbowVisualizer
from yellowbrick.cluster import SilhouetteVisualizer
from yellowbrick.cluster import InterclusterDistance
from yellowbrick.model_selection import LearningCurve
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style("whitegrid")
sns.set_context("notebook")
import numpy as np
import pandas as pd
from kmodes.kprototypes import KPrototypes
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns


"""
归一化,用于处理量纲不同的问题,本案例不适用
"""
def minmax(calc_case):
    min_max_scaler = MinMaxScaler()
    x_scaled = min_max_scaler.fit_transform(calc_case)
    X_scaled = pd.DataFrame(x_scaled,columns=calc_case.columns)
    return X_scaled

def data_clean(data, key=None, strlist=None, numlist=None):
    data = data.fillna(0)
    for s in strlist:
        data[s] = data[s].astype(str)
    temp = data[[key]+strlist]
    temp2 = data[numlist]
    clean = pd.concat([temp,minmax(temp2)],axis=1)
    return clean


def elbow_method(X,k=None,categorical=None):
    X2 = X[X.columns.values[1:]]
    X_matrix = X2.values
    cost = []
    for num_clusters in list(range(1,k)):
        kproto = KPrototypes(n_clusters=num_clusters, init='Cao')
        kproto.fit_predict(X_matrix, categorical=categorical)
        tl = []
        tl.append(num_clusters)
        tl.append(kproto.cost_)
        cost.append(tl)
    cost = pd.DataFrame(cost,columns=['num_clusters','MSE'])
    beauty_plot(cost, 'MSE', date='num_clusters', marker='*',name='elbow_method-MSE',color=['navy'])
#     pd.DataFrame(cost)

def beauty_plot(para, *value, date=None, marker=None,name=None,color=None):
    plt.figure(figsize=(16,9))
#     plt.ylim(0,2000000)
    plt.xticks(fontsize=14)
    plt.yticks(fontsize=14)
    #y轴取消科学计数法
    x_formatter = matplotlib.ticker.ScalarFormatter(useOffset=False)
    x_formatter.set_scientific(False)
    plt.gca().yaxis.set_major_formatter(x_formatter)
    temp = para.sort_values(by=date)
    x = temp[date]
    y1 = temp[value[0]]
#     y2 = temp[value[1]]
#     y3 = temp[value[2]]
#     y2 = temp[value[1]]
    plt.xlabel(date)
    plt.ylabel(name)
    plt.title(name)
    plt.xticks(rotation=45)
#     plt.annotate('max', xy=(a, b), xytext=(a+relativedelta(days=2), b*1.1),arrowprops=dict(facecolor='black', shrink=0.05))
    # plt.plot(x_pron, y_porn, color="y", linestyle="--", marker="^", linewidth=1.0)
    plt.plot(x, y1, color=color[0], linestyle="--", marker=marker, linewidth=2.0,label=value[0])
#     plt.plot(x, y2, color=color[1], linestyle="--", marker=marker, linewidth=2.0,label=value[1])
#     plt.plot(x, y3, color=color[2], linestyle="--", marker=marker, linewidth=2.0,label=value[2])
#     plt.plot(x, y2, color='navy', linestyle="--", marker=marker, linewidth=1.0,label=value[1])
#     plt.plot(x, y3, color='navy', linestyle="--", marker=marker, linewidth=1.0,label=value[2])
    plt.legend() # 显示图例
    plt.grid(color="k", linestyle=":")
    plt.show()

def run_k_prototypes(X, k=None,categorical=None,key=None,strlist=None,numlist=None):
    X2 = data_clean(X, key=key,strlist=strlist,numlist=numlist)
    X2 = X2[X2.columns.values[1:]]
    X_matrix = X2.values
    kproto = KPrototypes(n_clusters=k, init='Cao')
    clusters = kproto.fit_predict(X_matrix, categorical=categorical)
    print('====== Centriods ======')
    print(kproto.cluster_centroids_)
    print('====== Cost ======')
    print(kproto.cost_)
    X['cluster'] = clusters
    # 我们可以从上面这个图里观察聚类效果的好坏,但是当数据量很大,或者指标很多的时候,观察起来就会非常麻烦。
#     from sklearn import metrics  
#     # 就是下面这个函数可以计算轮廓系数(sklearn真是一个强大的包)
#     score = metrics.silhouette_score(X_matrix,clusters,metric="precomputed")
#     print('====== Silhouette Coefficient ======')
#     print(score)
    return X

if __name__ == "__main___":
	data_clean(test_kpro,key='toy_id',strlist=['c','e','f','h'],numlist=['a','b','d','g','i','j','k','l'])
    elbow_method(test_kpro2,k=20,categorical=[0,1,2,3,4])
    test_kpro3 = run_k_prototypes(test_kpro, k=10,categorical=[0,1,2,3,4],key='toy_id',strlist=['c','e','f','h'],numlist=['a','b','d','g','i','j','k','l'])

DBSCAN:
Density-based spatial clustering of applications with noise

"""
DBSCAN
"""
from sklearn import datasets
import numpy as np
import random
import matplotlib.pyplot as plt
import time
import copy
 

def find_neighbor(j, x, eps):
    N = list()
    for i in range(x.shape[0]):
        temp = np.sqrt(np.sum(np.square(x[j]-x[i])))  # 计算欧式距离
        if temp <= eps:
            N.append(i)
    return set(N)
 

def DBSCAN(X, eps, min_Pts):
    k = -1
    neighbor_list = []  # 用来保存每个数据的邻域
    omega_list = []  # 核心对象集合
    gama = set([x for x in range(len(X))])  # 初始时将所有点标记为未访问
    cluster = [-1 for _ in range(len(X))]  # 聚类
    for i in range(len(X)):
        neighbor_list.append(find_neighbor(i, X, eps))
        if len(neighbor_list[-1]) >= min_Pts:
            omega_list.append(i)  # 将样本加入核心对象集合
    omega_list = set(omega_list)  # 转化为集合便于操作
    while len(omega_list) > 0:
        gama_old = copy.deepcopy(gama)
        j = random.choice(list(omega_list))  # 随机选取一个核心对象
        k = k + 1
        Q = list()
        Q.append(j)
        gama.remove(j)
        while len(Q) > 0:
            q = Q[0]
            Q.remove(q)
            if len(neighbor_list[q]) >= min_Pts:
                delta = neighbor_list[q] & gama
                deltalist = list(delta)
                for i in range(len(delta)):
                    Q.append(deltalist[i])
                    gama = gama - delta
        Ck = gama_old - gama
        Cklist = list(Ck)
        for i in range(len(Ck)):
            cluster[Cklist[i]] = k
        omega_list = omega_list - Ck
    return cluster

if __name__ == "__main___":
	eps = 0.1
	min_Pts = 10
	C = DBSCAN(X, eps, min_Pts)
	test['cluster'] = C
	"""
	轮廓系数sihouette
	"""
	from sklearn import metrics  
	score = metrics.silhouette_score(test2.iloc[:,1:-1],test2.iloc[:,-1]) 
	print(score)
	 

分簇完成后数据集:
在这里插入图片描述

传统二维\三维图

明确变量数组X,Y或者X,Y,Z。我们可以画出实际的情况。

根据具体需求自己再调哈~

二维图

示例:
在这里插入图片描述

def plotshow2(para, *value, date=None, marker=None,name=None,color=None):
    plt.figure(figsize=(22,10))
#     plt.ylim(0,2000000)
    plt.xticks(fontsize=14)
    plt.yticks(fontsize=14)
    #y轴取消科学计数法
    x_formatter = matplotlib.ticker.ScalarFormatter(useOffset=False)
    x_formatter.set_scientific(False)
    plt.gca().yaxis.set_major_formatter(x_formatter)
    temp = para.sort_values(by=date)
    x = temp[date]
    y1 = temp[value[0]]
    y2 = temp[value[1]]
#     y2 = temp[value[1]]
    plt.xlabel(date)
    plt.ylabel(name)
    plt.title(name)
    plt.xticks(rotation=45)
#     plt.annotate('max', xy=(a, b), xytext=(a+relativedelta(days=2), b*1.1),arrowprops=dict(facecolor='black', shrink=0.05))
    # plt.plot(x_pron, y_porn, color="y", linestyle="--", marker="^", linewidth=1.0)
    plt.plot(x, y1, color=color[0], linestyle="--", marker=marker, linewidth=2.0,label=value[0])
    plt.plot(x, y2, color=color[1], linestyle="--", marker=marker, linewidth=2.0,label=value[1])
    plt.legend() # 显示图例
    plt.grid(color="k", linestyle=":")
    plt.show()

三维图

示例:
在这里插入图片描述

"""
三维空间图
"""
data_int = data.copy()
for item in list(data_int.columns)[1:]:
    data_int[item] = data_int[item].apply(lambda x: round(x))
    
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

data = np.random.randint(0, 255, size=[40, 40, 40])

x, y, z = np.array(data_int['aaaa']), np.array(data_int['bbb']), np.array(data_int['cccc'])
ax = plt.subplot(111, projection='3d')  # 创建一个三维的绘图工程
#  将数据点分成三部分画,在颜色上有区分度
ax.scatter(x[:177], y[:177], z[:177], c='y')  # 绘制数据点
ax.scatter(x[177:354], y[177:354], z[177:354], c='r')
ax.scatter(x[354:532], y[354:532], z[354:532], c='g')

ax.set_zlabel('aaaa')  # 坐标轴
ax.set_ylabel('bbb')
ax.set_xlabel('cccc')
plt.show()

N维图

N维图其实一句话,需要我们单拿出标签,剩下的所有特征做降维处理,才能方便我们肉眼去看…(可怜的三维生物o(╥﹏╥)o~~~)
那么下面介绍几种常用的降维方法:

pairplot

pairplot非常好用,尤其在机器学习中,经常用它来观察各特征间分布情况。同时,也可以通过hue参数来设置分簇的结果。非常直观~!
在这里插入图片描述

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.pairplot(pair, hue='cluster',size=2, kind='reg')

PCA主成分分析

通过正交变换将原始特征转换为线性独立的特征,转换后得到的特征被称为主成分。主成分分析可以将原始维度降维到n个维度,有一个特例情况,就是通过主成分分析将维度降低为2维,这样的话,就可以将多维数据转换为平面中的点,来达到多维数据可视化的目的。

在这里插入图片描述

"""
主成分分析(PCA)
"""
from sklearn import decomposition

pca = decomposition.PCA(n_components=2)

X = pca.fit_transform(test2.iloc[:,1:-1].values)

pos=pd.DataFrame()
pos['X'] =X[:, 0]
pos['Y'] =X[:, 1]
pos['cluster'] = test2['cluster']

ax = pos[pos['cluster']==-1].plot(kind='scatter', x='X', y='Y', color='blue', label='-1簇')
pos[pos['cluster']==0].plot(kind='scatter', x='X', y='Y', color='green', label='0簇', ax=ax)
pos[pos['cluster']==1].plot(kind='scatter', x='X', y='Y', color='red', label='1簇', ax=ax)
pos[pos['cluster']==2].plot(kind='scatter', x='X', y='Y', color='orange', label='2簇', ax=ax)

多维度量尺(Multi-dimensional scaling, MDS)

多维量表试图寻找原始高维空间数据的距离的良好低维表征。简单来说,多维度量尺被用于数据的相似性,它试图用几何空间中的距离来建模数据的相似性,直白来说就是用二维空间中的距离来表示高维空间的关系。数据可以是物体之间的相似度、分子之间的交互频率或国家间交易指数。这一点与前面的方法不同,前面的方法的输入都是原始数据,而在多维度量尺的例子中,输入是基于欧式距离的距离矩阵。多维度量尺算法是一个不断迭代的过程,因此,需要使用max_iter来指定最大迭代次数,同时计算的耗时也是上面算法中最大的一个。
在这里插入图片描述

"""
多维度量尺(Multi-dimensional scaling, MDS)
"""
from sklearn import manifold

from sklearn.metrics import euclidean_distances

similarities = euclidean_distances(test2.iloc[:,1:-1].values)
# mds = manifold.MDS(n_components=2, max_iter=3000, eps=1e-9, dissimilarity="precomputed", n_jobs=1)
mds = manifold.MDS(n_components=2, max_iter=3000, eps=1e-9, dissimilarity="euclidean", n_jobs=1)
X = mds.fit(similarities).embedding_

pos=pd.DataFrame(X, columns=['X', 'Y'])
pos['cluster'] = test2['cluster']

ax = pos[pos['cluster']==-1].plot(kind='scatter', x='X', y='Y', color='blue', label='-1簇')
pos[pos['cluster']==0].plot(kind='scatter', x='X', y='Y', color='green', label='0簇', ax=ax)
pos[pos['cluster']==1].plot(kind='scatter', x='X', y='Y', color='red', label='1簇', ax=ax)
pos[pos['cluster']==2].plot(kind='scatter', x='X', y='Y', color='orange', label='2簇', ax=ax)

TSNE(t-distributed Stochastic Neighbor Embedding)

t-SNE(t分布随机邻域嵌入)是一种用于探索高维数据的非线性降维算法。通过基于具有多个特征的数据点的相似性识别观察到的簇来在数据中找到模式,将多维数据映射到适合于人类观察的两个或多个维度。本质上是一种降维和可视化技术。使用该算法的最佳方法是将其用于探索性数据分析。
在这里插入图片描述

"""
TSNE(t-distributed Stochastic Neighbor Embedding
"""
from sklearn.manifold import TSNE

iris_embedded = TSNE(n_components=2).fit_transform(test2.iloc[:,1:-1].values)

pos = pd.DataFrame(iris_embedded, columns=['X','Y'])
pos['cluster'] = test2['cluster']

ax = pos[pos['cluster']==-1].plot(kind='scatter', x='X', y='Y', color='blue', label='-1簇')
pos[pos['cluster']==0].plot(kind='scatter', x='X', y='Y', color='green', label='0簇', ax=ax)
pos[pos['cluster']==1].plot(kind='scatter', x='X', y='Y', color='red', label='1簇', ax=ax)
pos[pos['cluster']==2].plot(kind='scatter', x='X', y='Y', color='orange', label='2簇', ax=ax)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值