主頁 > 後端開發 > 電信用戶流失分析與預測

電信用戶流失分析與預測

2020-09-17 11:06:21 後端開發

@目錄

  • 一. 研究背景
  • 二. 分析結論與建議
  • 三. 任務與實作
  • 四. 資料集決議
  • 五. 資料分析套餐
    • 1.準備作業
      • 匯入相關的庫
      • 匯入資料集
    • 2.資料預處理
      • 型別轉換
      • 缺失值處理
      • 重復值處理
    • 3.查看流失情況
    • 4.類別特征的描述性分析
    • 5.連續型變數的分析
      • 差異檢驗-兩樣本t檢驗
      • 分箱離散化
    • 6.機器學習
      • 基模型的建立
      • 基模型的初始評分
      • 例外值處理
      • 資料標準化處理
      • 樣本不均衡處理&邏輯回歸
      • 網格交叉驗證&KNN
      • 決策樹
      • 流水線&樸素貝葉斯
      • 多層感知器
      • 模型得分總結

這是作者自己做的一個資料分析專案,閑暇時間陸陸續續耗時大約2周,通篇采用大量python原始碼撰寫,歡迎一起學習交流,提升自我,
我的CSDN地址:https://blog.csdn.net/weixin_46274061/article/details/107790605
轉載請標明出處,謝謝!
資料集下載地址:https://www.datafountain.cn/datasets/35guide

一. 研究背景

用戶流失預測在機器學習中算是一種比較典型的分類場景,做好用戶的流失預測可以降低營銷成本,留住用戶并且獲得更好的用戶體驗,在三大巨頭的瓜分下,做好營銷運營比重新獲取一個新用戶更節省成本,達到較好的運營回報,如果在傳統分類模式下,通常是通過人工對各個特征進行統計,然后分到合適的類別中,這樣不但會耗費大量的資源,且低效,

二. 分析結論與建議

  1. 增加套餐福利,解鎖更多權益,如贈送流量,免費看視頻,增設小游戲,貴族制度,
  2. 加強電話服務質量,設立評分反饋系統,及時跟蹤例外評分
  3. 加強光纖相關設施的建設,增強網路穩定性
  4. 鼓勵用戶開通各種服務,如在線安全,在線備份,設備保護,技術支持
  5. 增加充值返現,充值滿減,發放優惠券的方式,用戶消費達到一定金額解鎖特權
  6. 針對老年人建議贈送通話時長,提高活躍度
  7. 針對排名前十的職業根據相應的職業給予相應的優惠和福利,提高用戶的粘性,

三. 任務與實作

我們的任務在于:
1.分析出流失用戶有哪些顯著性特征?
2.找出哪些用戶容易流失?
具體實作內容包括:
能夠對資料進行資料預處理 包括缺失值,例外值,重復值
能夠描述性分析各個特征與流失用戶的占比是否顯著
能夠將連續型變數進行分箱離散化
能夠將離散型特征進行獨熱編碼
能夠建立基模型,將源資料進行標準化
能夠處理樣本不均衡
能夠熟練運用多種分類模型對電信用戶進行預測
分析模型有:邏輯回歸,KNN,樸素貝葉斯,決策樹,多層感知器,

四. 資料集決議

每行代表一個客戶,每列包含元資料列中描述的客戶屬性,
一共7043行資料,21個列,前20個為特征列,最后一個為研究物件,
1 customerID Integer :用戶ID
2 gender String:性別(Female or Male)
3 SeniorCitizen Integer: 老年人(1表示是,0表示不是)
4 Partner String:配偶(Yes or No)
5 Dependents String:家屬(Yes or No)
6 tenure Integer :職位(0~72,共73個職位)
7 PhoneService String:電話服務(Yes or No)
8 MultipleLines String:多線(Yes 、No or No phoneservice 三種)
9 InternetService String:互聯網服務(No, DSL數字網路,fiber optic光纖網路 三種)
10 OnlineSecurity String:在線安全(Yes,No,No internetserive 三種)
11 OnlineBackup String:在線備份(Yes,No,No internetserive 三種)
12 DeviceProtection String:設備保護(Yes,No,No internetserive 三種)
13 TechSupport String:技術支持(Yes,No,No internetserive 三種)
14 StreamingTV String:網路電視(Yes,No,No internetserive 三種)
15 StreamingMovies:網路電影 (Yes,No,No internetserive 三種)
16 Contract String:合同(Month-to-month,One year,Two year 三種)
17 PaperlessBilling String:賬單(Yes or No)
18 PaymentMethod String:付款方式(bank transfer,credit card,electronic check,mailed check 四種)
19 MonthlyCharges Integer :月費用
20 TotalCharges Integer :總費用
21 Churn String:流失(Yes or No)

