what?你还不知道机器学习怎么实战?

1,166 阅读9分钟

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

数据预处理

# 基本库
import pandas as pd
import numpy as np
# 取数据
csv_df = pd.read_csv('data/abalone.csv')

# 设置列名
csv_df.columns= ['Sex', 'Length', 'Diameter', 'Height', 'Whole weight','Shucked weight', 'Viscera weight', 'Shell weight', 'result']
df = pd.DataFrame(csv_df)
df.head(5)

# 对lable进行硬编码(factorize),对性别变量进行one-hot编码(dummies)
label = pd.DataFrame({'label': pd.factorize(df['result'])[0]})  # 用字典指定列名
dummies = pd.get_dummies(df.drop(columns=['result']))

data = pd.concat([dummies, label], axis=1)  # 行拼接
data.head(10)

pandas.factorize可以实现将字符串特征转化为数字特征

为啥数据要进行one-hot编码?🤔

举一个例子,如血型一般分为A、B、O、AB四个类型,为无序多分类变量,通常情况下在录入数据的时候,为了使数据量化,我们常会将其赋值为1、2、3、4。

从数字的角度来看,赋值为1、2、3、4后,它们是具有从小到大一定的顺序关系的,而实际上,四种血型之间并没有这种大小关系存在,它们之间应该是相互平等独立的关系。如果按照1、2、3、4赋值并带入到回归模型中是不合理的,此时我们就需要将其转化为哑变量。

one-hot编码可以将分类变量装换为“哑变量矩阵”(dummy matrix)。如果DataFrame的某一列中含有K个不同的值,则可以派生出一个K列矩阵或者DataFrame(其值全为0和1)。pandas 有一个get_dummies函数可以实现该功能 。在pandas可以指定 columns参数,pd.get_dummies(df,columns=["key","sorce"])指定被编码的列,返回被编码的列和不被编码的列;prefix参数可以给哑变量的名字加上一个前缀。

EDA(exploratory data analysis)

import matplotlib.pyplot as plt
import seaborn as sns
# 描述性统计
data.describe()

# 计算相关系数,展示参数间相关系数的热力图
corr = data.corr()

ax = plt.subplots(figsize=(14, 8))[1]
ax.set_title('Correlation')
sns.heatmap(corr, annot=True, cmap='RdBu')
plt.show()

image.png

# 显示变量两两之间关系的散点图
sns.pairplot(data, hue='label')
plt.show()

image.png

模型训练及测试

代码

def showClassificationData(X, Y, ifFit=False, overSampling='None'):
    """
    showData实现多维二分类任务的数据可视化,函数接受数值型变量,使用PCA可视化。
    :param overSampling: 对样本进行重采样
    :param ifFit: 画图时是否对数据进行拟合
    :param X: 设计矩阵(不含标签)
    :param Y: 分类标签
    """
    import matplotlib.pyplot as plt
    import seaborn as sns
   
    from sklearn.decomposition import PCA
    from imblearn.over_sampling import SMOTE
    from imblearn.combine import SMOTETomek, SMOTEENN

    def getSMOTE():
        return SMOTE(random_state=10)

    def getSMOTETomek():
        return SMOTETomek(random_state=10)

    def getSMOTEENN():
        return SMOTEENN(random_state=10)

    switch = {'SMOTE': getSMOTE,
              'SMOTETomek': getSMOTETomek,
              'SMOTEENN': getSMOTEENN}

    if overSampling != 'None':
        overSampler = switch.get(overSampling)()
        X, Y = overSampler.fit_resample(X, Y)

    # PCA提取两个主成分
    pca = PCA(n_components=2) #n_components为保留下来的特征个数
    print("降维前:",X)
    X = pca.fit_transform(X)  #X就是降维后的数据
    print("降维后:",X)
    
    X = pd.DataFrame(X)
    Y = pd.DataFrame(Y)

    X = pd.concat([X, Y], ignore_index=True, axis=1)
    X.columns = ['firstIngridient', 'secondIngridient', 'label']
    sns.lmplot('firstIngridient', 'secondIngridient', X, hue='label', fit_reg=ifFit)
    plt.show()
    

#查看两类数据差距
def showHistogram(Y, ifLog=False):
    """
    showHistgoram实现对计数变量的分布可视化
    :param ifLog: 是否对数据进行对数变换
    :param Y: 响应变量
    """
    import matplotlib.pyplot as plt
    import seaborn as sns

    Y = pd.DataFrame(Y)
    sns.set_style('whitegrid')
    fig, ax = plt.subplots()
    Y.hist(ax=ax, bins=100)
    if ifLog:
        ax.set_yscale('log')
    ax.tick_params(labelsize=14)
    ax.set_xlabel('count', fontsize=14)
    ax.set_ylabel('Y', fontsize=14)
    print("showHistogram:")
    plt.show()

    
