第6章 挖掘建模


 

學習:通過接收到的數據,歸納提取相同與不同

機器學習:讓計算機以數據為基礎,進行歸納與總結

模型:數據解釋現象的系統。

6:2:2

·         訓練集:用來訓練與擬合模型

·         測試集:模型泛化能力的考量。(泛化:對數據的預測能力)

·         驗證集:當通過訓練集訓練出多個模型后,使用驗證集數據糾偏或比較預測

當數據量樣本較少時:
  
K-fold交叉驗證:將數據集分成K份,每份輪流作一遍測試集,其他作訓練集

其中羅基斯特映射和人工神經網絡既可以做回歸,也可以做分類,但是其作用主要以回歸為主。

6.1 分類

6.1.1 KNN

步驟如下:
1)算距離:給定測試對象,計算它與訓練集中的每個對象的距離
2)找鄰居:圈定距離最近的k個訓練對象,作為測試對象的近鄰
3)做分類:根據這k個近鄰歸屬的主要類別,來對測試對象分類

https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html#sklearn.neighbors.KNeighborsClassifier

import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler,StandardScaler,LabelEncoder,OneHotEncoder,Normalizer
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.decomposition import PCA
pd.set_option('display.max_columns',None) #控制列的輸出
#sl:satisfaction_level ---- False:MinMaxScaler;True:StandardScaler
#le:last_evaluation ---- False:MinMaxScaler;True:StandardScaler
#npr:number_project ---- False:MinMaxScaler;True:StandardScaler
#amh:average_monthly_hours ---- False:MinMaxScaler;True:StandardScaler
#tsc:time_spend_company ---- False:MinMaxScaler;True:StandardScaler
#wa:Work_accident ---- False:MinMaxScaler;True:StandardScaler
#pl5:promotion_last_5years ---- False:MinMaxScaler;True:StandardScaler

#dp:department ---- False:LabelEncoder;True:OneHotEncoder
#slr:salary ---- False:LabelEncoder;True:OneHotEncoder
def hr_preprocessing(sl = False,le = False,npr = False,amh = False,tsc = False,
                     wa = False,pl5 = False,dp = False,slr = False,lower_d = False,ld_n = 1):
    df = pd.read_csv('yuanHR.csv')
    # 1、清洗數據--即去除異常值或抽樣
    df = df.dropna(subset=['satisfaction_level','last_evaluation'])
    df = df[df['satisfaction_level']<=1][df['salary']!='nme']
    # 2、得到標注
    label = df['left']
    df = df.drop('left', axis=1)
    #3、特征選擇
    #4、特征處理
    scaler_lst = [sl,le,npr,amh,tsc,wa,pl5]
    column_lst = ['satisfaction_level','last_evaluation','number_project',
                  'average_monthly_hours','time_spend_company','Work_accident',
                  'promotion_last_5years']
    for i in range(len(scaler_lst)):
        if not scaler_lst[i]:
            df[column_lst[i]] = \
                MinMaxScaler().fit_transform(df[column_lst[i]].values.reshape(-1,1)).reshape(1,-1)[0]
        else:
            df[column_lst[i]] = \
                StandardScaler().fit_transform(df[column_lst[i]].values.reshape(-1,1)).reshape(1,-1)[0]

    scaler_lst = [slr, dp]
    column_lst = ['salary', 'department']
    for i in range(len(scaler_lst)):
        if not scaler_lst[i]:
            if column_lst[i] == 'salary':
                df[column_lst[i]] = [map_salary(s) for s in df['salary'].values]
            else:
                df[column_lst[i]] = LabelEncoder().fit_transform(df[column_lst[i]])
            #將'salary', 'department'進行歸一化處理
            df[column_lst[i]] = MinMaxScaler().fit_transform(df[column_lst[i]].values.reshape(-1,1)).reshape(1,-1)[0]
        else:
            #pandas庫中提供的直接進行OneHotEncoder的方法是get_dummies()
            df = pd.get_dummies(df,columns=[column_lst[i]])
    if lower_d == True:
        return PCA(n_components=ld_n).fit_transform(df.values)
    return df,label

d =dict([("low",0),('medium',1),('high',2)])

def map_salary(s):
    return d.get(s,0)

