feature_utils.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. # -*- coding:utf-8 -*-
  2. """
  3. @author: yq
  4. @time: 2023/12/28
  5. @desc: 特征工具类
  6. """
  7. import pandas as pd
  8. from sklearn.preprocessing import KBinsDiscretizer
  9. from entitys import DataSplitEntity
  10. from enums import BinsStrategyEnum
  11. import toad as td
  12. def f_get_bins(data: DataSplitEntity, feat: str, strategy: str='quantile', nbins: int=10) -> pd.DataFrame:
  13. # 等频分箱
  14. if strategy == BinsStrategyEnum.QUANTILE.value:
  15. kbin_encoder = KBinsDiscretizer(n_bins=nbins, encode='ordinal', strategy='quantile')
  16. feature_binned = kbin_encoder.fit_transform(data[feat])
  17. return feature_binned.astype(int).astype(str)
  18. # 等宽分箱
  19. if strategy == BinsStrategyEnum.WIDTH.value:
  20. bin_width = (data.train_data()[feat].max() - data.train_data()[feat].min()) / nbins
  21. return pd.cut(data.train_data()[feat], bins=nbins, labels=[f'Bin_{i}' for i in range(1, nbins + 1)])
  22. # 使用toad分箱
  23. '''
  24. c = td.transfrom.Combiner()
  25. # method参数需要根据toad指定的几种方法名称选择
  26. c.fit(data, y = 'target', method = strategy, min_samples=None, n_bins = nbins, empty_separate = False)
  27. # 返回toad分箱combiner,用于训练集和测试集的分箱
  28. # 可使用c.export()[feature]查看某一特征的分箱临界值
  29. return c
  30. '''
  31. # 此函数入参应为scorecardpy进行woebin函数转换后的dataframe
  32. def f_get_bins_display(bins_info: pd.DataFrame) -> pd.DataFrame:
  33. df_list = []
  34. for col, bin_data in bins_info.items():
  35. tmp_df = pd.DataFrame(bin_data)
  36. df_list.append(tmp_df)
  37. result_df = pd.concat(df_list, ignore_index = True)
  38. total_bad = result_df['bad'].sum()
  39. total_cnt = result_df['count'].sum()
  40. # 整体的坏样本率
  41. br_overall = total_bad / total_cnt
  42. result_df['lift'] = result_df['badprob'] / br_overall
  43. result_df = result_df.sort_values(['total_iv', 'variable'], ascending=False).set_index(['variable','total_iv','bin'])\
  44. [['count_distr','count','good','bad','badprob','lift','bin_iv','woe']]
  45. return result_df.style.format(subset=['count','good','bad'], precision=0).format(subset=['count_distr','bad','lift',
  46. 'badprob','woe','bin_iv'],precision=4).bar(subset=['badprob','bin_iv','lift'],color=['#d65f58','#5fbb7a'])
  47. def f_get_woe(data: DataSplitEntity, c: td.transform.Combiner, to_drop:list) -> pd.DataFrame:
  48. transer = td.transform.WOETransformer()
  49. # 根据训练数据来训练woe转换器,并选择目标变量和排除变量
  50. train_woe = transer.fit_transform(c.transform(data.train_data()), data.train_data()['target'],exclude=to_drop+['target'])
  51. test_woe = transer.transform(c.transfrom(data.test_data()))
  52. oot_woe = transer.transform(c.transform(data.val_data()))
  53. return train_woe, test_woe, oot_woe
  54. def f_get_iv(data: DataSplitEntity) -> pd.DataFrame:
  55. # 计算前,先排除掉不需要计算IV的cols
  56. return td.quality(data, 'target',iv_only=True)
  57. def f_get_psi(train_data: DataSplitEntity, oot_data: DataSplitEntity) -> pd.DataFrame:
  58. # 计算前,先排除掉不需要的cols
  59. return td.metrics.PSI(train_data, oot_data)
  60. def f_get_corr(data: DataSplitEntity, meth: str='spearman') -> pd.DataFrame:
  61. return data.train_data().corr(method=meth)
  62. def f_get_ivf(data: DataSplitEntity) -> pd.DataFrame:
  63. pass