def multiClassificationModel(X, Y, testSize=0.3, cv=5, ifSmote=False, ifKFold=False,ifRandomUnderSampler=False):
    """
    multiClassificationModel实现朴素贝叶斯、支持向量机、Logistic回归和XGBoost在数据集上的分类性能测试
    :param ifSmote: 是否做SMOTE重采样
    :param X: 特征矩阵
    :param Y: 标签
    :param testSize: 测试集大小,默认为0.3 
    :param cv: k折交叉验证的k值
    """
    print("使用不同模型分类的效果:")
    from collections import Counter
    from sklearn import naive_bayes, svm, linear_model,neighbors,tree
    from sklearn.model_selection import train_test_split, cross_val_score,StratifiedKFold
    from sklearn.metrics import accuracy_score, f1_score, recall_score, precision_score
    import xgboost
    from imblearn.over_sampling import SMOTE
    
    def train(model, x_train, y_train):
        return model.fit(x_train, y_train)
    
    def printScore(model, x, y):
        
        print('召回率(recall): ', recall_score(y, model.predict(x)))  #召回率
        print('精确度(Precision): ', precision_score(y, model.predict(x))) #准确率
        print('f1: ', f1_score(y, model.predict(x)))  #f1值
        print('准确率(accuracy): ', accuracy_score(y, model.predict(x))) 
    
    def printKFoldScore(model, X, Y, cv):  
        print('recall: ', cross_val_score(model, X, Y, cv=cv, scoring='recall').mean())
        print('precision: ', cross_val_score(model, X, Y, cv=cv, scoring='precision').mean())
        print('f1: ', cross_val_score(model, X, Y, cv=cv, scoring='f1').mean())
        print('accuracy: ', cross_val_score(model, X, Y, cv=cv, scoring='accuracy').mean())
    
    # 划分数据集
    x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=testSize, random_state=10)
    
    if ifSmote:
        smo = SMOTE(random_state=10)
        print("过采样之前的数据:",Counter(y_train))
        x_train, y_train = smo.fit_resample(x_train, y_train)       
        print("过采样之后的数据:",Counter(y_train))
    
    from imblearn.under_sampling import ClusterCentroids
    #欠采样
    if ifRandomUnderSampler:
        cc = ClusterCentroids(random_state=0)
        print("欠采样之前的数据:",Counter(y_train))
        x_train, y_train = cc.fit_resample(x_train, y_train)
       
        print("欠采样之后的数据:",Counter(y_train))
        
    
    #感知机
    Perceptron = linear_model.Perceptron()
    
    #KNN
    KNN = neighbors.KNeighborsClassifier()
   
    #决策树
    decision_tree=tree.DecisionTreeClassifier()
   
    # 朴素贝叶斯
    NB = naive_bayes.GaussianNB()

    # SVM
    SVM = svm.SVC()

    # logisticRegression
    LR = linear_model.LogisticRegression(max_iter=5000)

    # xgboost
    Xgb = xgboost.XGBClassifier()
              
    model_list = [NB, SVM, LR, Xgb, KNN,decision_tree,Perceptron]
    
    for i in range(len(model_list)):
        model_list[i] = train(model_list[i], x_train, y_train)
    
    print('----- train -----')
    for model in model_list:
        print('#### {} ####'.format(str(model).split('(')[0]))
        printScore(model, x_train, y_train)
        print()
    
    print('----- test -----')
    for model in model_list:
        print('#### {} ####'.format(str(model).split('(')[0]))
        printScore(model, x_test, y_test)
        print()
        
 
    
    if ifKFold:
        print("********** Stratified k-fold cross validation 分层交叉验证 **********")
        for model in model_list:
            print('#### {} ####'.format(str(model).split('(')[0]))
            strKFold = StratifiedKFold(n_splits=2,shuffle=True,random_state=0)
            printKFoldScore(model, X, Y, cv=strKFold)
            print()

应用

X = data.drop(columns=["label"]) #删除label列
Y = data["label"]  #label列

showHistogram(Y)
multiClassificationModel(X, Y,ifSmote=True,ifRandomUnderSampler=False,ifKFold=True)

image.png 使用不同模型训练的效果:

image.png 使用不同模型测试的效果:

image.png

评价指标

正样本/正例/正类:(二分类)任务中想要查找(识别)出来的类别

正样本-负样本_副本.png

精确度(Precision)

表示的是真正例占模型判断出的所有正例的比例

用途:用于评估检测器在检测成功基础上的正确率

召回率(recall)

表示的是模型正确判断出的正例占数据集中所有正例的比例

用途:用于评估检测器对所有待检测目标的检测覆盖率。

一般来说,准确率就是检索出来的条目中有多少是准确的,召回率就是所有准确的条目有多少被检索出来了。准确率和召回率区别就是分母不同,一个分母是预测为正的样本数,另一个是原来样本中所有的正样本数。

通过绘制precision-recall 曲线,该曲线下方的面积越大,识别精度也就越高,反之越低。

#准确率
sklearn.metrics.precision_score(y_true, y_pred, labels=None, pos_label=1, average=’binary’, sample_weight=None,zero_division='warn')

