本文为数据茶水间群友原创,经授权在本公众号发表。
关于作者:JunLiang,一个热爱挖掘的数据从业者,勤学好问、动手达人,期待与大家一起交流探讨机器学习相关内容~
数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。由此可见,特征工程在机器学习中占有相当重要的地位。在实际应用当中,可以说特征工程是机器学习成功的关键。
那特征工程是什么?
特征工程是利用数据领域的相关知识来创建能够使机器学习算法达到最佳性能的特征的过程。
特征工程又包含了 Data PreProcessing(数据预处理)、Feature Extraction(特征提取)、Feature Selection(特征选择)和 Feature construction(特征构造)等子问题,本章内容主要讨论特征构造的方法。
创造新的特征是一件十分困难的事情,需要丰富的专业知识和大量的时间。机器学习应用的本质基本上就是特征工程。 ——Andrew Ng
之前文章已经介绍了聚合特征构造、转换特征构造、笛卡尔乘积特征构造和遗传编程特征构造,接下来将介绍怎么使用GBDT进行特征构造以及使用聚类进行特征构造。
GBDT 是一种常用的非线性模型,基于集成学习中 boosting 的思想,由于GBDT本身可以发现多种有区分性的特征以及特征组合,决策树的路径可以直接作为 LR 输入特征使用,省去了人工寻找特征、特征组合的步骤。所以可以将 GBDT 的叶子结点输出,作为LR的输入,如图所示:
这种通过 GBDT 生成LR特征的方式(GBDT+LR),业界已有实践(Facebook,Kaggle-2014),且效果不错,是非常值得尝试的思路。
一棵树的表达能力很弱,不足以表达多个有区分性的特征组合,多棵树的表达能力更强一些。GBDT 每棵树都在学习前面棵树尚存的不足,迭代多少次就会生成多少颗树。按 paper 以及 Kaggle 竞赛中的 GBDT+LR 融合方式,多棵树正好满足 LR 每条训练样本可以通过 GBDT 映射成多个特征的需求。
RF 也是多棵树,但从效果上有实践证明不如 GBDT。且 GBDT 前面的树,特征分裂主要体现对多数样本有区分度的特征;后面的树,主要体现的是经过前 N 颗树,残差仍然较大的少数样本。优先选用在整体上有区分度的特征,再选用针对少数样本有区分度的特征,思路更加合理,这应该也是用 GBDT 的原因。
import numpy as np
import random
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.preprocessing import OneHotEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve, roc_auc_score
# 生成随机数据
np.random.seed(10)
X, Y = make_classification(n_samples=1000, n_features=30)
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, random_state=233, test_size=0.4)
# 训练GBDT模型
gbdt = GradientBoostingClassifier(n_estimators=10)
gbdt.fit(X_train, Y_train)
# 对GBDT预测结果进行onehot编码
onehot = OneHotEncoder()
onehot.fit(gbdt.apply(X_train)[:, :, 0])
# 训练LR模型
lr = LogisticRegression()
lr.fit(onehot.transform(gbdt.apply(X_train)[:, :, 0]), Y_train)
# 测试集预测
Y_pred = lr.predict_proba(onehot.transform(gbdt.apply(X_test)[:, :, 0]))[:, 1]
fpr, tpr, _ = roc_curve(Y_test, Y_pred)
auc = roc_auc_score(Y_test, Y_pred)
print('GradientBoosting + LogisticRegression: ', auc)
在广告推荐中,广告 ID 是一个易被忽略的重要特征。采用 GBDT-LR 的方案可将其很好的利用起来。一般而言,ID 取值多且呈现长尾分布,常用作法是对一些大广告(曝光充分,样本充足)建立专属 GBDT,其它构建共用 GBDT。
俗话说:“物以类聚,人以群分”,在自然科学和社会科学中,存在着大量的分类问题。所谓类,通俗地说,就是指相似元素的集合。
聚类是把相似的对象通过静态分类的方法分成不同的组别或者更多的子集(subset),这样让在同一个子集中的成员对象都有相似的一些属性,常见的包括在坐标系中更加短的空间距离等。
常用的距离算法:
使用 k-mean 算法对用户兴趣爱好进行聚类
import pandas as pd
import jieba
import numpy as np
from mitie import total_word_feature_extractor
from sklearn.cluster import KMeans
from sklearn.preprocessing import OneHotEncoder
# 构造特征集
hobby = [
'健身', '电影', '音乐', '读书', '历史',
'篮球', '羽毛球', '足球',
]
df = pd.DataFrame({'兴趣': hobby})
display(df.head(20))
# 输出:
兴趣
0 健身
1 电影
2 音乐
3 读书
4 历史
5 篮球
6 羽毛球
7 足球
# 加载Embedding模型
mitie_model_filename = 'total_word_feature_extractor_zh.dat'
twfe = total_word_feature_extractor(mitie_model_filename)
# 把词语转换成embedding向量
embeding_array = np.array(list(df['兴趣'].apply(
lambda w: twfe.get_feature_vector(w))))
# k-mean距离
kmeans = KMeans(n_clusters=2, random_state=0).fit(embeding_array)
kmean_label = kmeans.labels_
print('kmeans.labels_:{}'.format(kmean_label))
# 输出:kmeans.labels_:[1 1 1 1 1 0 0 0]
kmean_label = kmean_label.reshape(-1, 1)
print('kmean_label shape={}'.format(kmean_label.shape))
# 输出:kmean_label shape=(8, 1)
# 特征编码
enc = OneHotEncoder()
onehot_code = enc.fit_transform(kmean_label)
print(onehot_code.toarray())
# 输出:
[[0. 1.]
[0. 1.]
[0. 1.]
[0. 1.]
[0. 1.]
[1. 0.]
[1. 0.]
[1. 0.]]
预告:下一篇文章将介绍时间特征构造以及时间序列特征构造。