五. 資料分析套餐

1.準備作業

本文資料源來自網上,資料源除了各大網站可以下載,還可以來自自家公司的資料庫,爬蟲等方式獲取,

匯入相關的庫

# 匯入庫 
import pandas as pd 
import numpy as np 
import matplotlib.pyplot as plt 
import seaborn as sns
import warnings
from matplotlib import font_manager
import time

sns.set(style="darkgrid", font_scale=1.2)
# plt.rcParams["font.family"] = "SimHei"
plt.rcParams['font.family'] = ['Arial Unicode MS']
plt.rcParams["axes.unicode_minus"] = False
my_font=font_manager.FontProperties(fname=
                                    '/System/Library/Fonts/PingFang.ttc',
                                    size=15)  
warnings.filterwarnings("ignore")

from scipy import stats #用于方差分析

# from sklearn.linear_model import LinearRegression  #線性回歸模型
from sklearn.model_selection import train_test_split #切分訓練集 測驗集
from sklearn.linear_model import LogisticRegression #邏輯回歸模型
from sklearn.metrics import classification_report #混淆矩陣打分
from sklearn.model_selection import GridSearchCV #網格交叉驗證
from imblearn.over_sampling import SMOTE,ADASYN # 引入SMOTE和ADASYN處理樣本不均衡
from collections import Counter #查看每個類別出現的次數
from sklearn.pipeline import Pipeline #引入流水線
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score # 評估指標 --正確率 精準率 召回率 F1調和平均值
from sklearn.neighbors import KNeighborsClassifier #KNN分類模型
from sklearn.preprocessing import StandardScaler, MinMaxScaler # StandardScaler:均值標準差標準化 # MinMaxScaler:最小最大值標準化
from sklearn.neural_network import MLPClassifier #多層感知器

匯入資料集

data = https://www.cnblogs.com/lverkou/p/pd.read_csv("WA_Fn-UseC_-Telco-Customer-Churn.csv")
print(data.shape)
data.sample(10)

在這里插入圖片描述

2.資料預處理

查看資料整體情況

data.info()

在這里插入圖片描述

型別轉換

我們發現TotalCharges本應該是float64型別,這里卻是object型別,那么需要轉換,

data['TotalCharges'].astype(np.float64)

會報錯 無法轉換,這里用到一個函式:DataFrame.convert_objects( convert_dates = True,convert_numeric = False,convert_timedeltas = True,copy = True )

data["TotalCharges"]=data["TotalCharges"].convert_objects(convert_numeric=True)
data['TotalCharges'].dtype

輸出:dtype('float64') ,轉換完成,

缺失值處理

data.isnull().sum(axis=0)


TotalCharges有11個缺失值,查看資料分布 再確定是洗掉還是填充

print(data["TotalCharges"].skew()) 
sns.distplot(data["TotalCharges"].dropna())

在這里插入圖片描述
結果大于0, 屬于右偏 ,當然 ,也能一眼從圖形看出,
缺失值的處理方式有:洗掉,中位數填充,均值填充,眾數填充,
右偏資料我們用中位數填充,兩種方式計算中位數,計算中位數時會剔除缺失值

data["TotalCharges"].median()
或者
np.median(data["TotalCharges"].dropna().values)

輸出為:1397.475

填充缺失值

data.fillna({"TotalCharges":data["TotalCharges"].median()},inplace=True)
data.isnull().sum(axis=0)

在這里插入圖片描述

重復值處理

如果有重復值:可直接洗掉


# data.drop_duplicates(inplace=True)
data.duplicated().sum()

輸出:0
說明沒有重復值

3.查看流失情況

整體流失情況 條形圖查看

