在LC建模历史最详细(二 评估+清洗) 中,对数据进行整体评估,并对各个列的关键指标值及分布进行了统计和可视化展示。
本章主要内容还是特征处理,整体处理上偏重于列填充、列转换、类型转换、数值化;重点对部分列进行众数填充、归一化、聚类处理、交叉关联、变量衍生、极差、变异系数、四分位等。完成本章节后,基本实现数据的列与关键指标的相关性、数据化。归一化、分箱,样本平衡在下一个章节。
- 本章节中需要对特征列,先评估列的业务意义、重要性、与重要指标的关联性、数值分布、空值填充(特征处理思路)。
- 本文中的可视化及关键处理,均做了组件化封装,方便后续复用。
if 'dataClrAndPre' in stage:
print("三、数据评估-特征转换")
start_time = time.time()
o_ml.null_chart(df, 'start', base_dir)
dict_list = o_lc.dict_list
'''
列填充(众数):(定位缺失值列,利用众数添加)
由于接下来将用到逻辑回归模型,它对特征线性相关性较敏感,所以尽管用其它变量拟合缺失值对缺失值的填充会更符合实际情况,也没有采用这种方法。
为什么使用众数填充而不是用中位数或是均值填充?因为众数对于数值型变量和字符型变量都适用,而且也有统计意义。
求极差、平均数、中位数、众数与方差
'''
print("1、空值填充:文字-众数填充,数字-平均值填充") # 数字转换,便于后续数字化分析
to_fit_with_mode = ['emp_title', 'emp_length'] # 众数填充
for i in to_fit_with_mode:
print(o_utils.tab() + i + "-before:" + str(df[i].isnull().sum(axis=0) / df.shape[0]))
# val = df[i].value_counts().index.values[0] #众数分析较慢 val = mode(df[i][df[i].notnull()])[0][0] # 原始填充方式
# df[i] = df[i].apply(lambda x: val if pd.isna(x) else x) # 注意赋值
if str(df[i].dtype) in 'int32,int64,float64':
df[i] = SimpleImputer(strategy="median").fit_transform(df[i].values.reshape(-1, 1)) # 数值类型-中位数填充
else:
df[i] = SimpleImputer(strategy="most_frequent").fit_transform(df[i].values.reshape(-1, 1)) # object类型-众数填充
print(o_utils.tab() + i + "-after:" + str(df[i].isnull().sum(axis=0) / df.shape[0]))
print("2、格式转换,分离object中的字符串和单位等表示,还有数字及日期") # 数字转换,便于后续数字化分析
"""
a、数据提取
b、有序变量-OrdinalEncoder、名义变量-OneHotEncoder哑变量
c、离散特征-独热编码OneHotEncoder(均值为0,方差为1)
"""
# df.iloc[:,0]=LabelEncoder().fit_transform(df.iloc[:,0]) # 首列标签化编码
# temp=OneHotEncoder().fit_transform(df).toarray() #离散--独热编码
# df=temp.iloc[:,1:] # 哑变量影响,去除首列
df['open_acc'] = df['open_acc'].astype('float') # 注意赋值
df['term'] = df['term'].apply(lambda x: str(x).replace('months', '')).astype('float') # 注意赋值
df['int_rate'] = df['int_rate'].apply(lambda x: str(x).replace('%', '')).astype('float') # 注意赋值
# df['int_rate'] = df['int_rate'].apply(lambda x: float(x[:-1])) # 替换/正则替换、截取、split都可以np.int8(s.split()[0])
df['earliest_cr_line'] = df['earliest_cr_line'].apply(lambda x: datetime.strptime(str(x), '%b-%Y')) # 注意赋值
df['issue_d'] = df['issue_d'].apply(lambda x: datetime.strptime(str(x), '%b-%Y')) # 注意赋值
df['emp_length'] = df.emp_length.str.replace('years', ' ').str.strip()
df['emp_length'] = df.emp_length.str.replace('year', ' ').str.strip()
# 支持数组replace(['NONE', 'ANY'], 'OTHER', inplace=True)
df['emp_length'] = df.emp_length.replace({'10+': '10', '< 1': '0', 'n/a': '-1'}).astype('float64')
df['emp_title'] = df['emp_title'].apply(lambda x: o_lc.emp_classfiy(x))
df['addr_state_inc'] = df['addr_state'].apply(lambda x: o_lc.addr_classfiy(x))
# 空值处理
# null_cols = [i for i in data.columns if data[i].dtype == "object"]
# data[null_cols] = data[null_cols].fillna("vacanct")
# null_cols = [i for i in data.columns if data[i].dtype == "float"]
# data[null_cols].isnull().sum().sort_values(ascending=False)
# df[null_cols] = SimpleImputer(strategy="median").fit_transform(null_cols) # 数值-平均数填充
print("3、聚类分析,object或者数值中,分组标签较多的列,需要聚类分析")
big_groups_cols = o_ml.get_cols(df, 'O,object,float64', groups_min=10,
groups_max=lisan_cols_point) # 提取分组数介于10,离散上限之间的列
print("离散变量中>10的,支持聚类分析的列: \n{}".format(big_groups_cols))
print("3.1、借款人州地址分类(k-means分片聚类):")
df_state_temp = df[['addr_state', 'addr_state_inc']]
df_state_temp = df_state_temp.reset_index(drop=True)
# df_state_temp.rename(columns={'index':'variable'}, inplace=True) # 支持重命名列标签tail
train_x_1 = df_state_temp.loc[:, 'addr_state_inc'].to_frame() # 重建新dataframe 追加列然后进行分析
train_x_1 = MinMaxScaler().fit_transform(train_x_1)[0:6000] # 归一化,统一量纲
# print(pd.concat((df_state_temp,pd.DataFrame(train_x_1)),axis = 1,ignore_index=True)) # 拼装归一化后的数据
better_k = o_ml.clustering_analysis_K('addr_state', train_x_1, 9, base_dir) # 聚类分析获取最佳K值-tag,data,K轮循
o_ml.gen_wordcloud(df, 'addr_state', base_dir) # 词云图
result = o_ml.clustering_analysis_scatter('addr_state', train_x_1, better_k, base_dir) # addr_state已做人工7分类,聚类效果不明显
# print(result) # print转散点图 观测分布情况
print(o_utils.tab() + "addr_state 输出结果中并没有看出不同群体有什么共性")
print("4、 特征编码:")
print(o_utils.spaces(4) + "逻辑回归和随机森林模型不接受字符型变量,因此需要将对此类变量进行编码。")
print(o_utils.spaces(4) + "类别标签法,哑变量编码法(对类别变量取哑变量)等等。考虑到评分卡模型的简洁性,在此选用类别标签法。")
print("5、 归一化处理:(深入学习,参考聚类分析部分的归一化处理,主要为降低峰值,达到均值为0,方差为1)")
print(o_utils.spaces(4) + "逻辑回归模型基于线性回归,求参需要用到梯度下降法,为了加快迭代速度,不同特征的变化范围规模相差不宜过大,如果用数值直接带入逻辑回归模型,必须进行变量缩放。"
"但是本文是用逻辑回归建立评分卡,会将数值变量进行分箱,所以这一步可以省略。")
print("6、 警惕数据泄露(不恰当特征导致的泄露/不恰当的交叉验证策略导致泄露):跳过")
print(o_utils.spaces(4) + "1)、不恰当特征导致的泄露:(所有特征中,一旦在目标属性出现后,会随之更新或出现的属性,属于会泄露信息的属性,)")
leak_feas = ['sub_grade', 'title', 'zip_code', 'recoveries', 'last_pymnt_amnt', 'funded_amnt', 'funded_amnt_inv',
'total_pymnt', 'total_pymnt_inv',
'total_rec_prncp', 'total_rec_int', 'desc']
for i in leak_feas:
if i in df.columns:
df.drop(i, axis=1, inplace=True)
print(o_utils.spaces(4) + "2)、尽量保证验证集数据的纯粹,不要让它参与到训练集的处理和模型构建当中,这意味着,要在预处理之前分割训练集和测试集。)")
print("7、目标特征分布:")
print(df.loan_status.value_counts())
print("7.1、钻取多元素之间的交叉关系:借款用途和利率、")
o_ml.two_factors_chart(df, "int_rate", "purpose", base_dir)
o_ml.multiple_factors_chart(df, ['int_rate', 'term', 'emp_length'], "loan_status", base_dir, size=3)
print("8、两两特征的协方差:")
o_ml.corr_chart(df, None, base_dir)
print("9、衍生变量:")
df["cre_hist"] = ((df["issue_d"] - df["earliest_cr_line"]) / 30).dt.days
df.drop(["issue_d", "earliest_cr_line"], axis=1, inplace=True)
print("10、业务分布,count/sum/sort,支持先过滤再定分布,或者直接分组画图")
badloanDf = df[df['loan_condition'] == 'Bad Loan'] # 整理出坏账数据
badloanDf = badloanDf.sort_values(by='grade', ascending=True)
df3 = badloanDf.groupby(by=['emp_length'])['loan_condition'].count()
# df.groupby(by='loan_status')['loan_amnt'].describe()
# 目前使用分类编码直接编码,可考虑使用热独码OneHotCode进行编码,二选一
df = df.replace(dict_list)
# df = o_ml.onehotCode(df,["home_ownership", "purpose"]) # 热独码处理
# data = pd.get_dummies(data, columns=['zip_code'], drop_first=True) # get_dummies 也可以进行热独码处理。
df.drop(['id', 'loan_status', 'addr_state', 'loan_condition'], axis=1, inplace=True)
df['home_ownership'].astype(int)
print("11、 单行数据:")
print(o_ml.getrow(df, 4, data_disc))
print("12、 单列数据emp_length:")
list_view = df['emp_length'].describe() # 使用describe函数输出计算结果
list_view.loc['jicha'] = list_view.loc['max'] - list_view.loc['min'] # 求极差
list_view.loc['bianyixishu'] = list_view.loc['std'] / list_view.loc['mean'] # 变异系数
list_view.loc['sifenweijianju'] = list_view.loc['75%'] - list_view.loc['25%'] # 四分位间距
print(list_view)
print("13、 空值列排序:")
print(df.isnull().sum().sort_values(ascending=False))
o_ml.null_chart(df, 'end', base_dir) # 缺失值可视化,
# 扩展: 若含有缺失值,常量填充fillna
# 扩展: 极端值处理
df.to_pickle(file_lcs)
print('df=' + str(df.shape))
end_time = time.time()
print("耗时: {:.2f}秒".format(end_time - start_time))
本文暂时没有评论,来添加一个吧(●'◡'●)