#在sklearn中沒有函數可以一步將訓練集、驗證集、測試集一步切分的函數,但有train_test_split函數可一步切分訓練集和測試集
def hr_modeling(features,label):
    from sklearn.model_selection import train_test_split
    f_v = features.values
    l_v = label.values
    #得到驗證集,占比20%
    X_tt,X_validation,Y_tt,Y_validation= train_test_split(f_v,l_v,test_size=0.2)
    #得到測試集,占比20%
    X_train,X_test,Y_train,Y_test = train_test_split(X_tt,Y_tt,test_size=0.25)
    print('train:',len(X_train),'\n','validation:',len(X_validation),'\n','test',len(X_test))

    #KNN
    #NearestNeighbors可以直接獲取一個點附近的若干個點
    from sklearn.neighbors import NearestNeighbors,KNeighborsClassifier

    #通過比較,k=3時的效果比較好,所以固定模型選擇k=3
    knn_clf = KNeighborsClassifier(n_neighbors=3)
    # knn_clf_n5 = KNeighborsClassifier(n_neighbors=5)
    #進行擬合
    knn_clf.fit(X_train,Y_train)
    # knn_clf_n5.fit(X_train, Y_train)
    #驗證:用驗證集進行對比
    Y_pred_validation = knn_clf.predict(X_validation)
    # Y_pred_validation_n5 = knn_clf_n5.predict(X_validation)

    #衡量指標:准確率、召回率、F值
    from sklearn.metrics import accuracy_score,recall_score,f1_score
    print('針對驗證集,選擇3個鄰居時:')
    print("accuracy_score:",accuracy_score(Y_validation,Y_pred_validation))
    print("recall_score:",recall_score(Y_validation,Y_pred_validation))
    print("f1_score:",f1_score(Y_validation,Y_pred_validation))
    # print('\n','選擇5個鄰居時:')
    # print("accuracy_score:", accuracy_score(Y_validation, Y_pred_validation_n5))
    # print("recall_score:", recall_score(Y_validation, Y_pred_validation_n5))
    # print("f1_score:", f1_score(Y_validation, Y_pred_validation_n5))

    #針對測試集
    Y_pred_test = knn_clf.predict(X_test)
    print('針對測試集,選擇3個鄰居時:')
    print("accuracy_score:",accuracy_score(Y_test,Y_pred_test))
    print("recall_score:",recall_score(Y_test,Y_pred_test))
    print("f1_score:",f1_score(Y_test,Y_pred_test))

    # 針對訓練集
    Y_pred_train= knn_clf.predict(X_train)
    print('針對訓練集,選擇3個鄰居時:')
    print("accuracy_score:", accuracy_score(Y_train, Y_pred_train))
    print("recall_score:", recall_score(Y_train, Y_pred_train))
    print("f1_score:", f1_score(Y_train, Y_pred_train))


    #對訓練出的模型進行存儲
    from sklearn.externals import joblib
    #對訓練出的模型進行存儲,取名為knn_clf_model
    joblib.dump(knn_clf,'knn_clf_model')
    #使用模型
    knn_clf = joblib.load('knn_clf_model')
    #利用存儲的模型進行計算
    Y_pred_train = knn_clf.predict(X_train)
    print('利用存儲的模型針對訓練集進行計算:')
    print("accuracy_score:", accuracy_score(Y_train, Y_pred_train))
    print("recall_score:", recall_score(Y_train, Y_pred_train))
    print("f1_score:", f1_score(Y_train, Y_pred_train))

def main():
    features,label = hr_preprocessing()
    hr_modeling(features,label)

if __name__ == "__main__":
    main()

'''
train: 8999 
 validation: 3000 
 test 3000
針對驗證集,選擇3個鄰居時:
accuracy_score: 0.955
recall_score: 0.9283667621776505
f1_score: 0.9056603773584906
針對測試集,選擇3個鄰居時:
accuracy_score: 0.9523333333333334
recall_score: 0.9252717391304348
f1_score: 0.9049833887043189
針對測試集,選擇3個鄰居時:
accuracy_score: 0.9745527280808979
recall_score: 0.9611605053813758
f1_score: 0.9471985243255706
利用存儲的模型針對訓練集進行計算:
accuracy_score: 0.975108345371708
recall_score: 0.9569332702318978
f1_score: 0.9475164011246485
'''

6.1.2 朴素貝葉斯

 

拉普拉斯平滑:在算條件概率時,給分母加上一個Ni(表示第i個屬性可能取的值),給分子加一個1

