一、導(dǎo)入關(guān)鍵包
# 導(dǎo)入數(shù)據(jù)分析需要的包
import pandas as pd
import numpy as np
# 可視化包
import seaborn as sns
sns.set(style="whitegrid")
import matplotlib.pyplot as plt
%matplotlib inline
# 忽略警告信息
import warnings
warnings.filterwarnings('ignore')
# 導(dǎo)入數(shù)據(jù)分析需要的包
import pandas as pd
import numpy as np
from datetime import datetime
# 構(gòu)建多個(gè)分類器
from sklearn.impute import KNNImputer
from sklearn.ensemble import RandomForestClassifier # 隨機(jī)森林
from sklearn.svm import SVC, LinearSVC # 支持向量機(jī)
from sklearn.linear_model import LogisticRegression # 邏輯回歸
from sklearn.neighbors import KNeighborsClassifier # KNN算法
from sklearn.naive_bayes import GaussianNB # 樸素貝葉斯
from sklearn.tree import DecisionTreeClassifier # 決策樹(shù)分類器
from xgboost import XGBClassifier
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import precision_score, recall_score, f1_score
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import GridSearchCV # 網(wǎng)格搜索
np.set_printoptions(suppress=True)
# 顯示中文
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
二、如何載入、分析和保存文件
df=pd.read_csv('data/dataset.csv')
df.head(5)# 查看前幾列數(shù)據(jù)
df.tail() # 返回CSV文件的最后幾行數(shù)據(jù)。
df.info() # 顯示CSV文件的基本信息,包括數(shù)據(jù)類型、列數(shù)、行數(shù)、缺失值等。
df.describe()# 對(duì)CSV文件的數(shù)值型數(shù)據(jù)進(jìn)行統(tǒng)計(jì)描述,包括計(jì)數(shù)、均值、標(biāo)準(zhǔn)差、最小值、最大值等。
df.shape()# 返回CSV文件的行數(shù)和列數(shù)。
df['IS_WX'].unique() # 返回CSV文件中某一列的唯一值。
df.value_counts()# 計(jì)算CSV文件中某一列中每個(gè)值的出現(xiàn)次數(shù)。
df.groupby('col1')['col2'] # 按照某一列的值進(jìn)行分組,并對(duì)其他列進(jìn)行聚合操作,如求和、計(jì)數(shù)、平均值等。
df.sort_values(by='col1') # 按照某一列的值進(jìn)行排序。
df.pivot_table(values='C', index='A', columns='B', aggfunc='mean')# 創(chuàng)建透視表,根據(jù)指定的行和列對(duì)數(shù)據(jù)進(jìn)行匯總和分析。
# 保存處理后的數(shù)據(jù)集
df.to_csv('data/Telecom_data_flag.csv')
三、修改缺失值
3.1 查看缺失值
# 計(jì)算每列的缺失值數(shù)量
missing_values = df.isnull().sum()
# 繪制柱狀圖
plt.figure(figsize=(10, 6))
missing_values.plot(kind='bar')
plt.xlabel('Columns')
plt.ylabel('Missing Values Count')
plt.title('Missing Values in DataFrame')
plt.xticks(rotation=90)
plt.show()
3.1 眾數(shù)
# 對(duì)每一列屬性采用相應(yīng)的缺失值處理方式,通過(guò)分析發(fā)現(xiàn)這類數(shù)據(jù)都可以采用眾數(shù)的方式解決
df.isnull().sum()
modes = df.mode().iloc[0]
print(modes)
df = df.fillna(modes)
print(df.isnull().sum())
3.2 平均值
mean_values = df.mean()
print(mean_values)
df = df.fillna(mean_values)
print(df.isnull().sum())
3.3 中位數(shù)
median_values = df.median()
print(median_values)
df = df.fillna(median_values)
print(df.isnull().sum())
3.4 0填充
df = df.fillna(0)
print(df.isnull().sum())
3.5 KNN填充
KNNImputer的默認(rèn)算法是基于K最近鄰算法來(lái)填充缺失值。具體步驟如下:
- 對(duì)于每個(gè)缺失值,找到其最近的K個(gè)鄰居樣本。
- 使用這K個(gè)鄰居樣本的非缺失值來(lái)計(jì)算缺失值的近似值??梢允褂镁?、中位數(shù)或加權(quán)平均值等方法來(lái)計(jì)算近似值。
- 將計(jì)算得到的近似值填充到缺失值的位置。
- KNNImputer中的K值可以通過(guò)設(shè)置n_neighbors參數(shù)來(lái)指定,默認(rèn)值為5。你也可以通過(guò)設(shè)置weights參數(shù)來(lái)選擇不同的權(quán)重方式來(lái)計(jì)算近似值,默認(rèn)為uniform,即所有鄰居樣本具有相同的權(quán)重。
# 導(dǎo)入數(shù)據(jù)集 'SERV_ID', ,"ACCT_MONTH"
df=pd.read_csv('data/dataset.csv')
# 查看數(shù)據(jù)
df.head(5)
# 定義 knnimputer
imputer = KNNImputer()
# 填充數(shù)據(jù)集中的空值
imputer.fit(df)
# 轉(zhuǎn)換數(shù)據(jù)集
Xtrans = imputer.transform(df)
# 打印轉(zhuǎn)化后的數(shù)據(jù)集的空值
print('KNNImputer after Missing: %d' % sum(np.isnan(Xtrans).flatten()))
df_filled = pd.DataFrame(Xtrans, columns=df.columns)
四、修改異常值
4.1 刪除
1.刪除DataFrame表中全部為NaN的行
your_dataframe.dropna(axis=0,how='all')
2.刪除DataFrame表中全部為NaN的列
your_dataframe.dropna(axis=1,how='all')
3.刪除表中含有任何NaN的行
your_dataframe.dropna(axis=0,how='any')
4.刪除表中含有任何NaN的列
your_dataframe.dropna(axis=1,how='any')
4.2 替換
這里的替換可以參考前文的中位數(shù),平均值,眾數(shù),0替換等。
replace_value = 0.0
# 這里設(shè)置 inplace 為 True,能夠直接把表中的 NaN 值替換掉
your_dataframe.fillna(replace_value, inplace=True)
# 如果不設(shè)置 inplace,則這樣寫就行
# new_dataframe = your_dataframe.fillna(replace_value)
4.3 3σ原則
3σ原則,也稱為三倍標(biāo)準(zhǔn)差原則,是統(tǒng)計(jì)學(xué)中一種常用的質(zhì)量管理方法,用于判斷數(shù)據(jù)是否偏離正常分布。其目標(biāo)是通過(guò)計(jì)算數(shù)據(jù)的均值和標(biāo)準(zhǔn)差,確定異常值的存在,并將其排除或處理。也就是將連續(xù)型變量劃入下圖所示的八個(gè)區(qū)間中,完成離散化處理。以下是3σ原則的原理和步驟:
原理:
- 假設(shè)數(shù)據(jù)集服從正態(tài)分布,根據(jù)正態(tài)分布的性質(zhì),大部分?jǐn)?shù)據(jù)集中在均值附近,而異常值遠(yuǎn)離均值。
根據(jù)3σ原則,大約68%的數(shù)據(jù)集中在均值的±1個(gè)標(biāo)準(zhǔn)差范圍內(nèi),約95%的數(shù)據(jù)集中在均值的±2個(gè)標(biāo)準(zhǔn)差范圍內(nèi),約99.7%的數(shù)據(jù)集中在均值的±3個(gè)標(biāo)準(zhǔn)差范圍內(nèi)。
步驟:
- 計(jì)算數(shù)據(jù)集的均值(μ)和標(biāo)準(zhǔn)差(σ)。
- 根據(jù)3σ原則,確定異常值的閾值范圍。通常將均值加減3倍標(biāo)準(zhǔn)差作為閾值范圍,即 μ±3σ。
- 遍歷數(shù)據(jù)集,將落在閾值范圍外的數(shù)據(jù)點(diǎn)標(biāo)記為異常值。
- 根據(jù)業(yè)務(wù)需求,對(duì)異常值進(jìn)行處理,可以選擇刪除、替換或其他處理方式。
- 重新分析處理后的數(shù)據(jù)集,確保異常值的影響被消除。
需要注意的是,3σ原則僅適用于符合正態(tài)分布假設(shè)的數(shù)據(jù)集。對(duì)于非正態(tài)分布的數(shù)據(jù),可以考慮使用其他方法進(jìn)行異常值檢測(cè)和處理,如箱線圖、Z分?jǐn)?shù)等。
代碼實(shí)現(xiàn):
import pandas as pd
import numpy as np
def three_sigma(Ser):
rule = (Ser.mean()-3*Ser.std()>Ser1) | (Ser.mean()+3*Ser.std()< Ser)
index = np.arange(Ser1.shape[0])[rule]
outrange = Ser.iloc[index]
return outrange
4.4 箱型圖
箱型圖(Boxplot)也稱箱須圖(Box-whisker Plot)、盒式圖或箱線圖,是利用數(shù)據(jù)中的五個(gè)統(tǒng)計(jì)量:最小值、上四分位數(shù)、中位數(shù)、下四分位數(shù)與最大值來(lái)描述數(shù)據(jù)的一種統(tǒng)計(jì)圖。它能夠直觀地顯示數(shù)據(jù)的異常值,分布的離散程度以及數(shù)據(jù)的對(duì)稱性。
中位數(shù):數(shù)據(jù)按從小到大順序排列后的處于中間位置的值,如果序列是偶數(shù)個(gè),則是中間兩個(gè)數(shù)的平均值;
下四分位數(shù)Q1:位于數(shù)據(jù)序列25%位置處的數(shù);
上四分位數(shù)Q3:位于數(shù)據(jù)序列75%位置處的數(shù);
四分位間距IQR:即 IQR = Q3-Q1;
下邊緣:= Q1 – 1.5 *IQR;
上邊緣:= Q3 + 1.5 *IQR;
代碼實(shí)現(xiàn):
def box_plot(index):
# 使用自帶的樣式美化圖片
plt.style.use('ggplot')
# 設(shè)置中文和負(fù)號(hào)正常顯示
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
# 繪圖:年齡箱線圖
plt.boxplot(x = df[index], # 指定繪圖數(shù)據(jù)
whis=1.5,#1.5倍的四分位值
patch_artist=True, # 要求用自定義顏色填充盒形圖,默認(rèn)白色填充
showmeans=True, # 以點(diǎn)的形式顯示均值
boxprops = {'color':'black','facecolor':'#9999ff'}, # 設(shè)置箱體屬性,填充色和邊框色
flierprops = {'marker':'o','markerfacecolor':'red','color':'black'}, # 設(shè)置異常值屬性,點(diǎn)的形狀、填充色和邊框色
meanprops = {'marker':'D','markerfacecolor':'indianred'}, # 設(shè)置均值點(diǎn)的屬性,點(diǎn)的形狀、填充色
medianprops = {'linestyle':'--','color':'orange'}) # 設(shè)置中位數(shù)線的屬性,線的類型和顏色
# 設(shè)置y軸的范圍
plt.ylim(0,85)
# 去除箱線圖的上邊框與右邊框的刻度標(biāo)簽
plt.tick_params(top='off', right='off')
# 顯示圖形
plt.show()
# 導(dǎo)入數(shù)據(jù)集
df=pd.read_csv('data/dataset.csv')
# 查看數(shù)據(jù)
df.head(5)
numeric_cols=['ONLINE_LEN', 'SERV_ID_COUNT', 'CMPLNT_NUM', 'BANK_NUM','STOP_COUNT','CMPLNT_NUM'] #給出數(shù)值型特征的列名
for numeric_col in numeric_cols:
box_plot(numeric_col)
異常值處理:
對(duì)給定的某列Series進(jìn)行異常值檢測(cè),并用不包括異常值的剩余數(shù)據(jù)的均值替換(Ser:進(jìn)行異常值分析的DataFrame的某一列)
#定義箱線圖識(shí)別異常值函數(shù)
def box_mean(Ser,Low=None,Up=None):
if Low is None:
Low=Ser.quantile(0.25)-1.5*(Ser.quantile(0.75)-Ser.quantile(0.25))
if Up is None:
Up=Ser.quantile(0.75)+1.5*(Ser.quantile(0.75)-Ser.quantile(0.25))
Ser2=Ser[(Ser>=Low) & (Ser<=Up)] #取出不包含異常點(diǎn)的數(shù)據(jù),為了求均值
Ser[(Ser<Low) | (Ser>Up)]=Ser2.mean() #用非空且非異常數(shù)據(jù)的那些數(shù)據(jù)的均值替換異常值
return(Ser)
cols=['ONLINE_LEN', 'SERV_ID_COUNT', 'CMPLNT_NUM', 'BANK_NUM','STOP_COUNT','CMPLNT_NUM'] #給出數(shù)值型特征的列名
for col_name in cols:
data[col_name]=box_mean(data[col_name])
五、數(shù)據(jù)繪圖分析
5.1 餅狀圖
5.1.1 繪制某一特征的數(shù)值情況(二分類)
# 查看總體客戶流失情況
churnvalue = df["LEAVE_FLAG"].value_counts()
labels = df["LEAVE_FLAG"].value_counts().index
plt.pie(churnvalue,
labels=["未流失","流失"],
explode=(0.1,0),
autopct='%.2f%%',
shadow=True,)
plt.title("客戶流失率比例",size=24)
plt.show()
# 從餅形圖中看出,流失客戶占總客戶數(shù)的很小的比例,流失率達(dá)3.58%
5.2 柱狀圖
5.2.1 單特征與目標(biāo)特征之間的圖像
# 粘性/忠誠(chéng)度分析 包括綁定銀行卡張數(shù)
fig, axes = plt.subplots(1, 1, figsize=(12,12))
plt.subplot(1,1,1)
# palette參數(shù)表示設(shè)置顏色
gender=sns.countplot(x='BANK_NUM',hue="LEAVE_FLAG",data=df,palette="Pastel2")
plt.xlabel("綁定銀行卡張數(shù)",fontsize=16)
plt.title("LEAVE_FLAG by BANK_NUM",fontsize=18)
plt.ylabel('count',fontsize=16)
plt.tick_params(labelsize=12) # 設(shè)置坐標(biāo)軸字體大小
# 從此表可知,對(duì)于沒(méi)有綁定銀行卡的用戶流失情況會(huì)更大,應(yīng)該加強(qiáng)督促用戶綁定銀行卡
# 查看正常用戶與流失用戶在上網(wǎng)流量上的差別
plt.figure(figsize=(10,6))
g = sns.FacetGrid(data = df,hue = 'LEAVE_FLAG', height=4, aspect=3)
g.map(sns.distplot,'BYTE_ALL',norm_hist=True)
g.add_legend()
plt.ylabel('density',fontsize=16)
plt.xlabel('BYTE_ALL',fontsize=16)
plt.xlim(0, 100)
plt.tick_params(labelsize=13) # 設(shè)置坐標(biāo)軸字體大小
plt.tight_layout()
plt.show()
# 從上圖看出,上網(wǎng)流量少的用戶流失率相對(duì)較高。
5.2.2 多特征與目標(biāo)特征之間的圖像
這里繪制的多個(gè)二分類特征的情況是與目標(biāo)特征之間的關(guān)系
# 粘性/忠誠(chéng)度分析 包括是否捆綁微信、是否捆綁支付寶
# sns.countplot()函數(shù)繪制了"是否使用支付寶"(IS_ZFB)這一列的柱狀圖,并根據(jù)"LEAVE_FLAG"(是否離網(wǎng))進(jìn)行了顏色分類。
fig, axes = plt.subplots(1, 2, figsize=(12,12))
plt.subplot(1,2,1)
# palette參數(shù)表示設(shè)置顏色
partner=sns.countplot(x="IS_ZFB",hue="LEAVE_FLAG",data=df,palette="Pastel2")
plt.xlabel("是否使用支付寶(1代表使用,0代表使用)")
plt.title("LEAVE_FLAG by IS_ZFB",fontsize=18)
plt.ylabel('count',fontsize=16)
plt.tick_params(labelsize=12) # 設(shè)置坐標(biāo)軸字體大小
plt.subplot(1,2,2)
seniorcitizen=sns.countplot(x="IS_WX",hue="LEAVE_FLAG",data=df,palette="Pastel2")
plt.xlabel("是否使用微信(1代表使用,0代表使用)")
plt.title("LEAVE_FLAG by IS_WX",fontsize=18)
plt.ylabel('count',fontsize=16)
plt.tick_params(labelsize=12) # 設(shè)置坐標(biāo)軸字體大小
# 從此表可知 支付寶綁定目前對(duì)于用戶流失沒(méi)有影響,微信的綁定影響會(huì)稍微大點(diǎn),可能是微信用戶用的較多
# 異常性 根據(jù)用戶流失情況來(lái)結(jié)合判定
covariables=["CMPLNT_NUM", "STOP_COUNT"]
fig,axes=plt.subplots(1,2,figsize=(20,12))
for i, item in enumerate(covariables):
'''
0,'CMPLNT_NUM'
1,'STOP_COUNT'
'''
plt.subplot(1,2,(i+1))
ax=sns.countplot(x=item,hue="LEAVE_FLAG",data=df,palette="Set2")
plt.xlabel(str(item),fontsize=16)
plt.tick_params(labelsize=14) # 設(shè)置坐標(biāo)軸字體大小
plt.title("LEAVE_FLAG by "+ str(item),fontsize=20)
i=i+1
plt.tight_layout()
plt.show()
# 從此表可知 最近6個(gè)月累計(jì)投訴次數(shù)間接性的決定了用戶的流失,停機(jī)天數(shù)也和用戶流失成正相關(guān)。
5.2.3 單特征的數(shù)值分布
plt.hist(df["policy_code"], bins=10) # 設(shè)置直方圖的箱數(shù)
plt.xlabel("policy_code")
plt.ylabel("Frequency")
plt.title("Distribution of policy_code" )
plt.show()
5.3 折線圖
5.3.1 多個(gè)特征之間的關(guān)系圖
# 用戶的成長(zhǎng)性分析,結(jié)合用戶流失情況。
# 包括流量趨勢(shì)、語(yǔ)音通話次數(shù)趨勢(shì)、語(yǔ)音通話時(shí)長(zhǎng)趨勢(shì)、交往圈趨勢(shì)
# 提取特征數(shù)據(jù)列
feature1 = df["LIULIANG_B"]
feature2 = df["YUYING_COUNT"]
feature3 = df["YUYING_B"]
feature4 = df["JIAOWANG_B"]
# 繪制折線圖
plt.plot(feature1, label="LIULIANG_B")
plt.plot(feature2, label="YUYING_COUNT")
plt.plot(feature3, label="YUYING_B")
plt.plot(feature4, label="JIAOWANG_B")
# 添加標(biāo)題和標(biāo)簽
plt.title("Trend of User growth")
plt.xlabel("Index")
plt.ylabel("Value")
# 添加圖例
plt.legend()
# 顯示圖表
plt.show()
# 從此圖可以發(fā)現(xiàn)針對(duì)流量趨勢(shì)來(lái)說(shuō),用戶的波動(dòng)是最大的。
5.4 散點(diǎn)圖
df.plot(x="SERV_ID_COUNT", y="CDR_NUM", kind="scatter", c="red")
plt.show()
這段代碼的作用是繪制一個(gè)以"SERV_ID_COUNT"為橫軸,"CDR_NUM"為縱軸的散點(diǎn)圖,并將散點(diǎn)的顏色設(shè)置為紅色。通過(guò)這個(gè)散點(diǎn)圖,可以直觀地觀察到"SERV_ID_COUNT"和"CDR_NUM"之間的關(guān)系。
5.5 繪圖工具
工具一:只需要傳入一個(gè)list列表,name表示繪圖目標(biāo)的名稱(如損失圖則為loss),color_index表示想要用哪一種顏色來(lái)繪圖,save_path表示圖片保存的位置
def plot_loss_curve(llist, name,color_index, save_path=None):
colors = ["#0000ff",'#e4007f']
plt.figure(figsize=(10, 5))
freqs = [i for i in range(1, len(llist) + 1)]
# 繪制訓(xùn)練損失變化曲線
plt.plot(freqs, llist, color=colors[color_index], label="Train {}".format(name))
# 繪制坐標(biāo)軸和圖例
plt.ylabel("{}".format(name), fontsize='large')
plt.xlabel("epoch", fontsize='large')
plt.legend(loc='upper right', fontsize='x-large')
plt.show()
# plt.savefig("train_{}_curve.png".format(name))
六、特征選擇
6.1、相關(guān)性分析
6.1.1 皮爾遜相關(guān)系數(shù)
plt.figure(figsize=(16,8))
df.corr()['LEAVE_FLAG'].sort_values(ascending = False).plot(kind='bar')
plt.tick_params(labelsize=14) # 設(shè)置坐標(biāo)軸字體大小
plt.xticks(rotation=45) # 設(shè)置x軸文字轉(zhuǎn)向
plt.title("Correlations between LEAVE_FLAG and variables",fontsize=20)
plt.show()
# 從圖可以直觀看出,YUYING_COUNT 、YUYING_B、IS_ZFB、BALANCE、JIAOWANG_B、IS_WX這六個(gè)變量與LEAVE_FLAG目標(biāo)變量相關(guān)性最弱。
6.1.2 斯皮爾曼相關(guān)系數(shù)
plt.figure(figsize=(16,8))
df.corr(method='spearman')['LEAVE_FLAG'].sort_values(ascending = False).plot(kind='bar')
plt.tick_params(labelsize=14) # 設(shè)置坐標(biāo)軸字體大小
plt.xticks(rotation=45) # 設(shè)置x軸文字轉(zhuǎn)向
plt.title("Correlations between LEAVE_FLAG and variables",fontsize=20)
plt.show()
6.1.3 肯德?tīng)栂嚓P(guān)系數(shù)
plt.figure(figsize=(16,8))
df.corr(method='kendall')['LEAVE_FLAG'].sort_values(ascending = False).plot(kind='bar')
plt.tick_params(labelsize=14) # 設(shè)置坐標(biāo)軸字體大小
plt.xticks(rotation=45) # 設(shè)置x軸文字轉(zhuǎn)向
plt.title("Correlations between LEAVE_FLAG and variables",fontsize=20)
plt.show()
6.1.4 計(jì)算熱力圖
# 計(jì)算相關(guān)性矩陣
corr_matrix = df.corr()
# 繪制熱力圖
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, cmap="coolwarm")
plt.title("Correlation Heatmap", fontsize=16)
plt.show()
6.2 主成分分析
PCA思想:構(gòu)造原變量的一系列線性組合形成幾個(gè)綜合指標(biāo),以去除數(shù)據(jù)的相關(guān)性,并使低維數(shù)據(jù)最大程度保持原始高維數(shù)據(jù)的方差信息
一般來(lái)說(shuō)在進(jìn)行數(shù)據(jù)降維之前,需要先對(duì)其做歸一化
from sklearn import preprocessing
from sklearn.decomposition import PCA
X_scaled = preprocessing. scale(X)
pca = PCA(n_components=6) # 加載PCA算法,設(shè)置降維后主成分?jǐn)?shù)目為2
# n_components的值不能大于n_features(特征數(shù))和n_classes(類別數(shù))之間的較小值減1。
reduced_x = pca.fit_transform(normalized_data) # 對(duì)樣本進(jìn)行降維
reduced_x = pd.DataFrame(reduced_x, columns = ['pca_1','pca_2','pca_3','pca_4','pca_5','pca_6'])
reduced_x.head()
reduced_x.head()的結(jié)果
PCA代碼:
# -*- coding:utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn.decomposition import PCA # 加載PCA算法包
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn import svm
import pandas as pd
df = pd.read_csv(r'D:\Python\test\iris.csv')
X = df.iloc[:, 0:4]
Y = df.iloc[:, 4]
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, stratify=Y) # stratify 為分層抽樣
pca = PCA(n_components=2) # 加載PCA算法,設(shè)置降維后主成分?jǐn)?shù)目為2
# n_components的值不能大于n_features(特征數(shù))和n_classes(類別數(shù))之間的較小值減1。
reduced_x = pca.fit_transform(X) # 對(duì)樣本進(jìn)行降維
reduced_x = pd.DataFrame(reduced_x, columns = ['pca_1','pca_2'])
print(reduced_x.head(5))
# SVM分類
x_train, x_test, y_train, y_test = train_test_split(reduced_x, Y, test_size=0.2)
clf = svm.SVC(gamma='scale', decision_function_shape="ovr") # 一對(duì)多法
# clf = svm.SVC(gamma='scale', decision_function_shape='ovo') # 一對(duì)一法
clf.fit(x_train, y_train.astype('int'))
y_pred = clf.predict(x_test)
# 可視化,畫分類結(jié)果圖
N, M = 500, 500 # 橫縱各采樣多少個(gè)值
x1_min, x2_min = x_train.min(axis=0)
x1_max, x2_max = x_train.max(axis=0)
t1 = np.linspace(x1_min, x1_max, N)
t2 = np.linspace(x2_min, x2_max, M)
x1, x2 = np.meshgrid(t1, t2) # 生成網(wǎng)格采樣點(diǎn)
x_show = np.stack((x1.flat, x2.flat), axis=1) # 測(cè)試點(diǎn)
y_predict = clf.predict(x_show)
cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
plt.pcolormesh(x1, x2, y_predict.reshape(x1.shape), cmap=cm_light)
plt.scatter(x_train.iloc[:, 0], x_train.iloc[:, 1], c=y_train, cmap=cm_dark, marker='o', edgecolors='k')
plt.grid(True, ls=':')
plt.show()
PCA結(jié)果:
6.3 線性判別分析
LDA思想:最早提出是為了解決生物問(wèn)題的分類問(wèn)題,有監(jiān)督的線性降維。使用數(shù)據(jù)的類別信息,將高維的樣本線性投影到低維空間中,使得數(shù)據(jù)樣本在低維空間中,數(shù)據(jù)的類別區(qū)分度最大。
LDA代碼:
# 1.導(dǎo)入所需的庫(kù)和模塊:
import matplotlib.pyplot as plt
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.datasets import load_iris
# 2.加載數(shù)據(jù)集:
iris = load_iris()
X = iris.data
y = iris.target
# 3.創(chuàng)建一個(gè)LDA對(duì)象并擬合數(shù)據(jù):
# 在這里,n_components參數(shù)指定要保留的主成分?jǐn)?shù)量。
lda = LinearDiscriminantAnalysis(n_components=2)
X_lda = lda.fit_transform(X, y)
# 4.可以使用以下代碼可視化結(jié)果:
plt.scatter(X_lda[:, 0], X_lda[:, 1], c=y)
plt.xlabel('LD1')
plt.ylabel('LD2')
plt.show()
LDA結(jié)果:
什么情況不適合做降維:
降維是將高維數(shù)據(jù)映射到低維空間的過(guò)程,以減少特征數(shù)量和復(fù)雜度。然而,并非所有情況下都適合進(jìn)行降維,以下是一些不適合做降維的情況:
- 數(shù)據(jù)維度本身較低:如果數(shù)據(jù)本身的維度已經(jīng)很低,比如只有幾個(gè)特征,那么進(jìn)行降維可能會(huì)導(dǎo)致信息的丟失,反而不利于模型的建立和分析。
- 數(shù)據(jù)特征之間的相關(guān)性較弱:如果數(shù)據(jù)特征之間的相關(guān)性較弱或者沒(méi)有明顯的相關(guān)關(guān)系,那么進(jìn)行降維可能會(huì)導(dǎo)致信息的丟失,因?yàn)榻稻S往往是基于特征之間的相關(guān)性來(lái)進(jìn)行的。
- 數(shù)據(jù)特征之間存在非線性關(guān)系:如果數(shù)據(jù)特征之間存在復(fù)雜的非線性關(guān)系,比如高階相互作用或非線性映射,那么簡(jiǎn)單的降維方法(如主成分分析)可能無(wú)法捕捉到這些非線性關(guān)系,從而導(dǎo)致信息的丟失。
- 數(shù)據(jù)中存在重要但難以捕捉的特征:有些特征可能在高維空間中對(duì)模型的性能有重要影響,但是在低維空間中很難被捕捉到。因此,在這種情況下,進(jìn)行降維可能會(huì)導(dǎo)致模型性能的下降。
總的來(lái)說(shuō),降維可以幫助減少特征數(shù)量、簡(jiǎn)化模型、加快計(jì)算和可視化等,但并不是適用于所有情況。在決定是否進(jìn)行降維時(shí),需要綜合考慮數(shù)據(jù)的維度、特征之間的相關(guān)性、非線性關(guān)系以及特征的重要性等因素,并根據(jù)具體問(wèn)題和需求來(lái)做出決策。
七、數(shù)據(jù)歸一化
特征主要分為連續(xù)特征和離散特征,其中離散特征根據(jù)特征之間是否有大小關(guān)系又細(xì)分為兩類。
- 連續(xù)特征:一般采用歸一標(biāo)準(zhǔn)化方式處理。
- 離散特征:特征之間沒(méi)有大小關(guān)系。
- 離散特征:特征之間有大小關(guān)聯(lián),則采用數(shù)值映射。
# 通過(guò)歸一化處理使特征數(shù)據(jù)標(biāo)準(zhǔn)為1,均值為0,符合標(biāo)準(zhǔn)的正態(tài)分布,
# 降低數(shù)值特征過(guò)大對(duì)預(yù)測(cè)結(jié)果的影響
# 除了目標(biāo)特征全部做歸一化,目標(biāo)特征不用做,歸一化會(huì)導(dǎo)致預(yù)測(cè)結(jié)果的解釋變得困難
from sklearn.preprocessing import StandardScaler
# 實(shí)例化一個(gè)轉(zhuǎn)換器類
scaler = StandardScaler(copy=False)
target = df["LEAVE_FLAG"]
# 提取除目標(biāo)特征外的其他特征
other_features = df.drop("LEAVE_FLAG", axis=1)
# 對(duì)其他特征進(jìn)行歸一化
normalized_features = scaler.fit_transform(other_features)
# 將歸一化后的特征和目標(biāo)特征重新組合成DataFrame
normalized_data = pd.DataFrame(normalized_features, columns=other_features.columns)
normalized_data["LEAVE_FLAG"] = target
normalized_data.head()
八、模型搭建
# 深拷貝
X=normalized_data.copy()
X.drop(['LEAVE_FLAG'],axis=1, inplace=True)
y=df["LEAVE_FLAG"]
#查看預(yù)處理后的數(shù)據(jù)
X.head()
# 建立訓(xùn)練數(shù)據(jù)集和測(cè)試數(shù)據(jù)集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size = 0.3, random_state = 0)
print("原始訓(xùn)練集包含樣本數(shù)量: ", len(X_train))
print("原始測(cè)試集包含樣本數(shù)量: ", len(X_test))
print("原始樣本總數(shù): ", len(X_train)+len(X_test))
# 使用分類算法
Classifiers=[
["RandomForest",RandomForestClassifier()],
["LogisticRegression",LogisticRegression(C=1000.0, random_state=30, solver="lbfgs",max_iter=100000)],
["NaiveBayes",GaussianNB()],
["DecisionTree",DecisionTreeClassifier()],
["AdaBoostClassifier", AdaBoostClassifier()],
["GradientBoostingClassifier", GradientBoostingClassifier()],
["XGB", XGBClassifier()]
]
九、模型訓(xùn)練
from datetime import datetime
import pickle
import joblib
def get_current_time():
current_time = datetime.now()
formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
return current_time, formatted_time
Classify_result=[]
names=[]
prediction=[]
i = 0
for name, classifier in Classifiers:
start_time, formatted_time = get_current_time()
print("**********************************************************************")
print("第{}個(gè)模型訓(xùn)練開(kāi)始時(shí)間:{} 模型名稱為:{}".format(i+1, formatted_time, name))
classifier = classifier
classifier.fit(X_train, y_train)
y_pred = classifier.predict(X_test)
recall = recall_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)
f1score = f1_score(y_test, y_pred)
model_path = 'models/{}_{}_model.pkl'.format(name, round(precision, 5))
print("開(kāi)始保存模型文件路徑為:{}".format(model_path))
# 保存模型方式1
# with open('models/{}_{}_model.pkl'.format(name, precision), 'wb') as file:
# pickle.dump(classifier, file)
# file.close()
# 保存模型方式2
joblib.dump(classifier, model_path)
end_time = datetime.now() # 獲取訓(xùn)練結(jié)束時(shí)間
print("第{}個(gè)模型訓(xùn)練結(jié)束時(shí)間:{}".format(i+1, end_time.strftime("%Y-%m-%d %H:%M:%S")))
print("訓(xùn)練耗時(shí):", end_time - start_time)
# 打印訓(xùn)練過(guò)程中的指標(biāo)
print("Classifier:", name)
print("Recall:", recall)
print("Precision:", precision)
print("F1 Score:", f1score)
print("**********************************************************************")
# 保存指標(biāo)結(jié)果
class_eva = pd.DataFrame([recall, precision, f1score])
Classify_result.append(class_eva)
name = pd.Series(name)
names.append(name)
y_pred = pd.Series(y_pred)
prediction.append(y_pred)
i += 1
十、評(píng)估模型
召回率(recall)的含義是:原本為對(duì)的當(dāng)中,預(yù)測(cè)為對(duì)的比例(值越大越好,1為理想狀態(tài))
精確率、精度(precision)的含義是:預(yù)測(cè)為對(duì)的當(dāng)中,原本為對(duì)的比例(值越大越好,1為理想狀態(tài))
F1分?jǐn)?shù)(F1-Score)指標(biāo)綜合了Precision與Recall的產(chǎn)出的結(jié)果
F1-Score的取值范圍從0到1的,1代表模型的輸出最好,0代表模型的輸出結(jié)果最差。
classifier_names=pd.DataFrame(names)
# 轉(zhuǎn)成列表
classifier_names=classifier_names[0].tolist()
result=pd.concat(Classify_result,axis=1)
result.columns=classifier_names
result.index=["recall","precision","f1score"]
result
十一、預(yù)測(cè)模型
對(duì)于h5模型
from keras.models import load_model
model = load_model('lstm_model.h5')
pred = model.predict(X, verbose=0)
print(pred)
對(duì)于pkl模型
loaded_model = joblib.load('models/{}_model.pkl'.format(name))
由于沒(méi)有預(yù)測(cè)數(shù)據(jù)集,選擇最后n條數(shù)為例進(jìn)行預(yù)測(cè)。
# 由于沒(méi)有預(yù)測(cè)數(shù)據(jù)集,選擇最后n條數(shù)為例進(jìn)行預(yù)測(cè)。
n = 500
pred_id = SERV_ID.tail(n)
# 提取預(yù)測(cè)數(shù)據(jù)集特征(如果有預(yù)測(cè)數(shù)據(jù)集,可以一并進(jìn)行數(shù)據(jù)清洗和特征提?。?/span>
pred_x = X.tail(n)
# 使用上述得到的最優(yōu)模型
model = GradientBoostingClassifier()
model.fit(X_train,y_train)
pred_y = model.predict(pred_x) # 預(yù)測(cè)值
# 預(yù)測(cè)結(jié)果
predDf = pd.DataFrame({'SERV_ID':pred_id, 'LEAVE_FLAG':pred_y})
print("*********************原始的標(biāo)簽情況*********************")
print(df.tail(n)['LEAVE_FLAG'].value_counts())
print("*********************預(yù)測(cè)的標(biāo)簽情況*********************")
print(predDf['LEAVE_FLAG'].value_counts())
print("*********************預(yù)測(cè)的準(zhǔn)確率*********************")
min1 = min(df.tail(n)['LEAVE_FLAG'].value_counts()[0],predDf['LEAVE_FLAG'].value_counts()[0])
min2 = min(df.tail(n)['LEAVE_FLAG'].value_counts()[1],predDf['LEAVE_FLAG'].value_counts()[1])
print("{}%".format(round((min1+min2)/n,3)*100))
# 由于沒(méi)有預(yù)測(cè)數(shù)據(jù)集,選擇最后n條數(shù)為例進(jìn)行預(yù)測(cè)。
n = 500 # 預(yù)測(cè)的數(shù)量
pred_id = SERV_ID.tail(n)
# 提取預(yù)測(cè)數(shù)據(jù)集特征(如果有預(yù)測(cè)數(shù)據(jù)集,可以一并進(jìn)行數(shù)據(jù)清洗和特征提?。?/span>
pred_x = X.tail(n)
# 加載模型
loaded_model = joblib.load('models/GradientBoostingClassifier_0.77852_model.pkl')
# 使用加載的模型進(jìn)行預(yù)測(cè)
pred_y = loaded_model.predict(pred_x)
# 預(yù)測(cè)結(jié)果
predDf = pd.DataFrame({'SERV_ID':pred_id, 'LEAVE_FLAG':pred_y})
print("*********************原始的標(biāo)簽情況*********************")
print(df.tail(n)['LEAVE_FLAG'].value_counts())
print("*********************預(yù)測(cè)的標(biāo)簽情況*********************")
print(predDf['LEAVE_FLAG'].value_counts())
print("*********************預(yù)測(cè)的準(zhǔn)確率*********************")
min1 = min(df.tail(n)['LEAVE_FLAG'].value_counts()[0],predDf['LEAVE_FLAG'].value_counts()[0])
min2 = min(df.tail(n)['LEAVE_FLAG'].value_counts()[1],predDf['LEAVE_FLAG'].value_counts()[1])
print("{}%".format(round((min1+min2)/n,3)*100))
十二、健康度分析
- 參考鏈接----Python數(shù)據(jù)分析實(shí)戰(zhàn)【十一】:學(xué)習(xí)用scorecardpy搭建風(fēng)控評(píng)分卡模型【文末源碼地址】
十三 模型融合-Stack
import warnings
warnings.filterwarnings('ignore')
import itertools
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from sklearn import datasets
from sklearn.linear_model import LogisticRegression,ExtraTreesClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from mlxtend.classifier import StackingClassifier
from sklearn.model_selection import cross_val_score, train_test_split
from mlxtend.plotting import plot_learning_curves
from mlxtend.plotting import plot_decision_regions
# 以python自帶的鳶尾花數(shù)據(jù)集為例
iris = datasets.load_iris()
X, y = iris.data[:, 1:3], iris.target
clf1 = KNeighborsClassifier(n_neighbors=1)
clf2 = RandomForestClassifier(random_state=1)
clf3 = GaussianNB()
lr = LogisticRegression()
sclf = StackingClassifier(classifiers=[clf1, clf2, clf3],
meta_classifier=lr)
label = ['KNN', 'Random Forest', 'Naive Bayes', 'Stacking Classifier']
clf_list = [clf1, clf2, clf3, sclf]
fig = plt.figure(figsize=(10,8))
gs = gridspec.GridSpec(2, 2)
grid = itertools.product([0,1],repeat=2)
clf_cv_mean = []
clf_cv_std = []
for clf, label, grd in zip(clf_list, label, grid):
scores = cross_val_score(clf, X, y, cv=5, scoring='accuracy')
print("Accuracy: %.2f (+/- %.2f) [%s]" %(scores.mean(), scores.std(), label))
clf_cv_mean.append(scores.mean())
clf_cv_std.append(scores.std())
clf.fit(X, y)
ax = plt.subplot(gs[grd[0], grd[1]])
fig = plot_decision_regions(X=X, y=y, clf=clf)
plt.title(label)
plt.show()
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-657767.html
十四 模型融合-blending
# 以python自帶的鳶尾花數(shù)據(jù)集為例
from sklearn.ensemble import ExtraTreesClassifier
data_0 = iris.data
data = data_0[:100,:]
target_0 = iris.target
target = target_0[:100]
#模型融合中基學(xué)習(xí)器
clfs = [LogisticRegression(),
RandomForestClassifier(),
ExtraTreesClassifier(),
GradientBoostingClassifier()]
#切分一部分?jǐn)?shù)據(jù)作為測(cè)試集
X, X_predict, y, y_predict = train_test_split(data, target, test_size=0.3, random_state=914)
#切分訓(xùn)練數(shù)據(jù)集為d1,d2兩部分
X_d1, X_d2, y_d1, y_d2 = train_test_split(X, y, test_size=0.5, random_state=914)
dataset_d1 = np.zeros((X_d2.shape[0], len(clfs)))
dataset_d2 = np.zeros((X_predict.shape[0], len(clfs)))
for j, clf in enumerate(clfs):
#依次訓(xùn)練各個(gè)單模型
clf.fit(X_d1, y_d1)
y_submission = clf.predict_proba(X_d2)[:, 1]
dataset_d1[:, j] = y_submission
#對(duì)于測(cè)試集,直接用這k個(gè)模型的預(yù)測(cè)值作為新的特征。
dataset_d2[:, j] = clf.predict_proba(X_predict)[:, 1]
print("val auc Score: %f" % roc_auc_score(y_predict, dataset_d2[:, j]))
#融合使用的模型
clf = GradientBoostingClassifier()
clf.fit(dataset_d1, y_d2)
y_submission = clf.predict_proba(dataset_d2)[:, 1]
print("Val auc Score of Blending: %f" % (roc_auc_score(y_predict, y_submission)))
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-657767.html
到了這里,關(guān)于模型預(yù)測(cè)筆記(一):數(shù)據(jù)清洗分析及可視化、模型搭建、模型訓(xùn)練和預(yù)測(cè)代碼一體化和對(duì)應(yīng)結(jié)果展示(可作為baseline)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!