数据挖掘比赛基本框架

0.前言

这篇博客主要目的是对近一个月来参加的天池的数据挖掘比赛做一个梳理,主要是对整个数据挖掘的基本框架进行梳理,方便以后需要时快速复习,远没达到可以教授别人的地步。第一次做一个完整的数据挖掘项目,收获良多,感觉是从0到1的突破,但同时自己也是刚刚入门,很多东西都是在粗略地模仿,还需不断学习。

这次参加的是零基础入门金融风控-贷款违约预测,排名到了前15%,还算满意但确实有很多做得不够好的地方。

1.基本框架

1.1数据探索性分析(EDA)

EDA主要是为了对数据集有个大体的认识,查看数据的缺失值、唯一值情况,查看数据类型,查看数据的分布情况。经过了EDA后也可以对后续的数据特征工程和建模有很大的启发作用。

另外如果是参加数学建模,EDA过程可以很好的将数据可视化,毕竟数学建模比赛(像美赛)还是很看重画图的。

1.1.1 查看数据基本信息

首先读取数据

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
sns.set_style("darkgrid",{"font.sans-serif":['KaiTi', 'Arial']})   #这是方便seaborn绘图得时候得字体设置
import matplotlib as mpl
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题,或者转换负号为字符串
from pandas import Series, DataFrame
%matplotlib inline
import warnings
warnings.filterwarnings('ignore')

data_train = pd.read_csv(r'E:\数据分析\天池新手赛\第二次\train.csv', index_col='id')
data_test = pd.read_csv(r'E:\数据分析\天池新手赛\第二次\testA.csv', index_col='id')

查看数据的基本信息

# 看下数据基本信息
print("data_train's shape:{}\n".format(data_train.shape))
print("data_test's shape:{}\n".format(data_test.shape))
print("data_train's info:{}\n".format(data_train.info()))
print("data_test's info:{}\n".format(data_test.info()))

在这里插入图片描述
这一步的作用主要是看下数据的形状以及不同属性列的数据类型(是int、float还是object),以及对数据的缺失情况有个大体了解。

1.1.2 查看缺失值情况

查看哪些属性存在缺失值,以便数据特征工程时对缺失值进行处理。

# 看下缺失值情况
# print(10*'*',"data_train Null", 10*'*'+'\n')
train_null = data_train.isnull().sum()
train_null = train_null[train_null>0]/len(data_train)
train_null.sort_values(inplace=True)
# print(train_null,'\n')
# print(10*'*',"data_test Null", 10*'*'+'\n')
test_null = data_test.isnull().sum()
test_null = test_null[test_null>0]/len(data_train)
test_null.sort_values(inplace=True)
# print(test_null)
fig, axes = plt.subplots(2, 1, figsize=(8, 15))
train_null.plot.barh(ax=axes[0])
axes[0].set_title('data_train_NULL')
test_null.plot.barh(ax=axes[1])
axes[1].set_title('data_test_NULL')
plt.savefig(r'E:\数据分析\天池新手赛\第二次\NAN.png')

train_null_col = [col for col in train_null.index]
test_null_col = [col for col in test_null.index]

在这里插入图片描述
(像这种图就很适合放在数学建模比赛中使用)

1.1.3 查看唯一值情况并删除唯一值

唯一值是指数据集的某一属性列只有一种数值,比如某一列全为1,这对模型预测没有用处,所以需要挑选出来并删除。

# 查看唯一值情况
train_unique = [col for col in data_train.columns if data_train[col].nunique()<=1]
test_unique = [col for col in data_test.columns if data_test[col].nunique()<=1]
print("data_train only has one variable:{}\n".format(train_unique))
print("data_test only has one variable:{}".format(test_unique))

# 直接把唯一值删除
data_train.drop('policyCode', axis=1, inplace=True)
data_test.drop('policyCode', axis=1, inplace=True)

1.1.4 筛选出不同数据类型

这一步需要按照数据类型对数据集的属性进行筛选,先筛选出object类型的,因为这种类型的属性大多是类别属性,剩下的大多是数值属性(int、float等)。当然这么筛选是非常粗糙的,会选错,在数据特征工程时需要按照具体背景做进一步的划分。

