zoukankan      html  css  js  c++  java
  • [Python数据挖掘]第7章、航空公司客户价值分析

     一、背景和挖掘目标

    二、分析方法与过程

     客户价值识别最常用的是RFM模型(最近消费时间间隔Recency,消费频率Frequency,消费金额Monetary)

     

    1、EDA(探索性数据分析)

    #对数据进行基本的探索
    import pandas as pd
    
    data = pd.read_csv('data/air_data.csv', encoding = 'utf-8') #读取原始数据,指定UTF-8编码(需要用文本编辑器将数据装换为UTF-8编码)
    
    explore = data.describe(percentiles = [], include = 'all').T #包括对数据的基本描述,percentiles参数是指定计算多少的分位数表(如1/4分位数、中位数等);T是转置,转置后更方便查阅
    explore['null'] = len(data)-explore['count'] #describe()函数自动计算非空值数,需要手动计算空值数
    
    explore = explore[['null', 'max', 'min']]
    explore.columns = [u'空值数', u'最大值', u'最小值'] #表头重命名
    '''这里只选取部分探索结果。
    describe()函数自动计算的字段有count(非空值数)、unique(唯一值数)、top(频数最高者)、freq(最高频数)、mean(平均值)、std(方差)、min(最小值)、50%(中位数)、max(最大值)'''
    
    explore.to_excel('tmp/explore.xls') #导出结果

    2、数据预处理

    1.数据清洗

    data = data[data['SUM_YR_1'].notnull()&data['SUM_YR_2'].notnull()] #票价非空值才保留
    
    #只保留票价非零的,或者平均折扣率与总飞行公里数同时为0的记录。
    index1 = data['SUM_YR_1'] != 0
    index2 = data['SUM_YR_2'] != 0
    index3 = (data['SEG_KM_SUM'] == 0) & (data['avg_discount'] == 0) #该规则是“与”
    data = data[index1 | index2 | index3] #该规则是“或”

    票价为空表示该值缺失,票价为0表示飞这一趟没花钱,二者概念不同

    2.属性规约

    原始数据属性太多,根据之前提出的LRFMC模型,只保留6个与之相关的属性

     

    3.数据变换

     

    方法1:EXCEL手动操作(方便简单)

    data_select.to_excel('tmp/data_select.xls', index = False) #数据写入

    方法2:代码操作(方便新增信息的抽取)

    from datetime import datetime
    
    #使用匿名函数将LOAD_TIME数据转换成datetime格式,然后才能进行日期加减(匿名函数比for循环效率高)
    data_select['LOAD_TIME_convert'] = data_select['LOAD_TIME'].apply(lambda x: datetime.strptime(x, '%Y/%m/%d'))
    data_select['FFP_DATE_convert'] = data_select['FFP_DATE'].apply(lambda x: datetime.strptime(x, '%Y/%m/%d'))
    
    #构造一个Series序列接收  (LOAD_TIME-FFP_DATE)
    data_select['L']=pd.Series()
    
    #(LOAD_TIME-FFP_DATE)得到两个日期之间的天数间隔,然后除以30得到月份间隔          这一步相当费时
    for i in range(len(data_select)):
        data_select['L'][i] =(data_select['LOAD_TIME_convert'][i]-data_select['FFP_DATE_convert'][i]).days/30
    
    data_select = data_select.rename(columns = {'LAST_TO_END': 'R','FLIGHT_COUNT':'F','SEG_KM_SUM':'M','avg_discount':'C'})
    data_selected=data_select[['L','R','F','M','C']]
    data_selected

    接下来进行数据标准化

    #标准差标准化
    import pandas as pd
    
    data = pd.read_excel('data/zscoredata.xls', index = False) 
    data = (data - data.mean(axis = 0))/(data.std(axis = 0)) #简洁的语句实现了标准化变换,类似地可以实现任何想要的变换。
    data.columns=['Z'+i for i in data.columns] #表头重命名。
    
    data.to_excel('tmp/zscoreddata.xls', index = False) #数据写入

    3、模型构建

     1.客户聚类

    #K-Means聚类算法
    import pandas as pd
    from sklearn.cluster import KMeans #导入K均值聚类算法
    
    k = 5                       #需要进行的聚类类别数
    
    #读取数据并进行聚类分析
    data = pd.read_excel('data/zscoreddata.xls') 
    
    #调用k-means算法,进行聚类分析
    kmodel = KMeans(n_clusters = k, n_jobs = 4) #n_jobs是并行数,一般等于CPU数较好
    kmodel.fit(data) #训练模型
    
    # kmodel.cluster_centers_ #查看聚类中心
    # kmodel.labels_ #查看各样本对应的类别
    
    #简单打印结果
    s = pd.Series(['客户群1','客户群2','客户群3','客户群4','客户群5'], index=[0,1,2,3,4]) #创建一个序列s
    r1 = pd.Series(kmodel.labels_).value_counts() #统计各个类别的数目
    r2 = pd.DataFrame(kmodel.cluster_centers_) #找出聚类中心
    r = pd.concat([s,r1,r2], axis = 1) #横向连接(0是纵向),得到聚类中心对应的类别下的数目
    r.columns =[u'聚类名称'] +[u'聚类个数'] + list(data.columns) #重命名表头
    print(r)

    2.客户价值分析

    #雷达图代码摘自  https://blog.csdn.net/Just_youHG/article/details/83904618
    def plot_radar(data):
        '''
        the first column of the data is the cluster name;
        the second column is the number of each cluster;
        the last are those to describe the center of each cluster.
        '''
        kinds = data.iloc[:, 0]
        labels = data.iloc[:, 2:].columns
        centers = pd.concat([data.iloc[:, 2:], data.iloc[:,2]], axis=1)
        centers = np.array(centers)
        n = len(labels)
        angles = np.linspace(0, 2*np.pi, n, endpoint=False)
        angles = np.concatenate((angles, [angles[0]]))
        
        fig = plt.figure()
        ax = fig.add_subplot(111, polar=True) # 设置坐标为极坐标
        
        # 画若干个五边形
        floor = np.floor(centers.min())     # 大于最小值的最大整数
        ceil = np.ceil(centers.max())       # 小于最大值的最小整数
        for i in np.arange(floor, ceil + 0.5, 0.5):
            ax.plot(angles, [i] * (n + 1), '--', lw=0.5 , color='black')
        
        # 画不同客户群的分割线
        for i in range(n):
            ax.plot([angles[i], angles[i]], [floor, ceil], '--', lw=0.5, color='black')
        
        # 画不同的客户群所占的大小
        for i in range(len(kinds)):
            ax.plot(angles, centers[i], lw=2, label=kinds[i])
            #ax.fill(angles, centers[i])
        
        ax.set_thetagrids(angles * 180 / np.pi, labels) # 设置显示的角度,将弧度转换为角度
        plt.legend(loc='lower right', bbox_to_anchor=(1.5, 0.0)) # 设置图例的位置,在画布外
        
        ax.set_theta_zero_location('N')        # 设置极坐标的起点(即0°)在正北方向,即相当于坐标轴逆时针旋转90°
        ax.spines['polar'].set_visible(False)  # 不显示极坐标最外圈的圆
        ax.grid(False)                         # 不显示默认的分割线
        ax.set_yticks([])                      # 不显示坐标间隔
        
        plt.show()
    
    plot_radar(r)        #调用雷达图作图函数

    4、决策支持

     

    三、【拓展思考】客户流失分析

    1、目标

    2、数据预处理

    参考自https://blog.csdn.net/zhouchen1998/article/details/85113535

    import pandas as pd
    from datetime import datetime
    
    def clean(data):
        '''
        数据清洗,去除空记录
        '''
        data = data[data['SUM_YR_1'].notnull() & data['SUM_YR_2'].notnull()]  # 票价非空值才保留
    
        # 只保留票价非零的,或者平均折扣率与总飞行公里数同时为0的记录。
        index1 = data['SUM_YR_1'] != 0
        index2 = data['SUM_YR_2'] != 0
        index3 = (data['SEG_KM_SUM'] == 0) & (data['avg_discount'] == 0)  # 该规则是“与”
        data = data[index1 | index2 | index3]  # 该规则是“或”
    
        #取出需要的属性列
        data = data[['LOAD_TIME', 'FFP_DATE', 'LAST_TO_END', 'FLIGHT_COUNT', 'avg_discount', 'SEG_KM_SUM', 'LAST_TO_END',
                     'P1Y_Flight_Count', 'L1Y_Flight_Count']]
        return data
    
    def LRFMCK(data):
        '''
        经过计算得到我的指标数据
        '''
        # 其中K为标签标示用户类型
        data2 = pd.DataFrame(columns=['L', 'R', 'F', 'M', 'C', 'K'])
        time_list = []
        for i in range(len(data['LOAD_TIME'])):
            str1 = data['LOAD_TIME'][i].split('/')
            str2 = data['FFP_DATE'][i].split('/')
            temp = datetime(int(str1[0]), int(str1[1]), int(str1[2])) - datetime(int(str2[0]), int(str2[1]), int(str2[2]))
            time_list.append(temp.days)
        data2['L'] = pd.Series(time_list)
        data2['R'] = data['LAST_TO_END']
        data2['F'] = data['FLIGHT_COUNT']
        data2['M'] = data['SEG_KM_SUM']
        data2['C'] = data['avg_discount']
        temp = data['L1Y_Flight_Count'] / data['P1Y_Flight_Count']
        for i in range(len(temp)):
            if temp[i] >=0.9:
                # 未流失客户
                temp[i] = 'A'
            elif 0.5 < temp[i] < 0.9:
                # 准流失客户
                temp[i] = 'B'
            else:
                temp[i] = 'C'
        data2['K'] = temp
        data2.to_csv('data/data_changed.csv', encoding='utf-8')
    
    def standard():
        '''
        标准差标准化
        '''
        data = pd.read_csv('data/data_changed.csv', encoding='utf-8').iloc[:, 1:6]
        # 简洁的语句实现了标准化变换,类似地可以实现任何想要的变换
        data = (data - data.mean(axis=0)) / (data.std(axis=0))
        data.columns = ['Z' + i for i in data.columns]
        data2 = pd.read_csv('data/data_changed.csv', encoding='utf-8')
        data['K'] = data2['K']
        data.to_csv('data/data_standard.csv', index=False)
    
    if __name__ == '__main__':
        data = pd.read_csv('data/air.csv', encoding='utf-8', engine='python')
        data=clean(data)
        data.to_csv('data/data_filter.csv', index = False, encoding='utf-8')
        data = pd.read_csv('data/data_filter.csv', encoding='utf-8')   #不重新读取的话,调用LRFMCK会报错,我也不知道为什么
        LRFMCK(data)
        standard()

    不知道为什么,总是要反复写入文件和读取文件,不然会莫名其妙的报错。猜测可能是csv文件与xls文件不同导致

     

    3、模型构建

    import pandas as pd
    from sklearn import tree
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import confusion_matrix #导入混淆矩阵函数
    import pydotplus
    
    # 读取数据
    def getDataSet(fileName):
        data = pd.read_csv(fileName)
        dataSet = []
        for item in data.values:
            dataSet.append(list(item[:5]))
        label = list(data['K'])
        return dataSet, label
        
    # 作图评估
    def cm_plot(y, yp):
      cm = confusion_matrix(y, yp) #混淆矩阵
      plt.matshow(cm, cmap=plt.cm.Greens) #画混淆矩阵图,配色风格使用cm.Greens,更多风格请参考官网。
      plt.colorbar() #颜色标签
      for x in range(len(cm)): #数据标签
        for y in range(len(cm)):
          plt.annotate(cm[x,y], xy=(x, y), horizontalalignment='center', verticalalignment='center')  
      plt.ylabel('True label') #坐标轴标签
      plt.xlabel('Predicted label') #坐标轴标签
      return plt
    
    data, label = getDataSet('data/data_standard.csv')
    train_data, test_data, train_label, test_label = train_test_split(data, label, test_size=0.2)
    
    #使用决策树
    clf = tree.DecisionTreeClassifier(max_depth=5)
    clf = clf.fit(train_data, train_label)
    
    # 可视化
    dataLabels = ['ZL', 'ZR', 'ZF', 'ZM', 'ZC', ]
    data_list = []
    data_dict = {}
    for each_label in dataLabels:
        for each in data:
            data_list.append(each[dataLabels.index(each_label)])
        data_dict[each_label] = data_list
        data_list = []
    lenses_pd = pd.DataFrame(data_dict)
    #print(lenses_pd.keys())
    
    #画决策树的决策流程
    dot_data = StringIO()
    tree.export_graphviz(clf, out_file=dot_data, feature_names=lenses_pd.keys(),
                             class_names=clf.classes_, filled=True, rounded=True, special_characters=True)
    graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
    graph.write_pdf("tree.pdf")
    
    cm_plot(test_label, clf.predict(test_data)).show()

     

  • 相关阅读:
    数据结构>堆栈的使用 小强斋
    数据结构>图的存储结构 小强斋
    数据结构>图的基本术语 小强斋
    java使用JNDI 获取weblogic配置的数据源 连接数据库 小强斋
    java使用JNDI 获取weblogic配置的数据源 连接数据库 小强斋
    数据结构>队列 小强斋
    C++实现平方的安全方法(redis的实现)
    jmeter性能测试使用示例
    redis学习总结1
    java NIO使用示例
  • 原文地址:https://www.cnblogs.com/little-monkey/p/10472250.html
Copyright © 2011-2022 走看看