https://scikit-learn.org/stable/modules/classes.html#module-sklearn.naive_bayes

說明:在運用朴素貝葉斯時,所用的特征必須是離散值;若這些離散值是二值的,那么就用BernoulliNB效果較好一些;若這些離散值是連續的,那么在BernoulliNB算法下也會先將這些離散值進行二值化。若特征服從高斯分布,那么就使用GaussianNB。

hr_modeling()中進行處理,此處重復代碼不再給出

from sklearn.naive_bayes import GaussianNB,BernoulliNB
#對模型進行統一管理
models = []

#通過比較,k=3時的效果比較好,所以固定模型選擇k=3
# knn_clf = KNeighborsClassifier(n_neighbors=3)
models.append(('KNN',KNeighborsClassifier(n_neighbors=3)))
models.append(('GaussianNB',GaussianNB()))
models.append(('BernoulliNB',BernoulliNB()))
print('0:訓練集   1:驗證集   2:測試集')
for clf_name,clf in models:
    clf.fit(X_train,Y_train)
    xy_lst =[(X_train,Y_train),(X_validation,Y_validation),(X_test,Y_test)]
    for i in range(len(xy_lst)):
        X_part = xy_lst[i][0]
        Y_part = xy_lst[i][1]
        Y_pred = clf.predict(X_part)
        print(i)
        from sklearn.metrics import accuracy_score, recall_score, f1_score
        print(clf_name,'准備率:',accuracy_score(Y_part,Y_pred),
              '召回率:',recall_score(Y_part,Y_pred),
              'F1分數:',f1_score(Y_part,Y_pred))


'''
0:訓練集   1:驗證集   2:測試集
0
KNN 准確率: 0.974997221913546 召回率: 0.955607476635514 F1分數: 0.947856315179606
1
KNN 准確率: 0.9556666666666667 召回率: 0.9348441926345609 F1分數: 0.9084652443220922
2
KNN 准確率: 0.9586666666666667 召回率: 0.926896551724138 F1分數: 0.9155313351498638
0
GaussianNB 准確率: 0.7957550838982109 召回率: 0.735981308411215 F1分數: 0.6315156375300721
1
GaussianNB 准確率: 0.7923333333333333 召回率: 0.7450424929178471 F1分數: 0.6280597014925373
2
GaussianNB 准確率: 0.813 召回率: 0.7489655172413793 F1分數: 0.6593806921675773
0
BernoulliNB 准確率: 0.8402044671630181 召回率: 0.47757009345794393 F1分數: 0.5870189546237794
1
BernoulliNB 准確率: 0.846 召回率: 0.49291784702549574 F1分數: 0.6010362694300518
2
BernoulliNB 准確率: 0.8393333333333334 召回率: 0.4731034482758621 F1分數: 0.5873287671232877
'''

 

生成模型

判別模型

對數據要求

對數據容忍度

速度

使用范圍

 

6.1.3 決策樹

決策樹切分方法

·         信息增益-ID3依次選擇Gain值最大的特征進行切分

·         信息增益率-C4.5

·         Gini系數-CART依次選擇不純度最低的進行切分,Gini可參見4.2.2分組與鑽取

https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html#sklearn.tree.DecisionTreeClassifier

繪制決策樹---生成pdf文件

仍然在hr_modeling()中進行處理,此處重復代碼不再給出

    import pydotplus   #和Graphvia一樣,用於決策樹圖形的繪制
    from sklearn.tree import DecisionTreeClassifier,export_graphviz
    from sklearn.externals.six import StringIO
    models = []
    #DecisionTreeClassifier()的criterion參數默認是gini
    #選擇最小不純度切分為0.1
    models.append(('DecisionTreeGini',DecisionTreeClassifier(min_impurity_split=0.1)))
    models.append(('DecisionTreeEntroy',DecisionTreeClassifier(criterion='entropy')))

    print('0:訓練集   1:驗證集   2:測試集')
    for clf_name,clf in models:
        clf.fit(X_train,Y_train)
        xy_lst =[(X_train,Y_train),(X_validation,Y_validation),(X_test,Y_test)]
        for i in range(len(xy_lst)):
            X_part = xy_lst[i][0]
            Y_part = xy_lst[i][1]
            Y_pred = clf.predict(X_part)
            print(i)
            from sklearn.metrics import accuracy_score, recall_score, f1_score
            print(clf_name,'准確率:',accuracy_score(Y_part,Y_pred),
                  '召回率:',recall_score(Y_part,Y_pred),
                  'F1分數:',f1_score(Y_part,Y_pred))
            if clf_name =='DecisionTreeGini' or clf_name=='DecisionTreeEntroy':
                #dot_data這兩種寫法等效
                dot_data = StringIO()
                export_graphviz(clf, out_file=dot_data,
                                           feature_names=f_names,
                                           class_names=["NL", "L"],
                                           filled=True, rounded=True, special_characters=True)
                graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
                # dot_data = export_graphviz(clf,out_file=None,
                #                 feature_names=f_names,
                #                 class_names=["NL","L"],
                #                 filled=True,rounded=True,special_characters=True)
                # graph = pydotplus.graph_from_dot_data(dot_data)
                # graph.write_pdf("df_tree.pdf")