# 对数据类型进行筛选:连续性、离散型、类别型、时间型
# 先挑出类别型和数值型
category_col = [col for col in data_train.select_dtypes(include=['object']).columns]
numerical_col = [col for col in data_train.select_dtypes(exclude=['object']).columns]
# 从数值型中挑出离散型和连续型数据(某种属性种类数<=150则为离散型)
numerical_discrete_col = []
numerical_continuous_col = []
for col in numerical_col:
    if(data_train[col].nunique()<=150):
        numerical_discrete_col.append(col)
    else:
        numerical_continuous_col.append(col)
# 'employmentLength'虽然以字符串形式存储,但却是离散数值
numerical_discrete_col.append('employmentLength')
# 从类别型中挑出时间型:
time_col = ['issueDate', 'earliesCreditLine']
for x in time_col:
    category_col.remove(x)
category_col.remove('employmentLength')

在这次比赛中我又挑选出了时间数据(object类型),因为时间数据的处理较为特殊,可以将其转换成数值型数据来处理(转换方法在数据特征工程部分说明)

1.1.5 画图观察数值型数据分布情况

# 看下数值型数据分布情况
f = pd.melt(data_train, value_vars=numerical_col)
g = sns.FacetGrid(f, col='variable', col_wrap=3, sharex=False, sharey=False)
g = g.map(sns.distplot, 'value')
g.savefig(r'E:\数据分析\天池新手赛\第二次\数值数据分布.png')

P.s:这种画图方法挺巧妙的,而且这种图很适合用在数学建模比赛中。
在这里插入图片描述

# 看下类别数据分布情况
fig, axes = plt.subplots(2, 1, figsize=(8,10))
for i, col in enumerate(category_col):
    data_train[col].value_counts().sort_values().plot.bar(ax=axes[i])
    # sns.countplot(data_train[col], ax=axes[i])
    axes[i].set_title(col+' distribution')

在这里插入图片描述

1.2 数据特征工程

数据特征工程非常非常重要,我经过这段时间的学习深刻认识到了数据特征工程的重要性,具体来说,我没经过数据特征工程直接处理最后的结果AUC为0.51(惨不忍睹对吧),做了特征工程后AUC值直接到了0.71(虽然只是粗略地模仿)。

1.2.1 处理缺失值

对EDA部分挑选出的缺失值进行填充,这里我做得处理很简单,就是直接按该属性的众数进行填充。

# 1.处理NAN值(统一用众数来填充)
data_train[train_null_col] = data_train[train_null_col].fillna(data_train[train_null_col].mode().iloc[0])
data_test[test_null_col] = data_test[test_null_col].fillna(data_test[test_null_col].mode().iloc[0])

1.2.2 处理时间数据

数据集的时间数据都是object类型的,有两种,一种是“2020/10/1”这样的,我们可以设置一个开始的时间(如2006/1/1),然后算出两者差了多少天,然后用这个整数来替代原来的属性(听起来挺麻烦的但pandas提供有现成的工具,pandasNB!!);另一种是Jan-2020这种的,这样的我们可以直接提取后四位字符然后转换成整数。

# 2.处理时间数据
# 先处理issueDate
time_end1 = pd.to_datetime(data_train['issueDate'], format='%Y/%m/%d')
time_end2 = pd.to_datetime(data_test['issueDate'], format='%Y/%m/%d')
time_sta = pd.datetime(2006,1,1)
data_train['issueDate'] = (time_end1-time_sta).dt.days
data_test['issueDate'] = (time_end2-time_sta).dt.days

# 接着处理 earliesCreditLine
for data in [data_train, data_test]:
    data['earliesCreditLine'] = data['earliesCreditLine'].apply(lambda x:int(x[-4:]))

1.2.3 对数据进行更精确的划分

有些object类型的数据(如工作年龄),是“10 years”这种的,但这显然属于数值型数据,所以我们对其进行处理。

# 2.5 之前虽然把'employmentLength'当为离散数值,但其还是字符串形式,将其处理成int形式
for data in [data_train, data_test]:
    data['employmentLength'].replace(('10+ years', '< 1 year'), ('10 years', '0 year'), inplace=True)
    data['employmentLength'] = data['employmentLength'].apply(lambda x: int(x.split()[0]))

