- 1.特征构建
- 1.1 特征延伸
- 1.1.1 类别特征编码
- 1.1.2 时间特征处理思路
- 1.1.3 特征延伸思路
- 2 特征评价
- 2.1 常见指标
- 2.1.1 IV值
- 2.1.2 PSI
- 2.1.3 特征重要性
对于离散特征来说,一般编码后才可输入模型,常见的编码方法如下:
● one-hot编码
将一列文本数据转化成一列或多列只有0和1的数据,如性别取值有男生、女生两种,那one-hot后,男对应的编码为1 0,女对应的编码为0 1
● label encoding
将一列文本数据转化成数值,例如,[red, blue, red, yellow] = [0,2,0,1]
注意事项:
● 当特征数量比较多时,one-hot会造成维度爆炸
● 当类别取值相互独立时优先使用one-hot编码
● 时间戳本身特征
直接使用Pandas的series提取时间戳特征,比如说哪年、哪季度、哪月、哪周、哪日、哪时、哪分、哪秒、年里的第几天、月里的第几天、周里的第几天。
● 0-1特征
一般是与真实场景结合来用,比如说工作日、周末、公众假日(春节、端午节、中秋节等)、X初、X中、X末(X代表年、季度、月、周)、特殊节日(如运营暂停、服务暂停)、日常习惯叫法(如清晨、上午、中午、下午、傍晚、夜晚、深夜、凌晨),从而可以衍生出:
○ 是否工作日
○ 是否春节
○ 是否月初
○ 是否服务期外
○ 是否凌晨
○ 等等等等
● 时间差特征
一般也是与真实场景结合来用,比如说工作日、周末等等,比如:
○ 距离春节还有N天
○ 距离周末还有N天
○ 举例下月初还有N天
○ 等等等等
思路一:特征=时间周期+一个或多个修饰词(维度)+原子指标+聚合函数,如30天内xxapp的理财金额总和,其中30天为时间周期,xxapp为维度,理财金额为原子指标,总和为聚合函数。
如:【近1/3/7天】/【近3/7/30天】的【医疗类消费】【均值、累计值、计数】。
● 原子指标:原子指标和度量含义相同,基于某一业务事件行为下的度量,是业务定义中不可再拆分的指标,具有明确业务含义的名词 ,如支付金额。原子指标描述的其实是一种指标的类型,比如授信金额,已用额度等
● 时间周期:不同的时间切片长度,例如近1个月,近3个月,最近一次,最远一次等
● 修饰词(维度):维度是描述事情的角度 ,依赖于指标,如性别,地区,所属机构等
● 聚合函数:聚合函数对一组值执行计算并返回单一的值,例如求和,均值,方差,最大值,最小值,计数等
思路二:特征之间的四则运算,如商品在过去一段时间内点击量在整体的占比/上周商品点击量和本周商品点击量的差值/最近6个月内,最近一次消费到现在的月份数等
思路三:特征之间做比较,如消费金额的排名、地区热门购买产品排行榜等
通过评价指标进行特征筛选,以减少无意义的特征,减少入模特征数量,提高建模代码运行速度,提高建模效率。
2.1 常见指标 2.1.1 IV值刻画了一个特征对好坏用户分布的区分程度
∑
i
=
1
N
(
g
o
o
d
%
−
b
a
d
%
)
∗
l
n
(
g
o
o
d
%
/
b
a
d
%
)
\sum_{i=1}^N(good\%-bad\%)*ln(good\%/bad\%)
∑i=1N(good%−bad%)∗ln(good%/bad%),其中N为箱子个数,good%是这个箱中的优质客户占所有特征中所有优质客户的比例,bad%是这个箱子里的坏客户占整个特征中所有坏客户的比例。一般选择IV>0.02的特征
import numpy as np
import pandas as pd
import copy
def cut_width(df, inputcol, labelcol='label', bins=10):
"""
等宽分箱
:param dataset: DataFrame,计算数据
:param inputcol: String,待分箱列列名
:param labelcol: String,目标列列名
:param bins: int,正整数,分箱数
:return:
df: DataFrame,分箱后结果
"""
df[inputcol] = pd.qcut(x=df[inputcol], q=bins)
df = pd.crosstab(index=df[inputcol], columns=df[labelcol], margins=False)
df.columns = ['neg','pos']
return df
def calculate_woe_iv(dataset):
"""
对分箱后的特征计算WOE和IV
:param dataset:DataFrame,计算数据,需要在特征分箱后的数据
:return:
iv: float,iv值
df:DataFrame,woe和IV计算后结果
"""
df = copy.copy(dataset)
df['pos_rate'] = (df['pos'] + 1) / df['pos'].sum() # 计算每个分组内的响应(Y=1)占比,加1为了防止在计算woe时分子分母为0
df['neg_rate'] = (df['neg'] + 1) / df['neg'].sum() # 计算每个分组内的未响应(Y=0)占比
df['woe'] = np.log(df['pos_rate'] / df['neg_rate']) # 计算每个分组的WOE
df['iv'] = (df['pos_rate'] - df['neg_rate']) * df['woe'] # 计算每个分组的IV
iv = df['iv'].sum()
return iv, df
if __name__ == '__main__':
data = pd.DataFrame({'uid': list(range(10)), 'label': [0, 0, 1, 1, 0, 1, 0, 0, 0, 1], 'f1': list(range(3, 13))})
w = cut_width(data,'f1',bins=4)
iv,df = calculate_woe_iv(w)
print(iv)
2.1.2 PSI
用于衡量测试集和训练集直接数据分布差异性,是模型稳定性的常见指标,psi过高表示在不同数据集上特征分布表现相差过大,无需入模
∑
i
=
1
N
(
A
c
t
u
a
l
%
−
E
x
p
e
c
t
e
d
%
)
∗
l
n
(
A
c
t
u
a
l
%
/
E
x
p
e
c
t
e
d
%
)
\sum_{i=1}^N(Actual\%-Expected\%)*ln(Actual\%/Expected\%)
∑i=1N(Actual%−Expected%)∗ln(Actual%/Expected%),其中,N是分箱数量,Actual是实际占比,Expected是预期占比。一般来说,放弃PSI大于0.25的特征。
import pandas as pd
import numpy as np
def cal_psi(actual, predict, bins=10):
"""
功能: 计算PSI值,并输出实际和预期占比分布曲线
:param actual: Array或series,代表训练集特征A分数
:param predict: Array或series,代表测试集特征A分数
:param bins: 箱数
:return:
psi: float,PSI值
psi_df:DataFrame
"""
actual_min = actual.min() # 训练集中的最小值
actual_max = actual.max() # 训练集中的最大值
binlen = (actual_max - actual_min) / bins
cuts = [actual_min + i * binlen for i in range(1, bins)]#设定分组
cuts.insert(0, -float("inf"))
cuts.append(float("inf"))
actual_cuts = np.histogram(actual, bins=cuts)#将actual等宽分箱
predict_cuts = np.histogram(predict, bins=cuts)#将predict按actual的分组等宽分箱
actual_df = pd.DataFrame(actual_cuts[0],columns=['actual'])
predict_df = pd.DataFrame(predict_cuts[0], columns=['predict'])
psi_df = pd.merge(actual_df,predict_df,right_index=True,left_index=True)
psi_df['actual_rate'] = (psi_df['actual'] + 1) / psi_df['actual'].sum()#计算占比,分子加1,防止计算PSI时分子分母为0
psi_df['predict_rate'] = (psi_df['predict'] + 1) / psi_df['predict'].sum()
psi_df['psi'] = (psi_df['actual_rate'] - psi_df['predict_rate']) * np.log(
psi_df['actual_rate'] / psi_df['predict_rate'])
psi = psi_df['psi'].sum()
return psi, psi_df
2.1.3 特征重要性
对于lightgbm.feature_importance(importance_type=‘split’)可输出特征的重要度排名,其中importance_type可选split和gain两种,split(默认)表示特征在所有树中作为划分属性的次数,gain表示特征在作为划分属性时总loss降低量。
print(pd.DataFrame({
'column': feature_names,
'importance': lgb_trained_model.feature_importance(),
}).sort_values(by='importance'))
通过以上代码可得到特征重要度的排名,可根据需要,选择topN的特征
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)