6.1.4 支持向量機

擴維:

常用核函數:

  線性核函數:線性可分用線性核函數

  多項式核函數:若d =2,擴到19維;d=3,擴到19維;

  RBF核函數:可以將空間映射為無限維

松弛變量的引入:

  為了達到一個更寬的分界線,可以容忍少量的錯分點,可以解決過擬合的問題

 

https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html#sklearn.svm.SVC

from sklearn.svm import SVC
#錯分點的懲罰度設置的很大,有利於分類效果,通過C設置分類准備性
#C=1是的效果比KNN、GaussianNB、BernoulliNB、DecisionTreeClassifier的效果差很多
    models.append(('SVM Classifier',SVC(C=100000)))
'''
0
SVM Classifier 准確率: 0.9756639626625181 召回率: 0.937984496124031 F1分數: 0.9494576505885068
1
SVM Classifier 准確率: 0.965 召回率: 0.9316493313521546 F1分數: 0.9227373068432672
2
SVM Classifier 准確率: 0.966 召回率: 0.9120567375886525 F1分數: 0.9265129682997119
'''

6.2 分類-集成

6.2.1 隨機森林

  

隨機森林中的隨機可以認為是每棵樹訓練集樣本的隨機、或者是沒課數特征的隨機、或者特征和樣本來那個方面的隨機。

https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html#sklearn.ensemble.RandomForestClassifier

    models.append(('RandomForestClassifier默認', RandomForestClassifier()))
    #If max_features is None, then max_features=n_features.
    #Whether bootstrap samples are used when building trees. If False, the whole datset is used to build each tree.
    #n_estimators的默認隨機數為10,太多的隨機數容易過擬合
    models.append(('RandomForestClassifier有參',RandomForestClassifier(max_features=None,bootstrap=True,n_estimators=10)))

'''
0 ---: RandomForestClassifier默認 准確率: 0.9966662962551395 召回率: 0.9870069605568446 F1分數: 0.9929971988795518
1 ---: RandomForestClassifier默認 准確率: 0.9866666666666667 召回率: 0.9510791366906475 F1分數: 0.9706314243759178
2 ---: RandomForestClassifier默認 准確率: 0.9916666666666667 召回率: 0.9722607489597781 F1分數: 0.9824807288016819
0 ---: RandomForestClassifier有參 准確率: 0.9974441604622736 召回率: 0.9907192575406032 F1分數: 0.9946424411833217
1 ---: RandomForestClassifier有參 准確率: 0.983 召回率: 0.943884892086331 F1分數: 0.962582538517975
2 ---: RandomForestClassifier有參 准確率: 0.9886666666666667 召回率: 0.9667128987517337 F1分數: 0.9761904761904762
'''

結論:

bootstrap = True時效果比較好

效果比以上的分類器好,驗證集的效果沒有全用默認參數的好
調參時,一般比較驗證集的結果

6.2.1 Adaboost

 

 

 

主要步驟:

1、首先給每個點賦一個初始的權值(不是給分類器賦權值)

2、循環一個弱分類器(所以一定會導致錯分),將錯分點相加得到

3、通過 得到分類器的權值

4、更新每個樣本的權值,分對了乘以 (樣本的權值會減小),分錯了乘以 (樣本的權值會增加)

說明:其中Z是正規權值話的參數,使所有的權值加起來還是為1

5、將每個分類器的權值 與結果相乘,再全部相加,得到最后的Adabosst的判別函數