还有些之前EDA粗糙地划分得不合理的,我们再进行划分。

# 有些类别变量category_col被分到离散变量numerical_discrete_col里了
# 因为是粗略地根据数据类型来划分的,并没有结合数据的实际情况,现在
# 从实际出发再来划分一次
cate_cols = ['homeOwnership', 'verificationStatus', 'purpose', 'regionCode']
for col in cate_cols:
    category_col.append(col)
    numerical_discrete_col.remove(col)

1.2.4 对类别变量进行处理

像某些类别变量(如Grade,其值是A,B,C这样的),我们无法直接输入模型,得转化成数值型数据,最简单的就是one-hot编码(但如果一个类别变量类别太多如2000个,则不适合用one-hot处理),有些有大小关系的类别我们可以直接映射成数字。

# 3.对类别数据进行处理
# 对"grade"这种有大小关系的属性进行自映射
category_col.remove('grade')
for data in [data_train, data_test]:
    data['grade'] = data['grade'].map({'A':1, 'B':2, 'C':3, 'D':4, 'E':5, 'F':6, 'G':7})
    data = pd.get_dummies(data, columns=category_col)
# 不知道为啥执行完上面的循环后第二句没有执行,然后我又用下面的语句执行了一遍
# data_train = pd.get_dummies(data_train, columns=category_col)
# data_test = pd.get_dummies(data_test, columns=category_col)

1.2.5 处理异常值

异常值是指那些明显不是正常产生的值,比如一个人的年龄是1000岁,这样的一条数据我们要删除掉。但有些情况下异常值是不能删除的,比如网络诈骗,骗子的数据本身就很可能是一条异常数据,比如某项属性特别大。因此还是要酌情处理,如果这种异常现象是我们想要研究的,则不能删除。

我这里用了数据分箱的方法来处理异常值,这种方法不要求数据必须近似服从正态分布,而且较为简单,这也是我选它的原因。

# 4.处理异常值
# 4.1 找到异常值(用箱形图的方法)
# 先定义要处理的属性有哪些
abnormal_values = ['loanAmnt', 'interestRate', 'installment', 'dti','delinquency_2years','revolBal','revolUtil', 'totalAcc',
                   'employmentLength', 'issueDate']

def Find_Outliers(data, fea):
    val1, val2, val3 = np.percentile(data[fea], [25, 50, 75])
    QR = val3-val1
    data[fea+'outliers'] = data[fea].apply(lambda x:'异常值' if x>(val3+1.5*QR) or x<(val1-1.5*QR) else '正常值')
    return data
# 找出异常值
data_train0 = data_train.copy()
for fea in abnormal_values:
    data_train0 = Find_Outliers(data_train0, fea)
    a = data_train0[fea+'outliers'].value_counts()
    b = data_train0.groupby(fea+'outliers')['isDefault'].sum()
    print(a)
    print(b)
    if a[0] ==  800000:
        print('正常值中的违约率:{:.3f}'.format(b[0]/a[0]))
    else:
        print('正常值中的违约率:{:.3f}'.format(b[1]/a[0]))
        print('异常值中的违约率:{:.3f}'.format(b[0]/a[1]))
    print('*'*50)

在这里插入图片描述
我们删除那些正常值和异常值中违约率差不多的属性中的异常值,因为如果某一属性的异常值中违约率明显高于正常值,则该异常值有可能是客观存在的,我觉得删除不太合适,应当保留。

# 删除那些正常值和异常值中违约率差不多的属性中的异常值
del_abnormal_values = ['loanAmnt', 'installment','revolBal','totalAcc',
                       'employmentLength', 'issueDate']
for fea in del_abnormal_values:
    data_train0 = data_train0[data_train0[fea+'outliers']=='正常值']
    
# 删除挑选异常值时加入的10列
for fea in abnormal_values:
    data_train0.drop([fea+'outliers'], axis=1, inplace=True)
# 现在得到删除完异常值后的data_train
data_train = data_train0
print("data_train的形状:{}".format(data_train.shape))

1.2.6 *数据分箱