Churn_value=https://www.cnblogs.com/lverkou/p/data["Churn"].value_counts()
display(Churn_value)
sns.countplot(x="Churn",data=https://www.cnblogs.com/lverkou/p/data)

在這里插入圖片描述
也可餅狀圖查看

size=Churn_value.values
label_list=Churn_value.index
color=["#009999","#FF7400"]
explode=[0,0.1]
plt.figure(figsize=(8,8),dpi=80)
patches,l_text,p_text=plt.pie(size,
                            explode=explode,
                            colors=color,
                            labels=label_list,
                            labeldistance=1.1,
                            autopct='%1.1f%%',   
                            shadow=True,
                            startangle=90,
                            pctdistance=0.6,
                            )  
plt.show()

在這里插入圖片描述

餅狀圖可以內部直接算出百分比,從圖中可以看出流失比例26.5%,占比較高,也處于樣本不均衡問題,后面可以采用過采樣來解決,過采樣相比欠采樣較穩定,

對于研究物件:Churn,我們用pandas中的map函式實作數字化處理,我們通常將關注的類別設為1,

data["Churn"]=data["Churn"].map({"Yes":1,"No":0})
data.head()

在這里插入圖片描述
可以看出已經成功的將Churn做了離散化處理,

4.類別特征的描述性分析

特征列主要分兩大陣容,類別變數和連續型變數,我們有兩種方式把他們分離出來,第一種是直接一個一個drop掉,第二種方法是采用pandas里面提供的判斷類別型別和數值型的方法,這里我們采用第二種方式,

data_columns=[]
for col in data.columns.drop(["customerID","Churn"]):
    # is_object_dtype:查看特征是否為類別型別,是的話往下執行;
    # is_numeric_dtype:查看類別是否是數值型別的,是的話就繼續往下
    if pd.api.types.is_object_dtype(data[col]):
        data_columns.append(col)
print(data_columns)
data_object_lens=len(data_columns)

plt.figure(figsize=(20,100))#,dpi=80)
for col,k in zip(data_columns,range(data_object_lens)):
    # 子圖第一列
    plt.subplot(data_object_lens,2,2*k+1)
    plt.title("Churn by "+col)
    t=sns.countplot(x=col,hue="Churn",data=https://www.cnblogs.com/lverkou/p/data) #內部可統計數量
    t.set_ylabel('數量')
    

    # 子圖第二列
    plt.subplot(data_object_lens,2,2*k+2)
    plt.title("Churn rate by "+col)
    #內部可計算均值 相當于所有1相加再除以總數就等于流失率
    sns.barplot(x=col,y="Churn",data=https://www.cnblogs.com/lverkou/p/data).set_ylabel("流失率") 
    # 分組計算流失率
    print(data.groupby(by=col)["Churn"].mean())


輸出如下:在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
從圖中可以看出:
gender性別對于流失占比分布較均衡,無顯著性差異;
Partner無配偶的流失率相對有配偶的流失率高13%;
Dependents無家屬相對有家屬的流失率高16%;
PhoneService有電話服務的用戶量非常巨大,流失率占到了接近三成;
MultipleLines多線業務對流失率無顯著性差異;
InternetService互聯網服務中fiber optic光纖網路用戶群體約占所有用戶的1/3,流失率占比卻超過了光纖用戶的40%;
OnlineSecurity無在線安全的用戶量不僅巨大,流失率也超過40%;
OnlineBackup無在線備份功能的用戶中,40%會流失;
DeviceProtection無設備保護的用戶比有保護的用戶流失率高17%;
TechSupport無技術支持的用戶中 有4成會流失;
StreamingTV網路電視的有無對流失率無顯著性差異;
Streaming網路電影的有無對流失率無顯著性差異;
Contract合同按月的用戶占比最多,其中,流失率達到了42%,一年簽的用戶中流失率只占1成,兩年簽的幾乎不會流失;
PaperlessBilling有賬單的用戶流失率高于無賬單的17%;
PaymentMethod付款方式中電子支票的用戶中,流失率快達到一半人數,

運營建議:

  1. 針對單身用戶和無家屬用戶,他們最大的相同點就是容易產生孤獨感,社交較薄弱,可以給這類人群增加套餐福利,如單身貴族等級制度,贈送流量刷劇看視頻,小游戲等方式可提高會員等級,達到一定等級解鎖新權益,讓用戶心理有賺到的感覺,
  2. 電話服務質量是否存在一定問題,客服人員服務態度是否親和,若沒有,定期做相關培訓,是否真實的幫助用戶解決了,設立電話服務后的評分反饋系統,若評分較低再次跟進直到真實的幫助到了用戶,
  3. 現在用戶很大部分愿意選擇用光纖,說明都有意識到它的快速便捷,但是真實情況是經常網路不穩定,所以可以加大力度對這方面設施設備的建設,
  4. 鼓勵用戶開通在線安全,在線備份,設備保護,技術支持,
  5. 有賬單和電子支票的用戶極大部分是對價格比價敏感,考慮到有的用戶經濟不獨立,比如學生,而且合同中按月支付容易流失極大可能是無法承擔費用造成的,我們可以采取鼓勵按年簽約,校園套餐,每月返現的方式,充值滿減,發放優惠券,消費達到一定金額提升會員等級解鎖特權,

除了以上特征,發現SeniorCitizen老年人和tenure職業還有遺漏,
對于老年人代碼分析如下:

plt.figure(figsize=(20,13))#,dpi=80)
plt.subplot(2,2,1)
sns.countplot(x="SeniorCitizen",hue="Churn",data=https://www.cnblogs.com/lverkou/p/data)

plt.subplot(2,2,2)
t=sns.barplot(x="SeniorCitizen",y="Churn",data=data)
t.set_ylabel("流失率")
t.set_title("老年人與流失率的關系")
print(data.groupby(by="SeniorCitizen")["Churn"].mean())

在這里插入圖片描述
老年人數量雖然占比不高,但是流失率卻高達41%,但是其他用戶都會向這個群體邁入,很多老年人只會用打電話這一功能,所以我們可以采取啟用親友電話卡系結,提高老年人群體的免費撥打時長,增加短信提示每月剩余通話時長,提高活躍度,

對于職業,代碼分析如下:

plt.figure(figsize=(100,40))
sns.countplot(x="tenure",hue="Churn",data=https://www.cnblogs.com/lverkou/p/data)

在這里插入圖片描述
職業中:不同的數字代表不同的職業,挑選出了流失率排前十的職業,

plt.figure(figsize=(100,20))
t=sns.barplot(x="tenure",y="Churn",data=https://www.cnblogs.com/lverkou/p/data)
t.set_title("不同職業與流失率的關系",size=100,color="#009999")
data.groupby(by="tenure")["Churn"].mean().sort_values(ascending=False).iloc[:10,]

在這里插入圖片描述
從兩個圖結合可以看出,不同職業跟流失率也會存在一定的關系,職業為’0‘的雖然人數少,但是流失率幾乎為0,職業為’1‘的人數不僅最多,流失率也超過了該職業的50%,流失率排名前十的職業分別為:1,2,5,4,3,7,10,9,15,6,
辦法建議:可以采取獎勵機制,

5.連續型變數的分析

連續型變數:MonthlyCharges(月消費)和TotalCharges(總消費)
從主觀上來看,用戶的消費價格都是比較敏感的,所有我們可以重點關注一下消費價格,
查看月消費和總消費的各分位數 資料分布情況:

data.loc[:,["MonthlyCharges","TotalCharges"]].describe()

在這里插入圖片描述
在7043條資料中,用戶月消費的平均水平在65元,中位數在70元,最小消費為18元,最大消費為118元;
總消費的的平均水平在2282元,中位數在1397元,最小消費為18元,最大消費為8684元,
其中,月消費的平均值比中位數略小,主要受極小值的影響;總消費的平均值高于中位數885元,主要受到一些極大值影響,

我們可以具體分別查看月消費,總消費各排名前十的用戶資訊,
首先查看月消費最低的10名用戶:

data.sort_values(by="MonthlyCharges",ascending=True).iloc[:10]

在這里插入圖片描述

查看月消費最大的10名用戶:

data.sort_values(by="MonthlyCharges",ascending=True).iloc[-10:]

在這里插入圖片描述

總消費最小的10名用戶:

data.sort_values(by="TotalCharges",ascending=True).iloc[:10]

在這里插入圖片描述

查看總消費最高的10名用戶:

data.sort_values(by="TotalCharges",ascending=True).iloc[-10:]

在這里插入圖片描述
高消費的明顯特征是他們都有這些服務的需求,不易流失;
低消費的明顯特征恰恰相反,他們沒有這些需求,猜測與養號有關,

用散點圖查看流失用戶整體分布

plt.figure(figsize=(20,8),dpi=80)
sns.scatterplot(x="MonthlyCharges",y="TotalCharges",color="g",data=https://www.cnblogs.com/lverkou/p/data[data["Churn"]==0])
sns.scatterplot(x="MonthlyCharges",y="TotalCharges",color="r",data=data[data["Churn"]==1])

在這里插入圖片描述
紅色代表流失用戶,從圖中可以看出流失用戶主要分布在總消費偏低以及月消費偏高的地方,

嘗試用條形的散點圖查看分布情況:

fig=plt.figure(figsize=(20,10),dpi=80)
# 子圖1
fig.add_subplot(2,2,1)
sns.stripplot(x="Churn",y="MonthlyCharges",data=https://www.cnblogs.com/lverkou/p/data)
plt.title('月消費與流失的關系',fontproperties=my_font,color='red')

# 子圖2
fig.add_subplot(2,2,2)
sns.stripplot(x="Churn",y="TotalCharges",data=https://www.cnblogs.com/lverkou/p/data )
plt.title("總消費與流失的關系")
plt.show()

在這里插入圖片描述
似乎不是很好看,哈哈~
蜂群圖:本來想展示一下蜂群圖查看分布情況,但是太丑了就略過,

條形圖:

fig=plt.figure(figsize=(20,10),dpi=80)
# 子圖1
fig.add_subplot(2,2,1)
# 分組計算流失與否的均值
display(data.groupby("Churn")["MonthlyCharges"].mean())
# barplot內部會自己求均值
sns.barplot(x="Churn",y="MonthlyCharges",data=https://www.cnblogs.com/lverkou/p/data)
# 圖中那條線代表總體均值所在的置信區間 默認為95%的置信度

# 子圖2
fig.add_subplot(2,2,2)
display(data.groupby("Churn")["TotalCharges"].mean())
sns.barplot(x="Churn",y="TotalCharges",data=data)
plt.show()

在這里插入圖片描述
樣本中流失用戶的月消費平均值為74元,未流失用戶的月消費均值為61元;流失用戶的總消費均值為1531元,未流失用戶的均值為2552元,

箱線圖:

fig=plt.figure(figsize=(20,10),dpi=80)
# 子圖1
fig.add_subplot(2,2,1)
sns.boxplot(x="Churn",y="MonthlyCharges",data=https://www.cnblogs.com/lverkou/p/data)

# 子圖2
fig.add_subplot(2,2,2)
sns.boxplot(x="Churn",y="TotalCharges",data=data)
plt.show()

在這里插入圖片描述
可以看出總消費中,流失用戶存在個別例外值,我們可以采取洗掉,視為缺失值處理,取對數轉換,邊界值替換等方式處理,

月消費的用戶流失資料:

data.groupby("Churn")["MonthlyCharges"].describe().T

在這里插入圖片描述
總消費的用戶流失資料:

data.groupby("Churn")["TotalCharges"].describe().T

在這里插入圖片描述
小提琴圖:

fig=plt.figure(figsize=(20,10),dpi=100)
# 子圖1
fig.add_subplot(2,2,1)
sns.violinplot(x="Churn",y="MonthlyCharges",data=https://www.cnblogs.com/lverkou/p/data)

# 子圖2
fig.add_subplot(2,2,2)
sns.violinplot(x="Churn",y="TotalCharges",data=data)

plt.show()

在這里插入圖片描述
從以上圖中可以看出樣本中, 對于月消費來說,月消費高的用戶似乎容易流失;對于總消費來說,總消費低的用戶似乎容易失去,

差異檢驗-兩樣本t檢驗

以上都是對于樣本的結論,那么對于總體來說,是否也符合上述規律呢還是說我們抽樣出來的只是湊巧總體并不是這樣分布的,那么我們需要差異檢驗來驗證上述結論
我們用兩樣本t檢驗,來查看流失用戶與未流失用戶對于消費來說,他們的均值差異是否顯著,

差異檢驗 --月消費 "MonthlyCharges"
原假設:流失用戶的月消費與未流失用戶的月消費均值是一致的
總共分位兩步
第一步 :方差齊性檢驗

churn_1=data[data["Churn"]==1]["MonthlyCharges"]
churn_0=data[data["Churn"]==0]["MonthlyCharges"]
# 進行方差齊性檢驗-levene檢驗, 為后續的兩樣本t檢驗服務, 方差一致就叫齊性
stats.levene(churn_0,churn_1)

在這里插入圖片描述
第二步: p值為1.026>=0.05,說明是支持原假設的方差是一致的,equal_var=True
進行兩樣本t檢驗-雙邊檢驗,方法用的是stats.ttest_ind,注意:兩樣本的方差相同與不相同,取得的結果是不同的,

r = stats.ttest_ind(churn_0,churn_1,equal_var=True)
print(r)

在這里插入圖片描述p值2.7>=0.05,支持原假設,所以我們還不能認為流失用戶的月均消費高于未流失的用戶,

同樣對于總消費,原假設:總消費均值都是一致的
第一步:方差齊性檢驗

churn_1=data[data["Churn"]==1]["TotalCharges"]
churn_0=data[data["Churn"]==0]["TotalCharges"]
stats.levene(churn_0,churn_1)

在這里插入圖片描述
第二步:P值為3.38>0.05,說明是支持原假設的方差是一致的,齊性的,equal_var=True

r = stats.ttest_ind(churn_1,churn_0,equal_var=True)
print(r)

在這里插入圖片描述
P值7.5>0.05,所以我們也不能認為總體的流失用戶的總均消費低于未流失的用戶,
下一步,劃分消費等級,

分箱離散化

定義消費等級 ,按照各分位數分為低消費 中低消費 中高消費 高消費

def charge_to_level(charge):
    if charge<=da.loc["25%"]:
        return "低消費"
    elif charge<=da.loc["50%"] and charge>da.loc["25%"]:
        return "中低消費"
    elif charge<=da.loc["75%"] and charge>da.loc["50%"]:
        return "中高消費"
    else:
        return "高消費"
da=data["MonthlyCharges"].describe()
data["level_MonthlyCharges"] = data["MonthlyCharges"].apply(charge_to_level)
da=data["TotalCharges"].describe()
data["level_TotalCharges"] = data["TotalCharges"].apply(charge_to_level)


display(data["level_MonthlyCharges"].value_counts())
data.sample(5)

在這里插入圖片描述
條形圖查看:

fig=plt.figure(figsize=(20,10),dpi=80)
# 子圖1
fig.add_subplot(2,2,1)
sns.countplot(x="level_MonthlyCharges",hue="Churn",data=https://www.cnblogs.com/lverkou/p/data,order=["低消費","中低消費","中高消費","高消費"])

# 子圖2
fig.add_subplot(2,2,2)
sns.countplot(x="level_TotalCharges",hue="Churn",data=data,order=["低消費","中低消費","中高消費","高消費"])
plt.show()

在這里插入圖片描述
可以看出對于月消費來說,流失用戶主要集中在中高消費以及高消費;對于總消費來說,流失用戶主要集中在低消費和中低消費中,那么我們可以對這部分用戶進行精細化運營以最大程度留住用戶,

6.機器學習

基模型的建立

將類別特征離散化處理之前,首先洗掉不需要離散化處理的特征,作者花了部分時間比較按照分位數分箱離散化和未分箱離散的資料預測得分,發現未分箱的效果好那么一點點,還有個原因是分箱的分界點的選擇,如果可以找到最合適的分界點,那么分箱離散化是一個相當不錯的選擇,這里就只演示未分箱的操作,
洗掉列MonthlyCharges,TotalCharges,Churn:

y=data["Churn"]
data.drop(['customerID','level_MonthlyCharges','level_TotalCharges',"Churn"],axis=1,inplace=True)
data.head()

![在這里插入圖片描述](https://img-blog.csdnimg.cn/20200805140515133.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NjI3NDA2MQ==,size_16,color_FFFFFF,t_70

使用pandas.get_dummies( )進行one-hot 獨熱編碼,

data_onehot=pd.get_dummies(data)
print(data_onehot.shape)
data_onehot.head()

在這里插入圖片描述
職業雖然已經是數字,但是在數字中他們有大小的關系,實際職業之間是沒有大小比較的,所以也需要進行獨熱編碼,

data_base=pd.get_dummies(data_onehot,columns=['tenure'])
print(data_base.sample(5))
data_base.info()

在這里插入圖片描述
進行獨熱編碼后占用的記憶體變少,因為獨熱編碼使用的是稀疏矩陣,

基模型的初始評分

x_train,x_test,y_train,y_test=train_test_split(data_base,y,test_size=0.25,random_state=0)
lr=LogisticRegression()
lr.fit(x_train,y_train)
print("訓練集:",lr.score(x_train,y_train))
print("測驗集:",lr.score(x_test,y_test))

y_hat = lr.predict(x_test)
# 測驗集的混淆矩陣得分值
print(classification_report(y_true=y_test, y_pred=y_hat)) 

在這里插入圖片描述
如果只查看正確率accuracy,分值還是蠻高的達到了0.79,但是我們更多關注的是流失用戶,所以我們的評估指標選擇f1-score調和平均值會更符合氣質,
f1分值為0.57,

例外值處理

我們從之前的箱線圖可以看出總消費中存在個別的極大值,那么我們現在需要處理一下,

# 從箱線圖可以看出只有總消費存在較大的例外值 先計算分位數 IQR
quartile = np.quantile(x_train[y_train==1]['TotalCharges'],[0.25, 0.75])
IQR = quartile[1] - quartile[0]
upper = quartile[1] + 1.5 * IQR
print("IQR:{},upper:{}".format(IQR,upper))
def func(x):
    if x >= upper:
        return upper
    else:
        return x 
x_train.loc[:,'TotalCharges'][y_train==1]= x_train.loc[:,'TotalCharges'][y_train==1].apply(lambda x: func(x))
# x_train['TotalCharges'][y_train==1]= x_train['TotalCharges'][y_train==1].apply(fun)
x_test['TotalCharges'][y_test==1]= x_test['TotalCharges'][y_test==1].apply(lambda x: func(x))

# 查看是否還存在例外值
print(x_train['TotalCharges'][y_train==1][x_train['TotalCharges']>upper])
print(x_test['TotalCharges'][y_test==1][x_test['TotalCharges']>upper])

在這里插入圖片描述
這里很重要的一點:我們替換例外值應該是從測驗集中計算出,而不要把測驗集的資料也作為標準來計算出例外值,不然這就毫無意義了,

使用箱線圖查看訓練集中是否還存在例外值

sns.boxplot(x="Churn",y="TotalCharges",data=https://www.cnblogs.com/lverkou/p/pd.concat([x_train,y_train],axis=1))

在這里插入圖片描述
使用箱線圖查看測驗集中是否還存在例外值

sns.boxplot(x="Churn",y="TotalCharges",data=https://www.cnblogs.com/lverkou/p/pd.concat([x_test,y_test],axis=1))

在這里插入圖片描述

資料標準化處理

雖然邏輯回歸中w可以調節由于資料量綱的不同造成的模型不準確,但像KNN這樣的模型就會受到量綱在數量級上的不同,從而影響計算距離,所以我們可以先統一進行資料的標準化處理,
資料標準化主要有:均值標準差標準化和最小最大值標準化,
這里兩種方式嘗試之后 這里采用均值標準差標準化:

from sklearn.preprocessing import StandardScaler, MinMaxScaler
# StandardScaler:均值標準差標準化
# MinMaxScaler:最小最大值標準化
scaler,desc=[StandardScaler()],["均值標準差標準化"]
# scaler,desc=[MinMaxScaler()],["最小最大值標準化"]

for s, d in zip(scaler, desc):
    # fit_transform:將訓練集和測驗集都進行標準化
    x_train.loc[:,['MonthlyCharges','TotalCharges']] = s.fit_transform(x_train.loc[:,['MonthlyCharges','TotalCharges']])
    x_test.loc[:,['MonthlyCharges','TotalCharges']] = s.transform(x_test.loc[:,['MonthlyCharges','TotalCharges']])
    # 再代入KNN回歸演算法里
    knn = KNeighborsClassifier(n_neighbors=3, weights="uniform")
    knn.fit(x_train, y_train) 
    y_hat=knn.predict(x_test)
    print(d, knn.score(x_test, y_test))
    print(classification_report(y_true=y_test, y_pred=y_hat))

在這里插入圖片描述
采用邏輯回歸查看標準化處理后的評分:

lr = LogisticRegression(multi_class="ovr", solver="liblinear")
lr.fit(x_train,y_train)
print("訓練集:",lr.score(x_train,y_train))
print("測驗集:",lr.score(x_test,y_test))
y_hat = lr.predict(x_test)
print(classification_report(y_true=y_test, y_pred=y_hat))

在這里插入圖片描述
f1調和平均值:0.58

樣本不均衡處理&邏輯回歸

未處理之前,跑出來的評分模型最高評分有0.60,處理之后有所提升,
處理樣本不均衡方法有升采樣(上采樣),降采樣(下采樣),升采樣的主要方法有SMOTE和ADASYN,降采樣不推薦因為樣本數量減少對模型是有不良影響的,
這里采用的是上采樣,SMOTE和ADASYN對比使用之后,采用SMOTE方法

seed=0
# 鄰居數量k測驗出來為10有較好的得分
smote=SMOTE(random_state=seed,k_neighbors=10) 
x_resample,y_resample=smote.fit_resample(x_train,y_train)
print(Counter(y_resample))
lr=LogisticRegression()
lr.fit(x_resample,y_resample)
y_hat=lr.predict(x_test)
print(classification_report(y_test,y_hat))
print(f1_score(y_test, y_hat))

在這里插入圖片描述
升采用之后類別的次數基本相同,達到樣本均衡的效果,分值提升到了0.61,

網格交叉驗證&KNN

param = {"n_neighbors": range(3,13),
         "weights": ["uniform", "distance"],
        }
gs = GridSearchCV(estimator=KNeighborsClassifier(), param_grid=param,
         cv=2, scoring="f1", n_jobs=-1, verbose=10)
gs.fit(x_resample, y_resample)
print(gs.best_params_)
y_hat = gs.best_estimator_.predict(x_test)
print(classification_report(y_test, y_hat))
# 最好的分值,訓練集的分值
print("分值:",gs.best_score_)
# 最好的超引陣列合,
print("超引陣列合:",gs.best_params_)
# 使用最好的超引數訓練好的模型,
print("模型:",gs.best_estimator_)
# {'n_neighbors': 12, 'weights': 'distance'} fi: 0.55

在這里插入圖片描述

決策樹

from sklearn.tree import DecisionTreeClassifier
param = {"criterion": ["gini", "entropy"],
         "max_depth": range(1,10)
         }
gs = GridSearchCV(estimator=DecisionTreeClassifier(), param_grid=param,
         cv=2, scoring="f1", n_jobs=-1, verbose=10)
gs.fit(x_resample, y_resample)
print(gs.best_params_)
y_hat = gs.best_estimator_.predict(x_test)
print(classification_report(y_test, y_hat))
# 最好的分值,
print("分值:",gs.best_score_)
# 最好的超引陣列合,
print("超引陣列合:",gs.best_params_)
# 使用最好的超引數訓練好的模型,
print("模型:",gs.best_estimator_)

在這里插入圖片描述

流水線&樸素貝葉斯

# 高斯樸素貝葉斯 伯努利樸素貝葉斯 多項式樸素貝葉斯  補充樸素貝葉斯
from sklearn.naive_bayes import GaussianNB, BernoulliNB, MultinomialNB, ComplementNB
from sklearn.pipeline import Pipeline

steps=[("model", None)]
pipe = Pipeline(steps=steps)
# ComplementNB(): 適用于樣本不均衡的情況
# param里面的模型也可是決策樹,KNN演算法,可自行調整
param = {"model": [GaussianNB(), BernoulliNB(), MultinomialNB(), ComplementNB()]}
# 因為是稠密矩陣,因此比較消耗記憶體空間,記憶體小的,這里建議改成少的并發數量,
gs = GridSearchCV(estimator=pipe, param_grid=param,
         cv=2, scoring="f1", n_jobs=-1, verbose=10)
gs.fit(x_train, y_train)
print(gs.best_params_)
y_hat = gs.best_estimator_.predict(x_test)
print(classification_report(y_test, y_hat))

在這里插入圖片描述

多層感知器

神經網路當中存在隱藏層
當神經網路只有一層就是我們的邏輯回歸

from sklearn.neural_network import MLPClassifier
# 這兒只畫了兩個隱藏層,第一個隱藏層5個神經元,第二個隱藏層4個神經元
# for i in range(1,5):
#     for j in range(5,7):
param = {"hidden_layer_sizes": [(5,), (4,)],
        }
gs = GridSearchCV(estimator=MLPClassifier(), param_grid=param,
        cv=2, scoring="f1", n_jobs=-1, verbose=10)
gs.fit(x_resample, y_resample)
print(gs.best_params_)
y_hat = gs.best_estimator_.predict(x_test)
print(classification_report(y_test, y_hat))
f1=f1_score(y_test, y_hat)

在這里插入圖片描述

模型得分總結

在經過了資料標準化,樣本不均衡處理之后,帶入多種模型中,雖然accuracy得分都差不多能達到0.8,但是我們的關注點在于流失用戶,所以評估指標采用f1,最后決策樹的得分最高為0.63,比初始0.57分有所提升,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/65148.html

標籤:Python

上一篇:論如何拯救程式員的發際線?程式員的事情當然要用編程解決啦

下一篇:面向物件編程之——封裝,裝飾器(property,classmethod,staticmethod)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more