例子:

Adaboost優點:

1)精度高,且靈活可調

2)幾乎不用擔心過擬合問題

3)簡化特征工程流程

https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.AdaBoostClassifier.html#sklearn.ensemble.AdaBoostClassifier

from sklearn.ensemble import AdaBoostClassifier
#n_estimators表示提升終止的最大估計數,經驗證n_estimators=10000時的效果和默認50想法效果差距不太大
models.append(('AdaBoostClassifier',AdaBoostClassifier(base_estimator=DecisionTreeClassifier(),n_estimators=10000)))
'''
0:訓練集   1:驗證集   2:測試集
0 ---: AdaBoostClassifier 准確率: 1.0 召回率: 1.0 F1分數: 1.0
1 ---: AdaBoostClassifier 准確率: 0.9753333333333334 召回率: 0.957037037037037 F1分數: 0.9458272327964862
2 ---: AdaBoostClassifier 准確率: 0.983 召回率: 0.9844192634560907 F1分數: 0.9646079111727968
'''

#需要注意base_estimator、n_estimators、algorithm、learning_rate這幾個參數

6.3 回歸

https://scikit-learn.org/stable/modules/model_evaluation.html

 

 

6.3.1 線性回歸

  回歸分析是確定多個變量間相互依賴的定量關系的一種統計分析方法

 

 

 

 1、嶺回歸算法---Ridge()---懲罰回歸函數的平方

   本質上是一種改良的最小二乘估計法,通過放棄最小二乘法的無偏性,以損失部分信息、降低精度為代價,獲得回歸系數更符合實際、更可靠的回歸方法。對病態數據的擬合要強於最小二乘法

2、套索回歸算法---Lasso()---懲罰回歸函數的絕對值

3、彈性網絡回歸算法---ElasticNet()

    Ridge()和Lasso()的混合體

 

 

從上圖中可以發現last_evaluation、number_project 、average_monthly_hours這3個屬性相關性較強,使用這3個屬性作為回歸實驗的屬性。

def regre_test(features,label):
    # print("X:",'\n',features)
    # print("Y:",'\n',label)

    #Ridge表示嶺回歸
    from sklearn.linear_model import LinearRegression,Ridge,Lasso
    # regr = LinearRegression()
    # regr = Ridge(alpha=1)  # alpha等於0時的效果與LinearRegression效果一樣
    regr = Lasso(alpha=0.0001)
    regr.fit(features.values,label.values)
    Y_pred = regr.predict(features.values)
    print("Coef:",regr.coef_)
    #用mean_squared_error衡量回歸方程的好壞
    from sklearn.metrics import mean_squared_error
    print('MSE:',mean_squared_error(label.values,Y_pred))
   
def main():
    features,label = hr_preprocessing()
    regre_test(features[['number_project','average_monthly_hours']],features['last_evaluation'])
    # hr_modeling(features,label)

'''
    Coef: [0.27156879 0.26782676]
    MSE: 0.05953825210281312
'''
    #用這組數據中,用嶺回歸可以得到控制參數規模的作用,但是效果不是很明顯
    #用Lasso回歸可以得到控制參數規模的作用,效果非常明顯

6.3.2 邏輯回歸

從本質上而言,是一種特殊的線性回歸,是一種有形變的線性回歸

其值域為[0,1]。

若將特征映射至高維,也可以用邏輯回歸的思想來解決高維分類問題。

解析思路與線性回歸思路是一致的。(結果發現效果並不理想)

 

https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html#sklearn.linear_model.LogisticRegression

from sklearn.linear_model import LogisticRegression

#C越大,正則化的影響就越好,tol表示精度,solve表示所使用的算法(其中sag表示平均梯度下降算法 Stochastic Average Gradient descent solver)
#max_iter表示最大迭代次數
models.append(('LogisticRegression',LogisticRegression(C=1000,tol=1e-10,solver='sag',max_iter=10000)))
'''
0 ---- LogisticRegression 准備率: 0.7895321702411379 召回率: 0.3560429304713019 F1分數: 0.4461988304093567
1 ---- LogisticRegression 准備率: 0.799 召回率: 0.3279648609077599 F1分數: 0.4262607040913416
2 ---- LogisticRegression 准備率: 0.7813333333333333 召回率: 0.32483221476510066 F1分數: 0.4245614035087719
'''

    效果一直很差,因為LogisticRegression()本質上還是一種線性的模型,此處所用的數據集不是線性可分的,所以所到的效果已經是在這種條件因素下最好的效果了。如果真要使線性回歸達到比較理想的效果,解題思路應該參考SVM,將數據映射到高維空間中,使其線性可分.