#召回率
sklearn.metrics.recall_score(y_true, y_pred, labels=None, pos_label=1, average='binary', sample_weight=None, zero_division='warn')

输入参数:

y_true:真实标签。

y_pred:预测标签。

labels:可选参数,是一个list。二分类时,用不上这个参数。

pos_label:字符串或者int类型,默认值是1。

average:字符串类型,取值为 [None, ‘binary’ (默认), ‘micro’, ‘macro’, ‘samples’, ‘weighted’]。默认为二分类。

sample_weight:样本比重

zero_division:默认为“warn”,表示 0 or 1,设置除法为零(即所有预测和标签均为负)时返回的值。如果设置为“ warn”,则该值为0, 但也会发出警告。

输出:

正样本准确率、召回率,浮点型。

F1值

准确率和召回率指标有时候会出现的矛盾的情况,这样就需要综合考虑他们,最常见的方法就是F1值。F1综合了准确率和召回率的结果,当F1较高时则能说明试验方法比较有效。

准确率(Accuracy)

表示的是模型判断正确的数据(预测对了, 本来是正样本检测为正样本,本来是负样本检测为负样本)占总数据的比例

通常来说,正确率越高,分类器越好。

K-Fold 交叉验证

在机器学习建模过程中,通常的做法通常是将数据分为训练集和测试集。测试集是与训练独立的数据,完全不参与训练,用于最终模型的评估。在训练过程中,经常会出现过拟合的问题。

过拟合问题就是模型可以很好的匹配训练数据,却不能很好在预测训练集外的数据。

如果此时就使用测试数据来调整模型参数,就相当于在训练时已知部分测试数据的信息,会影响最终评估结果的准确性。通常的做法是在训练数据再中分出一部分做为验证(Validation)数据,用来评估模型的训练效果。

验证数据从训练数据中获取,但不参与训练,这样可以相对客观的评估模型对于训练集之外数据的匹配程度。模型在验证数据中的评估常用的是交叉验证,又称循环验证。
它将原始数据分成K组(K-Fold),将每个子集数据分别做一次验证集,其余的K-1组子集数据作为训练集,这样会得到K个模型。这K个模型分别在验证集中评估结果,最后的误差MSE(Mean Squared Error)加和平均就得到交叉验证误差。

何时使用K-Fold🤔?
数据总量较小时,其他方法无法继续提升性能,可以尝试K-Fold。其他情况就不太建议了,例如数据量很大,就没必要更多训练数据,同时训练成本也要扩大K倍(主要指的训练时间)。

sklearn

scikit-learn,又写作sklearn,是一个开源的基于python语言的机器学习工具包。它通过NumPy, SciPy和Matplotlib等python数值计算的库实现高效的算法应用,并且涵盖了几乎所有主流机器学习算法。

sklearn里有什么👀❓

sklearn中常用的模块有分类、回归、聚类、降维、模型选择、预处理。

1️⃣分类:常用的算法有:SVM(支持向量机)、nearest neighbors(最近邻)、random forest(随机森林),常见的应用有:垃圾邮件识别、图像识别。

2️⃣回归:预测与对象相关联的连续值属性,常见的算法有:SVR(支持向量回归机)、 ridge regression(岭回归)、Lasso,常见的应用有:药物反应,预测股价。

3️⃣聚类:将相似对象自动分组,常用的算法有:k-Means、spectral clustering(谱聚类)、mean-shift(均值偏移),常见的应用有:客户细分,分组实验结果。

4️⃣降维:减少要考虑的随机变量的数量,常见的算法有:PCA(主成分分析)、feature selection(特征选择)、non-negative matrix factorization(非负矩阵分解),常见的应用有:可视化,提高效率。

5️⃣模型选择:比较,验证,选择参数和模型,常用的模块有:grid search(网格搜索)、cross validation(交叉验证)、 metrics(度量)。它的目标是通过参数调整提高精度。

6️⃣预处理:特征提取和归一化,常用的模块有:preprocessing,feature extraction,常见的应用有:把输入数据(如文本)转换为机器学习算法可用的数据。

7️⃣sklearn里还有数据集,如我们经常见到的鸢尾花数据集、波士顿房价数据集...

sklearn用起来简单到💥

安装只需要 pip install scikit-learn

引入程序只需要

from sklearn import naive_bayes, svm, linear_model,neighbors,tree
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import accuracy_score, f1_score, recall_score, precision_score

你想要什么算法只要from sklearn import 它,模型算法都在一句话里,你就可以直接调用起飞😋

以上相关代码请戳👉gitee.com/xin-yue-qin…

下篇👉 听说你被数据不均衡问题困扰?不如过采样or欠采样

一个函数就可直接评价分类指标,竟如此简单?

让我看看是谁还不会交叉验证?

参考资料

python 数据处理之使用get_dummies进行one-hot编码---yuxj记录学习

Python 对数据one-hot编码--水...琥珀

# sklearn(三)计算recall:使用metrics.recall_score()计算二分类的召回率--凝眸伏笔