数据分箱很重要!简单来说就是把连续数据映射为离散数据,把多变量的离散数据映射为少变量的离散数据。这么做可以降低数据的复杂度,减少噪音对数据产生的影响,提高自变量和因变量的相关性,从而使模型更加稳定。我觉得这一步骤对提升我模型的精度有很大的贡献(但我还没有做对比验证,只是觉得如此。)

# 5.做数据分箱
# 确定要分箱的属性
box_col = ['loanAmnt', 'interestRate', 'installment', 'employmentTitle', 'annualIncome',
          'issueDate', 'postCode', 'dti', 'ficoRangeLow', 'ficoRangeHigh', 'openAcc',
          'revolBal', 'revolUtil', 'totalAcc', 'earliesCreditLine', 'title']
def Box(data, feas):
    for fea in feas:
        data[fea] = pd.qcut(data[fea], 20, labels=False, duplicates='drop')
    return data
for data in [data_train, data_test]:
    data = Box(data, box_col)
# 将box_col里的属性可视化一下,看看效果
fig, axes = plt.subplots(16, 1, figsize=(50, 40))
for i,fea in enumerate(box_col):
    sns.countplot(data_train[fea], ax=axes[i])
fig.savefig(r'E:\数据分析\天池新手赛\第二次\box.png')

在这里插入图片描述

1.2.7 特征选择

当数据的属性比较多时,我们可以从中选择出一部分不太重要的特征舍弃,这么做可以提升模型的训练速度,模型的精度也基本不受影响(甚至更高)。
我用的是基于随机森林的模型来进行特征选择,原理如下:
在这里插入图片描述

# 6.特征选择(基于模型的特征选择)
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier
select = SelectFromModel(
    RandomForestClassifier(n_estimators=100, random_state=42),
    threshold='median'
)
select.fit(X_train, y_train)
X_train_new = select.transform(X_train)
data_test = select.transform(data_test)

# 补充:如何获得选择出的属性的名称
# 可用select.get_support()获得一个list=[True, False, True...],
# 然后使用pd.columns[list]得到筛选出的列名
# 训练了10分钟,先把数据存起来再说。。
np.save(r'E:\数据分析\天池新手赛\第二次\X_train.npy', X_train_new)
np.save(r'E:\数据分析\天池新手赛\第二次\y_train.npy', y_train)
np.save(r'E:\数据分析\天池新手赛\第二次\X_test.npy', data_test)

这样就只保留了一半的特征,而且经过实验模型最终的效果基本没受影响(只降低了0.001左右)。
P.s:
如果是在数学建模比赛中,可以对选择出的特征画一个协方差矩阵sns.heatmap,一是确实很有必要,二是,可视化效果很好。

1.3 构建模型

我感觉,数据预测的题花的时间最多的是在特征工程部分,其次就是在构建模型的调参部分,参数选择得好确实可以提升模型的一些精度。

1.3.1 选择模型

我这里选择的LightGBM模型,是参考别人的,而且经过百度学习了解到这也是目前竞赛界最爱用的模型之一,它在xgboost模型的基础上进行了改进,不过具体原理我也不太清楚,更多的只是作为一个工具黑箱。

# 导入特征工程后的数据
X_train = np.load(r'E:\数据分析\天池新手赛\第二次\X_train.npy')
y_train = np.load(r'E:\数据分析\天池新手赛\第二次\y_train.npy')
X_test = np.load(r'E:\数据分析\天池新手赛\第二次\X_test.npy')

X = DataFrame(X_train)
y = DataFrame(y_train)
data_test = DataFrame(X_test)

# 看下数据样子
print("X:{}".format(X_train.shape))
print("y:{}".format(y_train.shape))
print("data_test:{}".format(X_test.shape))
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X, y, shuffle=True, test_size=0.5, random_state=2020)
print("X_train:{}".format(X_train.shape))
print("y_train:{}".format(y_train.shape))
print("X_test:{}".format(X_test.shape))
print("y_test:{}".format(y_test.shape))

1.3.2 调参

调参真的比较费时间,我用的是最简单的贪心调参法,就是先确定一个参数的局部最优值,再再次基础上确定另一个参数的局部最优值,最后得到一组参数的局部最优值。
我的调参步骤是照抄这位大佬的(他的内容很棒,深入浅出!),具体过程如下:

