客戶價值識別最經常使用的是RFM模型(最近消費時間間隔Recency,消費頻率Frequency,消費金額Monetary)python
#對數據進行基本的探索 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') #導出結果
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表示飛這一趟沒花錢,兩者概念不一樣app
2.屬性規約編輯器
原始數據屬性太多,根據以前提出的LRFMC模型,只保留6個與之相關的屬性函數
3.數據變換編碼
方法1:EXCEL手動操做(方便簡單)spa
data_select.to_excel('tmp/data_select.xls', index = False) #數據寫入
方法2:代碼操做(方便新增信息的抽取).net
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
接下來進行數據標準化3d
#標準差標準化 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) #數據寫入
1.客戶聚類excel
#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) #調用雷達圖做圖函數
參考自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文件不一樣致使
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()