6.3.3 人工神經網絡

也是一個分類和回歸都可以使用的模型

 

 

 

 

神經網絡的優勢:

    可以將非線性擬合的很好,只要寬度足夠大,深度足夠深,神經網絡可以擬合任何非線性的映射

Keras中文網站:

https://keras-cn.readthedocs.io/en/latest/other/objectives/

注意:隨機梯度下降算法(sgd)及其變種亞當算法(adam)

#理解Sequential是人工神經網絡的一個容器,該容器是一個序列化的
from keras.models import Sequential
#Dense是神經網絡層,稱為稠密層,Activation為激活函數
from keras.layers.core import Dense,Activation
#SGD是隨機梯度下降算法
from keras.optimizers import SGD

mdl = Sequential()
mdl.add(Dense(units=50,input_dim=len(f_v[0])))#輸入層
mdl.add(Activation('sigmoid'))
mdl.add(Dense(units=2))#輸出層是標注,只有兩個值,所對應的值的2
mdl.add(Activation('softmax'))#保證其歸一化

sgd = SGD(lr=0.05)#構建一個優化器,lr表示學習率,相當於alpha
# from keras import losses
#編譯建立模型,此時的loss相當於最優化函數,optimizer表示選用優化器函數
mdl.compile(loss="mse",optimizer="adam")#,adam優化器不僅考慮了梯度的作用,也考慮了動量的作用
#要求Y_train是One-Hot形式的,nb_epoch表示迭代的次數,batch_size表示隨機梯度下降算法每次所選取的數量
mdl.fit(X_train,np.array([[0,1] if i==1 else [1,0] for i in Y_train]),nb_epoch=20000,batch_size=8999)
xy_lst = [(X_train, Y_train), (X_validation, Y_validation), (X_test, Y_test)]
for i in range(len(xy_lst)):
    X_part = xy_lst[i][0]
    Y_part = xy_lst[i][1]
    Y_pred = mdl.predict_classes(X_part)#用predict()時輸出的是連續值,使用predict_classes()時輸出的是分類標注
    # print(i)
    from sklearn.metrics import accuracy_score, recall_score, f1_score
    print(i, '---:', 'Nural Network', '准確率:', accuracy_score(Y_part, Y_pred),
          '召回率:', recall_score(Y_part, Y_pred),
          'F1分數:', f1_score(Y_part, Y_pred))
return
'''lr=0.01,optimizer=sgd,nb_epoch=1000,batch_size=2048時的結果
0 ---: Nural Network 准確率: 0.7647516390710078 召回率: 0.0 F1分數: 0.0
1 ---: Nural Network 准確率: 0.7616666666666667 召回率: 0.0 F1分數: 0.0
2 ---: Nural Network 准確率: 0.7536666666666667 召回率: 0.0 F1分數: 0.0

lr=0.05,optimizer=sgd,nb_epoch=20000,batch_size=8999,時的結果 0 ---: Nural Network 准確率: 0.8270918990999 召回率: 0.5118613138686131 F1分數: 0.5905263157894737 1 ---: Nural Network 准確率: 0.853 召回率: 0.5733532934131736 F1分數: 0.6346313173156587 2 ---: Nural Network 准確率: 0.843 召回率: 0.5414908579465542 F1分數: 0.620467365028203
lr=0.05,optimizer="adam",nb_epoch=20000,batch_size=8999,時的結果 0 ---: Nural Network 准確率: 0.9824424936104011 召回率: 0.931679925128685 F1分數: 0.9618357487922705 1 ---: Nural Network 准確率: 0.9736666666666667 召回率: 0.9205020920502092 F1分數: 0.9435310936383131 2 ---: Nural Network 准確率: 0.9703333333333334 召回率: 0.9093444909344491 F1分數: 0.9361091170136395 '''

    召回率為0表示全部擬合成1個函數,未能擬合到真實函數,loss的值越小,表示擬合的效果越好,可調整參數nb_epoch、batch_size優化器的學習率lr
    可以看到召回率有變化,證明學習正確了,但是學習率不能取很大,否則有可能不能很好的擬合數據
 

