美文网首页
Kmeans聚类 - 旅游企业客户洞察案例

Kmeans聚类 - 旅游企业客户洞察案例

作者: 熊定坤 | 来源:发表于2019-01-09 15:32 被阅读0次

    1.案例说明

    一般案例客户聚类分析流程(个人理解)

    1. 提取客户消费行为变量
    2. 对提取的行为变量进行正态化(使聚类结果更有商业解读意义),和Z-score处理(消除纲量)
    3. 对处理后的变量进行相关性分析
    4. 对处理后的变量进行主成分和因子分析(消除离群值)
    5. 对各因子基于业务理解进行解读
    6. 通过簇内离差平方和轮廓系数确定聚类簇的个数
    7. 对原数据在各因子上的得分进行聚类,并对结果进行解读
    8. 用客户个人属性变量及经济状态变量作为因变量,对分类结果构建决策树模型,探查各分类客户个人属性及经济状况

    由于案例数据集没有客户消费行为数据,对客户的兴趣爱好状态属性及家庭情况状态属性分别进行聚类,并对聚类结果通过决策树解读,探究旅游企业客户类型,并对各类型客户做业务解读,并提出精准营销建议

    2.查看数据,数据预处理

    读取数据
    os.chdir(r'C:\Users\Administrator\Desktop\Python_book\19Case\19_3Travel_clust')
    df = pd.read_csv('data_travel.csv')
    df.head()
    
    df.info()
    

    其中变量interested_reading为数值型,dtype显示为字符型,其包含错误值“.”,将其以0进行替换,代表该用户对阅读没有兴趣。

    df.interested_reading.value_counts()
    df['interested_reading'] = df['interested_reading'].replace('.',0).astype(int)
    
    缺失值处理
    #查看缺失情况
    df.isnull().sum()/len(df)
    

    缺失变量为连续变量,缺失率较小,填充中位数

    misscol = ['interested_travel','computer_owner','HH_adults_num']
    missvalue = {col:df[col].median() for col in misscol}
    df.fillna(missvalue,inplace=True)
    

    变量HH_has_children应为连续变量,将其二值化,其中NaN表示没有小孩,用0表示

    df['HH_has_children'] = df['HH_has_children'].map({'N':0,np.NaN:0,'Y':1})
    
    变量修改

    变量interested_reading 分类水平只有0,1,2,3将其二值化

    from sklearn.preprocessing import Binarizer
    binarizer = Binarizer(threshold=1.5)
    df['interested_reading'] = binarizer.fit_transform(df[['interested_reading']])
    

    'interested_reading','interested_travel','interested_golf','interested_gambling','computer_owner'五个变量代表是否对休闲娱乐的兴趣,将其做变量转化以五个变量的合计代表客户对休闲娱乐爱好广度

    interested = ['interested_reading','interested_travel','interested_golf','interested_gambling','computer_owner']
    df['interested'] = df[interested].sum(axis=1)
    df = df.drop(interested,axis=1)
    

    重新定义预处理后的数据

    data =df.copy()
    #定义变量属性
    #兴趣属性
    interest = ['auto_member',
    'interested_sport', 
    'interested', 
    'HH_dieting']
    #家庭信息属性
    household = ['age', 'marital', 'HH_adults_num', 'HH_has_children','HH_grandparent','home_value', 'risk_score', 'loan_ratio']
    

    3.正态化和Z-score标准化处理

    Z-score标准化处理
    #连续变量
    var_con = ['auto_member','interested_sport','age','HH_grandparent','home_value', 'risk_score', 'loan_ratio', 'HH_dieting']
    #水平较低的连续变量作为有序等级变量
    var_cat =['interested','HH_adults_num','marital']
    #二分类变量不做处理
    var_d = 'HH_has_children'
    

    水平较少的变量,如变量interested,作为有序分类变量,不做分布转化(正态化),直接标准化处理

    from sklearn.preprocessing import scale
    data[var_cat] = scale(data[var_cat])
    

    连续变量QuantileTransformer

    为避免聚类后某一类别较多(可能占到90%以上),为使每个类别的客户均匀分配,将原始分类变量进行正太转化

    # quantile_transform 函数提供了一个基于分位数函数的无参数转换,将数据映射到了零到一的均匀分布上
    # output_distribution='normal' 将转换后的数据映射到正态分布:
    from sklearn.preprocessing import QuantileTransformer
    qt = QuantileTransformer(output_distribution='normal')
    data[var_con] = qt.fit_transform(data[var_con])
    
    data[var_con].hist(bins =20)
    plt.show()
    
    QuantileTransformer后分布

    查看正态化和Z-score标准化处理后数据


    4.相关性分析

    sns.heatmap(data[interest].corr(),annot=True)
    
    interest属性
    sns.heatmap(data[household].corr(),annot=True,cmap='Blues')
    
    household属性

    进入聚类的各变量间具有一定相关性

    5.进行主成分和因子分析(消除离群值)

    from sklearn.decomposition import PCA
    pca = PCA()
    pca.fit(data[interest])
    print('累计方差贡献率',pca.explained_variance_ratio_.cumsum())
    print('-------------')
    print('方差贡献率越高,能解释的变异数据越多')
    

    累计方差贡献率 [ 0.49025739 0.71629358 0.91078434 1. ]
    方差贡献率越高,能解释的变异数据越多,可以选取2-3个因子
    其中保留3个主成分可以解释91%的变异数据,选取3个因子

    from fa_kit import FactorAnalysis
    from fa_kit import plotting as fa_plot
    fa = FactorAnalysis.load_data_samples(data[interest],preproc_demean = True,preproc_scale = True)
    #数据导入和转换
    fa.extract_components()
    #抽取主成分
    fa.find_comps_to_retain(method='top_n',num_keep=3)
    #确认保留因子的数量,使用top_n法
    fa.rotate_components(method='varimax')
    #使用最大方差法进行因子旋转
    

    查看各个因子在各变量上的权重

    fas = pd.DataFrame(fa.comps['rot'].T,columns = interest)
    fas
    
    第一个因子在auto_member,interested_sport变量上权重较大,表示客户对户外运动的度量,定义为户外运动因子
    第二个因子在HH_dieting,interested_sport变量上权重较大,表示客户选择保持身材的度量,定义为塑形因子
    第三个因子在interested变量上权重较大,表示客户选择休闲娱乐的度量,定义为休闲娱乐因子

    计算每个客户在各因子上的得分

    score = pd.DataFrame(np.dot(data[interest],fa.comps['rot']))
    score.columns=['户外运动因子','塑形因子','休闲娱乐因子']
    

    6.确定聚类簇的个数

    通过簇类离差平方和和silhouette_score系数确定最优的K值
    轮廓系数允许容易造成内存不足,也可通过calinski_harabaz系数确定最优的K值

    from sklearn.cluster import KMeans
    from sklearn.metrics import calinski_harabaz_score
    def cluster_plot(data):
        seed = []
        cs = []
        for k in range(2,10):
            model = KMeans(n_clusters=k,n_init=5,n_jobs=-1)
            model.fit(data)
            seed.append(model.inertia_)#离差平方和
            cs.append(calinski_harabaz_score(data,model.labels_))
    
        plt.subplot(221)
        plt.plot(range(2,10),seed)
        plt.subplot(222)
        plt.plot(range(2,10),cs)
    cluster_plot(score)
    

    分类类别越多,簇类离差平方越大,一般选取下降趋势最大的时作为K值选取范围,K=4后下降趋势变为平缓
    calinski_harabaz系数在K=2时最高,以后逐渐下降
    结合这两点我们选取k=3

    7. 进行聚类分析并解读
    model = KMeans(n_clusters=3,n_init=15,n_jobs=-1)
    model.fit(score)
    score['type'] = model.labels_
    
    from pyecharts import Pie
    attr = ['群体1','群体2','群体3']
    v1 = score.groupby('type').count().iloc[:,1]
    pie = Pie("各分类群体占比")
    pie.add("", attr, v1, is_label_show=True,radius=[20, 60])
    pie
    #各群体占比
    

    各分类占比较均匀,符合商业解读需求

    data_hh = score.groupby('type').mean()
    from pyecharts import Radar
    c_schema=[]
    for i in data_hh.columns:
        dict = {}
        dict['name'] = i
        dict['max'] = 2
        dict['min'] = -1
        c_schema.append(dict)
    radar = Radar()
    color = ['#50514F','#F25F5C','#FFE066']
    radar.config(c_schema=c_schema,shape='circle')
    for i in range(3):
        radar.add('群体%i'%(i+1),[data_hh.iloc[i]],is_area_show=True,area_opacity=0.6,area_color=color[i])
    radar
    
    聚类群体1 hh=0 偏爱健身,注重身材
    聚类群体2 hh=1 家里宅
    聚类群体3 hh=2 不太在意身形,偏向休闲娱乐
    8. 使用决策树算法进行分群后的用户个人信息及状态信息特征探查与理解
    import os
    os.environ["PATH"] += os.pathsep + 'C:/Program Files (x86)/Graphviz2.38/bin/' 
    df['hh'] = model.labels_
    #使用决策树算法进行分群后的用户个人信息及状态信息特征探查与理解
    from sklearn.tree import DecisionTreeClassifier
    clf= DecisionTreeClassifier()
    clf.fit(df[household],df['hh'])
    import pydotplus
    from IPython.display import Image
    import sklearn.tree as tree
    dot_hh = tree.export_graphviz(clf,out_file=None,feature_names=household,
                                 class_names=['0','1','2'],
                                 max_depth=2,filled=True,rounded=True,special_characters=True)
    graph_hh = pydotplus.graph_from_dot_data(dot_hh)
    Image(graph_hh.create_png())
    
    群体0特征,祖父是否健在可能性低于657.5(无长辈)
    群体1特征,贷款比例低于69,
    群体2特征,已婚可能性低于7.5(未婚)
    9. 对家庭属性进行聚类分析及解读
    from sklearn.decomposition import PCA
    pca = PCA()
    pca.fit(data[household])
    print('累计方差贡献率',pca.explained_variance_ratio_.cumsum())
    #保留4个主成分能解释87%的数据变异,选取4个因子
    #其中保留3个主成分可以解释91%的变异数据,选取3个因子
    from fa_kit import FactorAnalysis
    from fa_kit import plotting as fa_plot
    fa = FactorAnalysis.load_data_samples(data[household],preproc_demean = True,preproc_scale = True)
    #数据导入和转换
    fa.extract_components()
    #抽取主成分
    fa.find_comps_to_retain(method='top_n',num_keep=4)
    #确认保留因子的数量,使用top_n法
    fa.rotate_components(method='varimax')
    #使用最大方差法进行因子旋转
    fas = pd.DataFrame(fa.comps['rot'].T,columns = household)
    fas
    #第一个因子在年龄,祖辈建在可能性上权重较大,定义为长寿因子
    #第二个因子在房屋价值上,以及贷款比率权重较大,定义为经济状况因子
    #第三个因子在婚姻可能性,家庭成员数量上权重较大,定义为组建家庭因子
    #第四个因子在信用风险权重较大,定义为信用风险因子
    score1 = pd.DataFrame(np.dot(data[household],fa.comps['rot']))
    score1.columns=['长寿因子','经济状况因子','组建家庭因子','信用风险因子']
    #计算每个客户在各因子上的得分
    #聚类K值的选择
    #通过簇类离差平方和和silhouette_score系数确定最优的K值
    #轮廓系数允许容易造成内存不足,也可通过calinski_harabaz系数确定最优的K值
    cluster_plot(score1)
    #分类类别越多,簇类离差平方越大,一般选取下降趋势最大的时作为K值选取范围,K=4后下降趋势变为平缓
    #calinski_harabaz系数在K=2时最高,以后逐渐下降
    #结合这两点我们选取k=3
    model1 = KMeans(n_clusters=3,n_init=15)
    model1.fit(score1)
    score1['type'] = model1.labels_
    from pyecharts import Pie
    attr = ['群体1','群体2','群体3']
    v1 = score1.groupby('type').count().iloc[:,1]
    pie = Pie("各分类群体占比")
    pie.add("", attr, v1, is_label_show=True,radius=[20, 60])
    pie
    #各群体占比为较为理想的占比方式
    data_hb = score1.groupby('type').mean()
    data_hb
    
    聚类群体1 hb=0 经济状况较差,单身
    聚类群体2 hb=1 长寿,信用风险较高
    聚类群体3 hb=2 经济状况较好,有家有口

    将两个聚类结果放在一起解读,生成9个簇

    ana = df.groupby(['hh','hb']).mean()
    #便于解读变量转化为中文
    ana.columns = ['年龄','房屋价值','贷款比率','信用风险','已婚估计','运动偏爱','祖辈健在估计','偏爱节食','估计年龄','驾驶俱乐部估计','有否孩子','家庭成员人数','休闲兴趣广度']
    c_schema=[]
    for i in ana.columns:
        dict = {}
        dict['name'] = i
        dict['max'] = ana[i].values.max()
        dict['min'] = ana[i].values.min()
        c_schema.append(dict)
    radar = Radar()
    radar.config(c_schema=c_schema,shape='circle')
    for i in range(9):
        radar.add('群体%i'%(i+1),[ana.iloc[i].values.tolist()],is_area_show=True,area_opacity=0.6)
    radar
    

    群体1 经济状况较差,单身,偏爱健身,注重身材


    群体2 偏爱健身,注重身材,长寿,信用风险较高

    群体3 偏爱健身,注重身材,长寿经济状况较好,有家有口

    群体4 家里宅,经济状况较差,单身,低价值客户

    群体5 不愿意运动,长寿,信用风险较高

    群体6 不太爱运动,长寿经济状况较好,有家有口

    群体7 不太在意身形,偏向休闲娱乐,经济状况较差,单身

    群体8 不太在意身形,偏向休闲娱乐,长寿,信用风险较高

    群体9 不太在意身形,偏向休闲娱乐,经济状况较好,有家有口

    相关文章

      网友评论

          本文标题:Kmeans聚类 - 旅游企业客户洞察案例

          本文链接:https://www.haomeiwen.com/subject/ijiwrqtx.html