7. 特征工程

1.时间特征的常见处理

1.1 使用dt直接创建新特征

假设有一个dataframe名为df,其中某一列(datetime_column)的数据为datetime格式,现在用这一列来构建一些常见的特征(新列)。比如Year, Week of year, Month, Day of week, Weekend(是否为周末), Hour等。

# 示例1
# 新增一列,列名为year,下同
df.loc[:, 'year'] = df['datetime_column'].dt.year
df.loc[:, 'weekofyear'] = df['datetime_column'].dt.weekofyear
df.loc[:, 'month'] = df['datetime_column'].dt.month
df.loc[:, 'dayofweek'] = df['datetime_column'].dt.dayofweek
# 求该时间是第几个工作日,>= 5返回true
df.loc[:, 'weekend'] = (df['datetime_column'].dt.weekday >= 5).astype(int)
df.loc[:, 'hour'] = df['datetime_column'].dt.hour
# 示例2
import pandas as pd

# 创建一个关于datetime的series,间隔为10小时
s = pd.date_range('2020-01-06', '2020-01-10', freq='10H').to_series()


# 基于datetime创建一些特征
features = {
    "dayofweek": s.dt.dayofweek.values,
    "dayofyear": s.dt.dayofyear.values,
    "hour": s.dt.hour.values,
    "isleapyear": s.dt.is_leap_year.values,  # 是否是闰年
    "quarter": s.dt.quarter.values, # 是哪个季节
}

# s
# s.dt.hour
# features["hour"]

1.2构建分组聚合的特征

# 利用分组和聚合函数,可以在dataframe上创建很多新的特征

# 在df上创建新特征
def generate_features(df):
    # 用date列创建一系列特征
    df.loc[:, 'year'] = df['date'].dt.year
    df.loc[:, 'weekofyear'] = df['date'].dt.weekofyear
    df.loc[:, 'month'] = df['date'].dt.month
    df.loc[:, 'dayofweek'] = df['date'].dt.dayofweek
    df.loc[:, 'weekend'] = (df['date'].dt.weekday >= 5).astype(int)
    
    # 创建一个聚合字典,下面的聚合都是在基于customer_id分组的基础上
    aggs = {}
    # 对于月份的聚合,计算每个customer的不同月份数和月份的均值
    aggs['month'] = ['nunique', 'mean']
    aggs['weekofyear'] = ['nunique', 'mean']
    
    # 对num1列进行聚合,计算分组后这一列的和,最大值,最小值和均值
    aggs['num1'] = ['sum', 'max', 'min', 'mean']
    
    # 对customer_id本身,计算出现的总次数count
    aggs['customer_id'] = ['size']
    
    # 对customer_id分组,然后进行聚合
    agg_df = df.groupby('customer_id').aggs(aggs)
    agg_df = agg_df.reset_index()
    return agg_df

1.3 当特征值为列表时构建新特征的方法

有时候,比如在处理时间序列问题的时候,你会遇到一个特征的值不是一个单独的值,而是一个列表包含多个值的情况。比如一个客户在给定时间内的交易情况,这个特征可能会有多个值。这时候,可以根据列表的值创建很多新的特征:比如mean,max,min,unique,skew,kurtosis,kstat,percentile,quantile,pear to peak等等。

# 运用一些简单的numpy函数,就可以根据列表的值创建新特征
import numpy as np

feature_dict = {}
#x = [i for i in range(10)]

feature_dict['mean'] = np.mean(x)
feature_dict['max'] = np.max(x)
feature_dict['min'] = np.min(x)
feature_dict['std'] = np.std(x)
feature_dict['var'] = np.var(x)
feature_dict['ptp'] = np.ptp(x)

# 计算百分位数
feature_dict['percentile_10'] = np.percentile(x, 10)
feature_dict['percentile_60'] = np.percentile(x, 60)
feature_dict['percentile_90'] = np.percentile(x, 90)

# 分位数
feature_dict['quantile_5'] = np.percentile(x, 5)
feature_dict['quantile_95'] = np.percentile(x, 95)
feature_dict['quantile_99'] = np.percentile(x, 99)

有一个叫tsfresh的库可以用来处理这种特征(时间序列)。