这里是引用
第一步:学习率和迭代次数
第二步:确定max_depth和num_leaves
第三步:确定min_data_in_leaf和max_bin
第四步:确定feature_fraction、bagging_fraction、bagging_freq
第五步:确定lambda_l1和lambda_l2
第六步:确定 min_split_gain
第七步:降低学习率,增加迭代次数,验证模型

# 1.先设置一个比较大的learning_rate=0.1,确定n_estimatoes的取值=564
params = {    
          'boosting_type': 'gbdt',
          'objective': 'binary',
          'metric': 'auc',
          'nthread':4,
          'learning_rate':0.1,
          'num_leaves':30, 
          'max_depth': 5,   
          'subsample': 0.8, 
          'colsample_bytree': 0.8, 
    }
data_train = lgb.Dataset(X, y)
cv_results = lgb.cv(params, data_train, num_boost_round=1000, nfold=5, stratified=False, shuffle=True, metrics='auc',early_stopping_rounds=50,seed=0)
print('best n_estimators:', len(cv_results['auc-mean']))
print('best cv score:', pd.Series(cv_results['auc-mean']).max())
# num_leaves
from sklearn.model_selection import cross_val_score
num_leaves = range(5, 100, 5)
best_leaves = {}
for i, leaves in enumerate(num_leaves):
    model = LGBMRegressor(objective='binary',learning_rate=0.1,num_leaves=leaves)
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    print("ronud",i+1,":",score)
    best_leaves[leaves] = score
print(best_leaves)
# max_depth
leaves = max(best_leaves.items(), key=lambda x:x[1])[0] # leaves=70
depth_range = range(3, 12, 1)
best_max_depth = {}
for i, depth in enumerate(depth_range):
    model = LGBMRegressor(objective='binary',learning_rate=0.1,num_leaves=leaves, max_depth=depth)
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    print("ronud",i+1,":",score)
    best_max_depth[depth] = score
print(best_max_depth)
# min_data_in_leaf
depth = max(best_max_depth.items(), key=lambda x:x[1])[0] # depth=7
params = range(1, 200, 10)
best_min_data_in_leaf = {}
for i, leaf in enumerate(params):
    model = LGBMRegressor(objective='binary',learning_rate=0.1,num_leaves=leaves, max_depth=depth, min_data_in_leaf=leaf)
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    print("ronud",i+1,":",score)
    best_min_data_in_leaf[leaf] = score
print(best_min_data_in_leaf)
# max_bin
leaf = max(best_min_data_in_leaf.items(), key=lambda x:x[1])[0] # leaf=171
params = range(5, 200, 10)
best_max_bin = {}
for i, bins in enumerate(params):
    model = LGBMRegressor(objective='binary',learning_rate=0.1,num_leaves=leaves, max_depth=depth, min_data_in_leaf=leaf, max_bin=bins)
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    print("ronud",i+1,":",score)
    best_max_bin[bins] = score
print(best_max_bin)
# feature_fraction
bins = max(best_max_bin.items(), key=lambda x:x[1])[0] # bins=45
params = [0.6,0.7,0.8,0.9,1.0]
best_feature_fraction = {}
for i, ff in enumerate(params):
    model = LGBMRegressor(objective='binary',learning_rate=0.1,num_leaves=leaves, max_depth=depth, min_data_in_leaf=leaf, max_bin=bins,feature_fraction=ff)
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    print("ronud",i+1,":",score)
    best_feature_fraction[ff] = score
print(best_feature_fraction)
# bagging_fraction
ff = max(best_feature_fraction.items(), key=lambda x:x[1])[0] # ff=0.6
params = [0.6,0.7,0.8,0.9,1.0]
best_bagging_fraction = {}
for i, bf in enumerate(params):
    model = LGBMRegressor(objective='binary',learning_rate=0.1,num_leaves=leaves, max_depth=depth, min_data_in_leaf=leaf, max_bin=bins,feature_fraction=ff, bagging_fraction=bf)
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    print("ronud",i+1,":",score)
    best_bagging_fraction[bf] = score