6.3.4 回歸樹與提升樹

回歸樹(應用較少)

 

根據某一個特征進行切分,一定要滿足在切分后的兩部分的方差的和最小。

  此時的label還是上一步取下來的值

提升樹:基於回歸樹的集成方法(應用較多),尤其是梯度提升決策樹效果最佳(根據差分值進行回歸分析,直到將差分值變得越來越小)

    此時的label值為上一步預測后的值與原來值的差分值。

其中:Loss Function表示的是一棵樹的loss 

GBDT的算法:

 

https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.GradientBoostingClassifier.html#sklearn.ensemble.GradientBoostingClassifier

特征數量較大的時候用GBDT的效果是比較好的

from sklearn.ensemble import GradientBoostingClassifier
models.append(('GBDT',GradientBoostingClassifier(max_depth=6,n_estimators=100)))
'''
0:訓練集   1:驗證集   2:測試集
0 ---: GBDT 准確率: 0.9937770863429269 召回率: 0.9770114942528736 F1分數: 0.9869948908499767
1 ---: GBDT 准確率: 0.9893333333333333 召回率: 0.9645390070921985 F1分數: 0.9770114942528736
2 ---: GBDT 准確率: 0.9873333333333333 召回率: 0.9551374819102749 F1分數: 0.972017673048601
'''

6.4 聚類

6.4.1 Kmeans

 

1、中心如何定義:取數據各個維度的均值

2、定義如何衡量:使用歐氏距離

 

 

https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html#sklearn.cluster.KMeans

import numpy as np
import matplotlib.pyplot as plt
#make_circles,make_blobs,make_moons可以制造一些點以供使用
from sklearn.datasets import make_circles,make_blobs,make_moons
from sklearn.cluster import KMeans
n_samples = 1000
#構造樣本點
    #n_samples表示構造樣本點的個數,噪聲的比例為0.05
circles  = make_circles(n_samples = n_samples,factor=0.5,noise=0.05)
moons = make_moons(n_samples = n_samples,noise=0.05)
    #指定random_state的目的是是的每次產生的blobs都是一樣的,以免發生位置上的變化
blobs = make_blobs(n_samples = n_samples,random_state=8)
random_data = np.random.rand(n_samples,2),None  #生成一個2維的,None是值得標注只占位置而不進行使用
# print(random_data)
#制定要用到的色系
colors = "bgrcmyk"
data = [circles,moons,blobs,random_data]
# print(data)
models =[]
#此時首先假設的模型並沒有實體,Kmeans中的n_clusters=2表示被分為2類
models.append(("None",None))
models.append(("Kmeans",KMeans(n_clusters=2)))
f = plt.figure()
for inx,clt in enumerate(models):
    clt_name,clt_entity = clt   #clt分為兩部分,第一部分是名字,第二部分是實體
    #在沒有聚類之前,認為所有的點都是同一個類
    for i,dataset in enumerate(data):
        X,Y = dataset
        if not clt_entity: #如果實體為空
            clt_res = [0 for item in range(len(X))]  #沒有聚類前認為其標注都是0
        else:
            clt_entity.fit(X)
            #擬合(聚類)完成后,將得到的labels轉化成int格式
            clt_res = clt_entity.labels_.astype(np.int)
        f.add_subplot(len(models),len(data),inx*len(data)+i+1)
        plt.title(clt_name)
        [plt.scatter(X[p,0],X[p,1],color=colors[clt_res[p]]) for p in range(len(X))]
plt.show()

由結果可見:

切分方式是不同的,這是由於初始質心的選取所導致。

由於選擇聚類為2類,所以看第2幅圖第7個圖可知,將最近的兩個圖案也當成一個類。

6.4.2 DBSCAN(基於密度)

DBSCAN算法的目的:找到密度相連對象的最大集合

 

 

 幾個問題:

(1)  對離群點不敏感

(2)  需要kd-tree等數據結構輔助

(3)  需要先解決兩個參數再使用DBSCAN

from sklearn.cluster import KMeans,DBSCAN
    #指定random_state的目的是是的每次產生的blobs都是一樣的,以免發生位置上的變化;
    # center_box默認區間是(-10,10)
    #cluster_std設置標准差,默認為1