from tsfresh.feature_extraction import feature_calculators as fc

feature_dict = {}
# 基于tsfresh的特征
feature_dict['abs_energy'] = fc.abs_energy(x)
feature_dict['count_above_mean'] = fc.count_above_mean(x)
feature_dict['count_below_mean'] = fc.count_below_mean(x)
feature_dict['mean_abs_change'] = fc.mean_abs_change(x)
feature_dict['mean_change'] = fc.mean_change(x)

2. 创建多项式特征 & 特征分箱 & 对数转换

2.1 创建多项式特征

一个简单的生成新特征的方法是创建多项式特征(polynomial features)。比如,关于两个特征a和b的二次多项式特征有a,b,ab,a^2, b^2。

import numpy as np
import pandas as pd

# 随机生成一个100行2列的dataframe
df = pd.DataFrame(
    np.random.rand(100, 2),
    columns=[f"f_{i}" for i in range(1, 3)]
)
df
# 根据sklearn的PolynomialFeatures生成二次多项式特征
from sklearn import preprocessing

# 初始化多项式特征类对象,关于2次多项式的
pf = preprocessing.PolynomialFeatures(
    degree=2,
    interaction_only=False,
    include_bias=False
)

poly_feats = pf.fit_transform(df)

# 等同于先fit后transform的效果
# pf.fit(df)
# poly_feats = pf.transform(df)

# 创建一个包含所有特征的dataframe
num_feats = poly_feats.shape[1]
df_transformed = pd.DataFrame(
    poly_feats,
    columns=[f"f_{i}" for i in range(1, num_feats+1)]
)
df_transformed

2.2 特征分箱

特征分箱是一种把连续型的数值特征转换为离散型的类别特征的方法。

# 创建数值型特征的分箱
# 分成10箱和100箱
df['f_bin_10'] = pd.cut(df['f_1'], bins=10, labels=False)
df['f_bin_100'] = pd.cut(df['f_1'], bins=100, labels=False)
df

2.3 对数转换(log_transformation)

另一个有趣的特征变换类型是对数转换(log transformation),下面构造的f_3方差很大,相对来说其他特征方差很小。我们可以对f_3进行对数转换来减小它的方差。转换方法是log(1+x)。

# 构造f_3列
df['f_3'] = pd.Series(np.random.randint(0, 10000, (100, )))
# 转换前方差
df.f_3.var()
# 结果为:8983721.01

转换前数据分布:
转换前分布

# 对f_3列进行对数转换
df['f_3'] = df['f_3'].apply(lambda x: np.log(1 + x))
# 转换后方差
df.f_3.var()
# 结果为:0.89

转换后数据分布:
在这里插入图片描述
可以看到,进行对数转换后f_3列的方差从8983721变为0.89。

3. 缺失值处理

对于类别型特征,一般把缺失值当成一个新类即可。
对于数值型特征,一个方法是用一个未出现的值比如0来填充该特征所有的缺失值,但这种方法效果不佳。一般比较常见的方法是用该特征的均值填充缺失,也有用中位数或者众数填充的。

一个比较新奇的方法是knn:对于一个有缺失值的样本,找到最近的k个样本,用这k个样本的均值来填充缺失值。
下面的代码就是用knn方法来填充缺失值的案例。

import numpy as np
from sklearn import impute

# 创建一个包含10个样本和6个特征的整数数组
X = np.random.randint(1, 15, (10, 6))
# 转化成浮点数
X = X.astype(float)

# 随机把10个元素赋值为空
X.ravel()[np.random.choice(X.size, 10, replace=False)] = np.nan

knn_imputer = impute.KNNImputer(n_neighbors=3)
imputed_X = knn_imputer.fit_transform(X)
imputed_X

另外一种填充缺失值的方法是训练一个回归模型,以含有缺失值的目标列做为标签,剩余其他列做为特征,构建一个回归模型。用这个回归模型的预测值来填充目标列的缺失值。
对于树模型来说,填充缺失值是没有必要的,因为树模型本身有处理缺失值的机制。
另外,使用线性模型比如逻辑回归或者SVM,一定要记得对特征进行标准化处理。树模型则不需要对特征进行标准化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值