【機器學習】k-means——航空用戶聚類分析案例


  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()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM