数据不平衡处理,交叉验证,召回率

一 .数据量不平衡

​ 当数据极不平衡时会造成算法结果很不准确。可以通过上采样或者下采样来处理数据不平衡的情况(以y=0极多,y=1很少为例)

1.1 下采样

​ 下采样就是减少数据极多的样本数据,以达到平衡数据的效果(减少y=0的样本数,使y=0的数量和y=1的数量平衡起来)

​ 使用python实现下采样的代码

#下采样
def down(data):
    #分离特值X和结果y
    X = data.iloc[:,data.columns!='Class']
    y = data.loc[:,data.columns=='Class']
    #获取到y==1的数量
    number_records_fraud = len(data[data.Class==1])
    #获取y=1的index
    fraud_indic = np.array(data[data.Class==1].index)

    #获取y=0的索引
    normal_indices = data[data.Class==0].index
    #从y=0的索引中随机的抽取一部分数据
    random_normal_indices = np.random.choice(normal_indices,number_records_fraud,replace=False)
    random_normal_indices = np.array(random_normal_indices)

    #合并y=0和y=1的数据
    under_sample_indices = np.concatenate([fraud_indic,random_normal_indices])


    #
    under_sample_data = data.iloc[under_sample_indices,:]


    X_undersample = under_sample_data.ix[:,under_sample_data.columns!='Class']
    y_undersample = under_sample_data.ix[:,under_sample_data.columns=='Class']

    print("Percentage of normal transactions:",len(under_sample_data[under_sample_data.Class==0])/len(under_sample_data))
    print("Percentage of fraud transactions:",
          len(under_sample_data[under_sample_data.Class == 1]) / len(under_sample_data))
    print("Total number of transactions in resampled data:",len(under_sample_data))

1.2 上采样

​ 上采样就是使少的数据变多。

​ SMOTE(Synthetic Minority Oversampling Technique),合成少数类过采样技术.它是基于随机过采样算法的一种改进方案,由于随机过采样采取简单复制样本的策略来增加少数类样本,这样容易产生模型过拟合的问题,即使得模型学习到的信息过于特别(Specific)而不够泛化(General),SMOTE算法的基本思想是对少数类样本进行分析并根据少数类样本人工合成新样本添加到数据集中,具体如下图所示,算法流程如下。

(1)对于少数类中每一个样本x,以欧氏距离为标准计算它到少数类样本集中所有样本的距离,得到其k近邻。

(2)根据样本不平衡比例设置一个采样比例以确定采样倍率N,对于每一个少数类样本x,从其k近邻中随机选择若干个样本,假设选择的近邻为 x n x_n xn

(3)对于每一个随机选出的近邻 x n x_n xn,分别与原样本按照如下的公式构建新的样本。

x n e w = x + r a n d ( 0 , 1 ) ∗ ( x ~ − x ) x_{new }= x+rand(0,1)*(\tilde{x}-x) xnew=x+rand(0,1)(x~x)

数据不平衡处理,交叉验证,召回率_第1张图片

SMOTE的伪代码如下

数据不平衡处理,交叉验证,召回率_第2张图片

python使用SMOTE的案例

def updedata():
    path = "./creditcard.csv"
    credit_cards = pd.read_csv(path)

    columns = credit_cards.columns

    freatures_columns = columns.delete(len(columns)-1)

    freatures = credit_cards[freatures_columns]

    labels = credit_cards['Class']

    freatures_train,fretures_test,labels_train,labels_test = train_test_split(freatures,labels,test_size=0.2,random_state=0)

    oversampler = SMOTE(random_state=0)

    os_features,os_labels = oversampler.fit_resample(freatures_train,labels_train)

    print(len(os_labels==1))

    os_features = pd.DataFrame(os_features)
    os_labels = pd.DataFrame(os_labels)
    best_c = printing_Kfold_scores(os_features,os_labels)
    print(best_c)

二 .数据值不平衡

​ 如果在数据样本中特征值的分布相差太大(如:特征A的取值范围在-1~1 特值B的取值在1000~10000)这就会导致特征值的分布不相近,也会影响算法。可以使用sklearn对特征进行标准化确保特征分布相近。

 data['normAmount'] = StandardScaler().fit_transform(data['Amount'].values.reshape(-1, 1))

​ 通过验证得知此特征是一个可有可无的特征,那么就可以删掉此特征

data = data.drop(['Time','Amount'],axis=1)

三.交叉验证

​ 交叉验证(Cross-validation)主要用于建模应用中,例如PCR 、PLS 回归建模中。在给定的建模样本中,拿出大部分样本进行建模型,留小部分样本用刚建立的模型进行预报,并求这小部分样本的预报误差,记录它们的平方加和。

3.1 目的

​ 是为了得到可靠稳定的模型

3.2 中心思想

​ 交叉验证的基本思想是把在某种意义下将原始数据(dataset)进行分组,一部分做为训练集(train set),另一部分做为验证集(validation set or test set),首先用训练集对分类器进行训练,再利用验证集来测试训练得到的模型(model),以此来做为评价分类器的性能指标。如下图

数据不平衡处理,交叉验证,召回率_第3张图片

3.3 相关代码

3.3.1 数据切分
#使用sklear进行数据得切分
from sklearn.model_selection import train_test_split
def train_test(X,y,X_under,y_under):
    #原始数据 方便测试  测试集30%
    X_train,X_test,y_train,y_text = train_test_split(X,y,test_size=0.3,random_state=0)
    print("Number transactions train dataset:",len(X_train))
    print("Number transactions test dataset:", len(X_test))
    print("Total number of transactions::", len(X_train)+len(X_test))

    #下采样得数据
    X_train_under, X_test_under, y_train_under, y_text_under = train_test_split(X_under, y_under, test_size=0.3,
                                                                                random_state=0)
    print("Number transactions train dataset:",len(X_train_under))
    print("Number transactions test dataset:", len(X_test_under))
    print("Total number of transactions::", len(X_train_under)+len(X_test_under))
3.3.2 交叉验证得到最好的模型参数
#引入模型 KFold进行交叉验证,cross_val_score 交叉验证得结果
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import  KFold,cross_val_score
from sklearn.metrics import confusion_matrix,recall_score,classification_report

#找到最合适得参数
def printing_Kfold_scores(x_train_data, y_train_data):
    # 把训练集分为5份进行验证
    fold = KFold( 5, shuffle=False)

    # 不同的参数
    c_param_range = [0.01, 0.1, 1, 10, 100]

    results_table = pd.DataFrame(index=range(len(c_param_range), 2), columns=['0', '1'])
    results_table['0'] = c_param_range

    # the k-fold will give 2 lists: train_indices = indices[0], test_indices = indices[1]
    #k-fold 给出2的lists :train_indices = indices[0], test_indices = indices[1]
    j = 0
    #循环大带入参数进行验证
    for c_param in c_param_range:
        print('-------------------------------------------')
        print('C parameter: ', c_param)
        print('-------------------------------------------')
        print('')

        recall_accs = []
        #把训练集分为5份进行验证
        for iteration, indices in enumerate(fold.split(x_train_data), start=1):
            # Call the logistic regression model with a certain C parameter
            #调用sklearn中的逻辑回归模型
            lr = LogisticRegression(C=c_param, penalty='l1')

            # Use the training data to fit the model. In this case, we use the portion of the fold to train the model
            # with indices[0]. We then predict on the portion assigned as the 'test cross validation' with indices[1]
            #使用训练数据来拟合模型。 在这种情况下,我们使用折叠的部分来训练带有indices[0] 的模型
            # 然后,我们使用indices[1] 预测指定为“测试交叉验证”的部分
            lr.fit(x_train_data.iloc[indices[0], :], y_train_data.iloc[indices[0], :].values.ravel())

            # Predict values using the test indices in the training data
            #使用训练数据中的测试指数预测值
            y_pred_undersample = lr.predict(x_train_data.iloc[indices[1], :].values)

            # Calculate the recall score and append it to a list for recall scores representing the current c_parameter
            #计算召回分数并将其附加到表示当前c_parameter的召回分数列表中
            recall_acc = recall_score(y_train_data.iloc[indices[1], :].values, y_pred_undersample)
            recall_accs.append(recall_acc)
            print('Iteration ', iteration, ': recall score = ', recall_acc)

        # The mean value of those recall scores is the metric we want to save and get hold of.
        #这些召回分数的平均值是我们想要保存和掌握的指标。
        results_table.ix[j, '1'] = np.mean(recall_accs)
        j += 1
        print('')
        print('Mean recall score ', np.mean(recall_accs))
        print('')

    best_c = results_table.loc[results_table['1'].astype(float).idxmax()]['0']

    # Finally, we can check which C parameter is the best amongst the chosen.
    print('*********************************************************************************')
    print('Best model to choose from cross validation is with C parameter = ', best_c)
    print('*********************************************************************************')

    return best_c