blobs = make_blobs(n_samples = n_samples,random_state=8,center_box=(-1,1),cluster_std=0.1)
#eps表示E鄰域,min_samples表示MinPtn
models.append(('DBSCAN',DBSCAN(min_samples=3,eps=0.2)))

 在調參時,注意參數center_box、cluster_std、min_samples、eps

6.4.3 層次聚類

聚類過程是一層一層進行的,直到不能再聚為止

衡量方法采用距離衡量

       A、最短距離:將兩個簇最相近的兩個點的距離作為簇間距離

       B、最長距離:將兩個簇最遠的兩個點的距離作為簇間距離    

       C、平均距離:將兩個簇的中點見得距離違簇間距離

       D、Ward:

        ESS增加的越大,越不將其合成一個簇,所以選定ESS增加較小的值作為下一步聚類的方法。

層次聚類的優點:聚類靈活

層次聚類的缺點:計算復雜度較高,離群點影響比較大

https://scikit-learn.org/stable/modules/generated/sklearn.cluster.AgglomerativeClustering.html#sklearn.cluster.AgglomerativeClustering

from sklearn.cluster import KMeans,DBSCAN,AgglomerativeClustering
#linkage表示使用的方法
models.append(('Agglomerative',AgglomerativeClustering(n_clusters=3,linkage='ward')))

雖然不一定能將相連的都分的很好,但是對於離散的群落,得到的結果和DBSCAN差不多。

6.4.4 圖分裂

其中:

t表示承受系數, 表示分裂閾值(t> 時,應該將一條邊或是一組邊進行切分)

       W1表示所選區域左邊點的個數

       W2表示所選區域右邊點的個數

       n表示將一個圖分裂開所需要的邊的個數

       x表示最大連通圖中邊的數量

       y表示最大連通圖中點的個數

幾個問題:

  (1)    與層次聚類思路相反,為自頂向下

  (2)    圖建立方式、分裂方式可以非常靈活

6.5 關聯

       關聯規則:反應一個事物與其它事物之間的相互依存性和關聯性

 

  提升度 > 1時表示購買X對購買Y起到了提升作用;

  提升度 < 1 時表示購買X對購買Y並未提升作用,可以認為兩者是相斥的,即購買了X將不會購買Y

注意:

  低階頻繁項集的組合可能是高階頻繁項集,也可能不是高階級頻繁項集;

  低階非頻繁項集的組合一定是高階非頻繁項集;

  低級頻繁項集和低級非頻繁項集的組合一定是高階非頻繁項集。

  

sklearn中不支持序列規則

6.6 半監督學習

樣本集部分有標注,部分無標注。無標注的樣本常遠遠大於有標注的樣本。

目的:根據有標注的樣本和樣本的總體分布的情況給沒有標注的樣本進行標注。

6.6.1 標簽傳播算法

https://scikit-learn.org/stable/modules/generated/sklearn.semi_supervised.LabelPropagation.html#sklearn.semi_supervised.LabelPropagation

import numpy as np
from sklearn import datasets
iris = datasets.load_iris()
# print(iris)
labels = np.copy(iris.target)
# print(labels)
#生成0到1之間的隨機數
random_unlabeled_points =np.random.rand(len(iris.target))

#生成的隨機數若小於0.3則返回True--1,否則返回False--0
random_unlabeled_points = random_unlabeled_points < 0.3

Y = labels[random_unlabeled_points]
#重置標簽,將random_unlabeled_points中為True的數換成-1
labels[random_unlabeled_points] = -1
print("Unlabeled Number:",list(labels).count(-1))

from sklearn.semi_supervised import LabelPropagation
label_prop_model = LabelPropagation()
label_prop_model.fit(iris.data,labels)
Y_pred = label_prop_model.predict(iris.data)
#對標注為-1的部分再預測一遍
Y_pred = Y_pred[random_unlabeled_points]
from sklearn.metrics import accuracy_score,recall_score,f1_score
print("准確率:",accuracy_score(Y,Y_pred))
print("召回率:",recall_score(Y,Y_pred,average='micro'))
print("f1分數:",f1_score(Y,Y_pred,average='micro'))
'''
Unlabeled Number: 45
准確率: 0.9555555555555556
召回率: 0.9555555555555556
f1分數: 0.9555555555555556
'''

關於模型的選用:可參考sklearn官網

https://scikit-learn.org/stable/tutorial/index.html

https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html


 


免責聲明!

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



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