1 import pandas as pd 2 import numpy as np 3 from sklearn.cluster import KMeans 4 import matplotlib.pyplot as plt 5 6 7 def stand_sca(data): 8 """ 9 標准差標准化 10 :param data:原數據 11 :return: 標准差之后的數據 12 """ 13 data = (data - data.mean()) / data.std() 14 15 return data 16 17 18 def box_analysis(data): 19 """ 20 箱線圖分析去除異常值 21 :param data: 原數據---series 22 :return: bool數組 23 """ 24 # 上四分位數 25 qu = data.quantile(q=0.75) 26 # 下四分位數 27 ql = data.quantile(q=0.25) 28 # 計算四分位間距 29 iqr = qu - ql 30 31 # 上限 32 up = qu + 1.5 * iqr 33 # 下限 34 low = ql - 1.5 * iqr 35 36 bool_index = (data < up) & (data > low) 37 38 return bool_index 39 40 41 # 1、了解航空公司現狀以及 航空用戶的價值 42 # 6w+ 樣本 44個特征 ----> LRFMC 43 # 2、數據處理 44 # (1)缺失值處理 45 # 刪除法 46 # (2) 篩選相關特征---構建最終的特征 47 # LRFMC <----篩選出能夠構建這5個特征的相關特征 48 # (3)異常值處理 49 # 3sigma 原則 或者 box_analysis 50 # (4)標准化處理 51 # 標准差標准化 52 # 3、k-means實現航空用戶的聚類 53 # sklearn 54 # 4、結果展示 55 # 繪制雷達圖 56 # 5、輸出結論 57 # 營銷策略 58 59 def build_data(): 60 """ 61 構建原始數據 62 :return: 原始數據 63 """ 64 # 1、加載數據 65 air_data = pd.read_csv("./air_data.csv", encoding="ansi") 66 # print("air_data:\n", air_data) 67 # print("air_data 的列索引名稱:\n", air_data.columns) 68 69 return air_data 70 71 72 def deal_data(air_data): 73 """ 74 數據處理 75 :param air_data:原始數據 76 :return: 數據處理之后的結果 77 """ 78 # 2、數據清洗 79 # 缺失值、異常值 80 # 檢測缺失值 81 res_null = pd.isnull(air_data).sum() 82 # print("缺失值檢測結果:", res_null) 83 84 # 處理缺失值 85 # (1)丟棄票價為空的記錄 # SUM_YR_1 SUM_YR_2兩列 86 # ----可以理解保留票價不為空 87 bool_index_1 = air_data.loc[:, "SUM_YR_1"].notnull() 88 bool_index_2 = air_data.loc[:, "SUM_YR_2"].notnull() 89 # 個人認為 只有兩列票價都不為空,票價才不為空 90 bool_index = bool_index_1 & bool_index_2 91 air_data = air_data.loc[bool_index, :] 92 # (2)丟棄票價為0,折扣不為0,飛行里程 > 0 的數據--->丟棄航空公司沒有盈利的數據 93 # 保留盈利的數據 94 # 保留票價 > 0,折扣 > 0,飛行里程 > 0 95 # 個人認為只要有一列票價>0,票價就>0 96 bool_id_1 = air_data.loc[:, "SUM_YR_1"] > 0 97 bool_id_2 = air_data.loc[:, "SUM_YR_2"] > 0 98 99 # 折扣> 0 100 bool_id_3 = air_data.loc[:, "avg_discount"] > 0 101 102 # 飛行里程>0 103 bool_id_4 = air_data.loc[:, "SEG_KM_SUM"] > 0 104 105 bool_id = (bool_id_1 | bool_id_2) & bool_id_3 & bool_id_4 106 107 air_data = air_data.loc[bool_id, :] 108 109 res_null = pd.isnull(air_data).sum() 110 # print("缺失值檢測結果:", res_null) 111 112 # 先篩選特征 113 # LRFMC 114 # 篩選 入會時間、窗口結束時間、最后乘坐飛機距離窗口結束的時長,乘坐飛機次數、飛行里程、折扣系數 115 air_data = air_data.loc[:, ["FFP_DATE", "LOAD_TIME", "LAST_TO_END", "FLIGHT_COUNT", "SEG_KM_SUM", "avg_discount"]] 116 117 # 構建LRFMC五個特征 118 air_data.loc[:, "FFP_DATE"] = pd.to_datetime(air_data.loc[:, "FFP_DATE"]) 119 air_data.loc[:, "LOAD_TIME"] = pd.to_datetime(air_data.loc[:, "LOAD_TIME"]) 120 # 獲取時間差--單位是day 121 air_data.loc[:, "L_days"] = air_data.loc[:, "LOAD_TIME"] - air_data.loc[:, "FFP_DATE"] 122 # 獲取相差天數 的數值 123 air_data.loc[:, "L_days"] = [i.days for i in air_data.loc[:, "L_days"]] 124 # 獲取具體的月數--即L 125 air_data.loc[:, "L"] = np.ceil(air_data.loc[:, "L_days"] / 30) 126 # print(air_data.loc[:, "L"]) 127 # 構建R --- LAST_TO_END 這個時長應該是天數 128 # print(air_data.loc[:, "LAST_TO_END"]) 129 air_data.loc[:, "R"] = np.ceil(air_data.loc[:, "LAST_TO_END"] / 30) 130 # print("air_data.loc[:, "R"]:\n",air_data.loc[:, "R"]) 131 132 air_data.loc[:, "F"] = air_data.loc[:, "FLIGHT_COUNT"] 133 134 air_data.loc[:, "M"] = air_data.loc[:, "SEG_KM_SUM"] 135 136 air_data.loc[:, "C"] = air_data.loc[:, "avg_discount"] 137 138 air_data = air_data.iloc[:, -5:] 139 # print("最終的數據:\n", air_data) 140 141 # 異常值處理 142 for column in air_data.columns: 143 bool_ = box_analysis(air_data.loc[:, column]) 144 air_data = air_data.loc[bool_, :] 145 146 # 標准化數據 147 air_data = stand_sca(air_data) 148 149 print("標准化之后的數據:\n", air_data) 150 151 return air_data 152 153 154 def km_fit(air_data, k): 155 """ 156 k-means訓練數據,並進行用戶聚類 157 :param air_data: 數據 158 :param k: 聚類的類別數目 159 :return: 160 """ 161 # 1、創建算法實例 162 km = KMeans(n_clusters=k) 163 # 2、訓練數據 164 km.fit(air_data) 165 # 3、預測 166 y_predict = km.predict(air_data) 167 168 # 獲取聚類中心 169 center = km.cluster_centers_ 170 171 return y_predict, center 172 173 174 def show_res(center, feature_num): 175 """ 176 繪制雷達圖 177 :param center:聚類中心 178 :param feature_num: 特征的數量 179 :return: 180 """ 181 # 1、創建畫布 182 # 繪制雷達圖 需要用到極坐標 183 fig = plt.figure() 184 # 修改RC參數,來讓其支持中文 185 plt.rcParams['font.sans-serif'] = 'SimHei' 186 plt.rcParams['axes.unicode_minus'] = False 187 # polar 開啟極坐標 188 fig.add_subplot(1, 1, 1, polar=True) 189 # 2、繪圖 190 # 准備數據 191 # 准備角度數據 192 angle = np.linspace(start=0, stop=2 * np.pi, num=feature_num, endpoint=False) 193 print(angle) 194 # 閉合角度 195 angle = np.concatenate((angle, [angle[0]])) 196 # print(angle) 197 for i in range(center.shape[0]): 198 # print(center[i, 0]) 199 # 閉合數據 200 data = np.concatenate((center[i, :],[center[i, 0]])) 201 plt.polar(angle, data) 202 203 # 設置刻度 204 plt.xticks(angle[:-1],["L","R","F","M","C"]) 205 206 # 增加圖例 207 plt.legend(["第一類用戶","第二類用戶","第三類用戶","第四類用戶","第五類用戶"]) 208 # 保存圖片 209 plt.savefig("./航空用戶聚類分析結果雷達圖展示.png") 210 # 3、展示 211 plt.show() 212 213 214 def main(): 215 """ 216 主函數 217 :return: 218 """ 219 # 1、構建原始數據 220 air_data = build_data() 221 # 2、數據處理 222 air_data = deal_data(air_data) 223 # 3、構建聚類模型進行用戶聚類 224 # 確定聚類的類別數目 225 k = 5 226 y_predict, center = km_fit(air_data, k) 227 print("預測值為:\n", y_predict) 228 print("聚類中心為:\n", center) 229 230 # 4、結果展示 231 show_res(center, center.shape[1]) 232 233 234 if __name__ == '__main__': 235 main()