四.模型评估方法

4.1 Recall值和Precision

​ Precision又叫查准率,Recall又叫查全率。这两个指标共同衡量才能评价模型输出结果。

  • TP: 预测为1(Positive),实际也为1(Truth-预测对了)

  • TN: 预测为0(Negative),实际也为0(Truth-预测对了)

  • FP: 预测为1(Positive),实际为0(False-预测错了)

  • FN: 预测为0(Negative),实际为1(False-预测错了)

    如下图:

数据不平衡处理,交叉验证,召回率_第4张图片

总的样本个数为:TP+TN+FP+FN。

Accuracy = (预测正确的样本数)/(总样本数)=(TP+TN)/(TP+TN+FP+FN)

Precision = (预测为1且正确预测的样本数)/(所有预测为1的样本数) = TP/(TP+FP)

Recall = (预测为1且正确预测的样本数)/(所有真实情况为1的样本数) = TP/(TP+FN)

4.1.1 精度与Recall的计算

​ 假如我们由十个样本Y={1,2,3,4,5,6,7,8,9,10} 我们的预测 Y ^ \hat{Y} Y^={1,3,3,4,5,6,7,8,9,0} 那么精度就是 8 10 \frac{8}{10} 108=80%

但是如果我们一个医院的病人检测的系统用来检测病人是否患病,假如我们由1000个人,其中990个人正常,10个人患病,而我们的系统把1000个人全部检测为正常。这是系统的精确率为 990 1000 \frac{990}{1000} 1000990=99%,但是Recall = 0 10 \frac{0}{10} 100=0 所以这个系统是不能使用的。所以精度不能作为我们衡量模型的唯一标准。

4.2 如何理解F1

F1值就是精确值和召回率的调和均值,也就是
2 F 1 = 1 P + 1 R \frac{2}{F_1}=\frac{1}{P}+\frac{1}{R} F12=P1+R1
调整下也就是
F 1 = 2 P R P + 2 F_1 = \frac{2PR}{P+2} F1=P+22PR

准确率就是找得对,召回率就是找得全

4.3 代码

from sklearn.metrics import confusion_matrix,recall_score,classification_report
            #计算召回分数并将其附加到表示当前c_parameter的召回分数列表中
    recall_acc = recall_score(y_train_data.iloc[indices[1], :].values, y_pred_undersample)
            recall_accs.append(recall_acc)
            print('Iteration ', iteration, ': recall score = ', recall_acc)

初 次 学 习 , 记 录 方 便 理 解 , 若 有 错 望 指 正 , 谢 谢 \color {red}{初次学习,记录方便理解,若有错望指正,谢谢} 便

你可能感兴趣的:(机器学习)