计算机系统应用教程网站

网站首页 > 技术文章 正文

LC建模历史最详细(三 特征处理)

btikc 2024-09-03 11:33:10 技术文章 15 ℃ 0 评论

在LC建模历史最详细(二 评估+清洗) 中,对数据进行整体评估,并对各个列的关键指标值及分布进行了统计和可视化展示。

本章主要内容还是特征处理,整体处理上偏重于列填充、列转换、类型转换、数值化;重点对部分列进行众数填充、归一化、聚类处理、交叉关联、变量衍生、极差、变异系数、四分位等。完成本章节后基本实现数据的列与关键指标的相关性、数据化。归一化、分箱,样本平衡在下一个章节。

  1. 本章节中需要对特征列,先评估列的业务意义、重要性、与重要指标的关联性、数值分布、空值填充(特征处理思路)。
  2. 本文中的可视化及关键处理,均做了组件化封装,方便后续复用。


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))

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表