print(best_bagging_fraction)
# bagging_freq
bf = max(best_bagging_fraction.items(), key=lambda x:x[1])[0] # bf=0.6
params = range(0,81,10)
best_bagging_freq = {}
for i, bfq in enumerate(params):
    model = LGBMRegressor(objective='binary',learning_rate=0.1,num_leaves=leaves, max_depth=depth, min_data_in_leaf=leaf, max_bin=bins,feature_fraction=ff, bagging_fraction=bf, bagging_freq=bfq)
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    print("ronud",i+1,":",score)
    best_bagging_freq[bfq] = score
print(best_bagging_freq)
# lambda_l1
bfq = max(best_bagging_freq.items(), key=lambda x:x[1])[0] # bfq=0
params = [1e-5,1e-3,1e-1,0.0,0.1,0.3,0.5,0.7,0.9,1.0]
best_l1 = {}
for i, l1 in enumerate(params):
    model = LGBMRegressor(objective='binary',learning_rate=0.1,num_leaves=leaves, max_depth=depth, min_data_in_leaf=leaf, max_bin=bins,feature_fraction=ff, bagging_fraction=bf, bagging_freq=bfq, lambda_l1=l1)
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    print("ronud",i+1,":",score)
    best_l1[l1] = score
print(best_l1)
# lambda_l2
l1 = max(best_l1.items(), key=lambda x:x[1])[0] # l1=0.3
params = [1e-5,1e-3,1e-1,0.0,0.1,0.3,0.5,0.7,0.9,1.0]
best_l2 = {}
for i, l2 in enumerate(params):
    model = LGBMRegressor(objective='binary',learning_rate=0.1,num_leaves=leaves, max_depth=depth, min_data_in_leaf=leaf, max_bin=bins,feature_fraction=ff, bagging_fraction=bf, bagging_freq=bfq, lambda_l1=l1, lambda_l2=l2)
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    print("ronud",i+1,":",score)
    best_l2[l2] = score
print(best_l2)
# min_split_gain
l2 = max(best_l2.items(), key=lambda x:x[1])[0] # l2=0.001
params = [0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]
best_msg = {}
for i, msg in enumerate(params):
    model = LGBMRegressor(objective='binary',learning_rate=0.1,num_leaves=leaves, max_depth=depth, min_data_in_leaf=leaf, max_bin=bins,feature_fraction=ff, bagging_fraction=bf, bagging_freq=bfq, lambda_l1=l1, lambda_l2=l2, min_split_gain=msg)
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    print("ronud",i+1,":",score)
    best_msg[msg] = score
print(best_msg)

开始训练

# 降低学习率,增加迭代次数,训练模型
def makelgb():
    lgbr = LGBMRegressor(objective='binary',
                         learning_rate=0.01,
                         n_estimators=1000,
                         num_leaves=70,
                         max_depth=7,
                         min_data_in_leaf=171,
                         max_bin=45,
                         feature_fraction=0.6,
                         bagging_fraction=0.6,
                         bagging_freq=0,
                         lambda_l1=0.3,
                         lambda_l2=0.001,
                         min_split_gain=0.0
                        )
    return lgbr
kf = KFold(n_splits=10, shuffle=True, random_state=42)
scores = []
lgbr = makelgb()
for train_idx, test_idx in kf.split(X):
    Xtrain = X.iloc[train_idx]
    ytrain = y.iloc[train_idx]
    Xtest = X.iloc[test_idx]
    ytest = y.iloc[test_idx]
    lgbr.fit(Xtrain, ytrain)
    fpr, tpr, thresholds = roc_curve(ytest, lgbr.predict(Xtest))
    score = auc(fpr, tpr)
    scores.append(score)
print("scores情况:{}".format(scores))
print(np.mean(scores))
lgbr.fit(X_train, y_train)
proba = lgbr.predict(X_test)
result2 = DataFrame({'isDefault':proba}, index=data_test.index)
result2.to_csv(r"E:\数据分析\天池新手赛\第二次\result123.csv")

总结

这次比赛让我对数据挖掘比赛的整个结构框架有了大体的了解,以前真的是对整个框架一头雾水。但还有很多东西都只是照葫芦画瓢,会用却不深入,还有很多东西需要学。听大佬说模型融合可以有效提高最终结果,但我不会,还是需要多积累。就这样了:)

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SinHao22

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值