教你一文读懂特征工程
特征工程(feature engineering):利用领域知识和现有数据,创造出新的特征,用于机器学习算法;可以手动(manual)或自动(automated)。神经网络的自动特征工程,常常不适用于现实中其他的复杂任务。因此,本文主要针对数据挖掘以及传统的机器学习,不会涉及图像识别、自然语言处理等深度学习领域。
俗话说:数据与特征工程决定了模型的上限,改进算法只不过是逼近这个上限而已。
在豆瓣图书频道,搜索‘特征工程’关键词,搜索结果是仅有两本评分在7分以上数据,分别是精通特征工程、特征工程入门与实践
import pandas as pd
import numpy as np
import seaborn as sns
df_titanic = sns.load_dataset('titanic')
一、特征理解
定量数据:指的是一些数值,用于衡量某件东西的数量;
定性数据:指的是一些类别,用于描述某件东西的性质。
二、特征清洗
日期格式不一致【’2019-07-20’、’20190720’、’2019/07/20’、’20/07/2019’】
时间戳单位不一致,有的用秒表示,有的用毫秒表示;
使用无效时间表示,时间戳使用 0 表示,结束时间戳使用 FFFF 表示。
姓名写了性别,身份证号写了手机号等
数值类型统一 【如 1、2.0、3.21E3、四】
单位统一【如 180cm、1.80m】
2.2 缺失处理
df_titanic.isnull().sum()
survived 0
pclass 0
sex 0
age 177
sibsp 0
parch 0
fare 0
embarked 2
class 0
who 0
adult_male 0
deck 688
embark_town 2
alive 0
alone 0
df_titanic[df_titanic["embark_town"].isnull()]
df_titanic.dropna(axis=0,how='any',subset=['embark_town'],inplace=True)
df_titanic['embark_town'].fillna('unknown', inplace=True)
中位数填充
df_titanic['fare'].fillna(df_titanic['fare'].median(), inplace=True)
众数填充
df_titanic['embarked'].isnull().sum()
执行结果:2
df_titanic['embarked'].fillna(df_titanic['embarked'].mode(), inplace=True)
df_titanic['embarked'].value_counts()
执行结果:
S 64
用 imputer 填充缺失值
同类均值填充
df_titanic.groupby(['sex', 'pclass', 'who'])['age'].mean()
执行结果:
sex pclass who
female 1 child 10.333333
woman 35.500000
2 child 6.600000
woman 32.179688
3 child 7.100000
woman 27.854167
male 1 child 5.306667
man 42.382653
2 child 2.258889
man 33.588889
3 child 6.515000
man 28.995556
Name: age, dtype: float64
age_group_mean = df_titanic.groupby(['sex', 'pclass', 'who'])['age'].mean().reset_index()
age_group_mean
执行结果:
sex pclass who age
0 female 1 child 10.333333
1 female 1 woman 35.500000
2 female 2 child 6.600000
3 female 2 woman 32.179688
4 female 3 child 7.100000
5 female 3 woman 27.854167
6 male 1 child 5.306667
7 male 1 man 42.382653
8 male 2 child 2.258889
9 male 2 man 33.588889
10 male 3 child 6.515000
11 male 3 man 28.995556
def select_group_age_median(row):
condition = ((row['sex'] == age_group_mean['sex']) &
(row['pclass'] == age_group_mean['pclass']) &
(row['who'] == age_group_mean['who']))
return age_group_mean[condition]['age'].values[0]
df_titanic['age'] =df_titanic.apply(
lambda x: select_group_age_median(x) if np.isnan(x['age']) else x['age'],axis=1)
执行结果:
0 22.000000
1 38.000000
2 26.000000
3 35.000000
4 35.000000
...
886 27.000000
887 19.000000
888 27.854167
889 26.000000
890 32.000000
sns.distplot(df_titani
df_titanic_age = df_titanic[['age', 'pclass', 'sex', 'who','fare', 'parch', 'sibsp']]
df_titanic_age = pd.get_dummies(df_titanic_age)
df_titanic_age.head()
执行结果为
age pclass fare parch sibsp sex_female sex_male who_child who_man who_woman
0 22.0 3 7.2500 0 1 0 1 0 1 0
1 38.0 1 71.2833 0 1 1 0 0 0 1
2 26.0 3 7.9250 0 0 1 0 0 0 1
3 35.0 1 53.1000 0 1 1 0 0 0 1
4 35.0 3 8.0500 0 0 0 1 0 1 0
# 乘客分成已知年龄和未知年龄两部分
known_age = df_titanic_age[df_titanic_age.age.notnull()]
unknown_age = df_titanic_age[df_titanic_age.age.isnull()]
# y 即目标年龄
y_for_age = known_age['age']
# X 即特征属性值
X_train_for_age = known_age.drop(['age'], axis=1)
X_test_for_age = unknown_age.drop(['age'], axis=1)
from sklearn.ensemble import RandomForestRegressor
rfr = RandomForestRegressor(random_state=0, n_estimators=2000, n_jobs=-1)
rfr.fit(X_train_for_age, y_for_age)
# 用得到的模型进行未知年龄结果预测
y_pred_age = rfr.predict(X_test_for_age)
# 用得到的预测结果填补原缺失数据
df_titanic.loc[df_titanic.age.isnull(), 'age'] = y_pred_age
sns.distplot(df_titanic.age)
线性插值法
df_titanic['fare'].interpolate(method = 'linear', axis = 0)
df_titanic['fare'].interpolate(method = 'linear', axis = 1)
df_titanic['fare'].interpolate()
多重插补(Multiple Imputation)
sex_list = ['MALE', 'FEMALE', np.NaN, 'FEMALE', 'FEMALE', np.NaN, 'MALE']
df = pd.DataFrame({'SEX': sex_list})
display(df)
df.fillna('NA', inplace=True)
df = pd.get_dummies(df['SEX'],prefix='IS_SEX')
display(df)
# 原始数据
SEX
0 MALE
1 FEMALE
2 NaN
3 FEMALE
4 FEMALE
5 NaN
6 MALE
# 填充后
IS_SEX_FEMALE IS_SEX_MALE IS_SEX_NA
0 0 1 0
1 1 0 0
2 0 0 1
3 1 0 0
4 1 0 0
5 0 0 1
6 0 1
df_titanic.drop(["deck"],axis=1)
箱线法
sns.catplot(y="fare",x="survived", kind="box", data=df_titanic,palette="Set2");
正态分布
sns.distplot(df_titanic.age)
异常值检测方法
sns.scatterplot(x="fare", y="age", hue="survived",data=df_titanic,palette="Set1")
删除含有异常值的记录;
某些筛选出来的异常样本是否真的是不需要的异常特征样本,最好找懂业务的再确认一下,防止我们将正常的样本过滤掉了。
将异常值视为缺失值,交给缺失值处理方法来处理;
使用均值/中位数/众数来修正;
不处理。
三、特征构造
3.1 特征构造
3.3.1 统计量构造:
基于业务规则、先验知识等构建新特征
四分位数、中位数、平均值、标准差、偏差、偏度、偏锋、离散系统
构造长、短期统计量(如 周、月)
时间衰减(越靠近观测权重值高)
年龄分段:child、young、midlife、old
def age_bin(x):
if x <= 18:
return 'child'
elif x <= 30:
return 'young'
elif x <= 55:
return 'midlife'
else:
return 'old'
df_titanic['age_bin'] = df_titanic['age'].map(age_bin)
df_titanic['age_bin'].unique()
执行结果:
array(['young', 'midlife', 'child', 'old'], dtype=object)
抽取 title 特征
df_titanic['title'] = df_titanic['name'].map(
lambda x: x.split(',')[1].split('.')[0].strip())
df_titanic['title'].value_counts()
执行结果:
Mr 757
Miss 260
Mrs 197
Master 61
Rev 8
Dr 8
Col 4
Ms 2
Major 2
Mlle 2
Dona 1
Sir 1
Capt 1
Don 1
Lady 1
Mme 1
the Countess 1
Jonkheer 1
# 再根据这些 title 细分,是官员,还是皇室,还是女士、先生、小姐
df_titanic['title'].unique()
执行结果:
array(['Mr', 'Mrs', 'Miss', 'Master', 'Don', 'Rev', 'Dr', 'Mme', 'Ms',
'Major', 'Lady', 'Sir', 'Mlle', 'Col', 'Capt', 'the Countess',
'Jonkheer', 'Dona'], dtype=object)
title_dictionary = {
"Mr": "Mr",
"Mrs": "Mrs",
"Miss": "Miss",
"Master": "Master",
"Don": "Royalty",
"Rev": "Officer",
"Dr": "Officer",
"Mme": "Mrs",
"Ms": "Mrs",
"Major": "Officer",
"Lady": "Royalty",
"Sir": "Royalty",
"Mlle": "Miss",
"Col": "Officer",
"Capt": "Officer",
"the Countess": "Royalty",
"Jonkheer": "Royalty",
"Dona": 'Mrs'
}
df_titanic['title'] = df_titanic['title'].map(title_dictionary)
df_titanic['title'].value_counts()
执行结果:
Mr 757
Miss 262
Mrs 201
Master 61
Officer 23
Royalty 5
3.3.2 周期值:
前n个周期/天/月/年的周期值,如过去5天分位数、平均值等
同比/环比
3.3.3 数据分桶:
1) 等频、等距分桶
数值变量分箱
# qcut 等频率分箱
df_titanic['fare_bin'], bins = pd.qcut(df_titanic['fare'], 5, retbins=True)
df_titanic['fare_bin'].value_counts()
(7.854, 10.5] 184
(21.679, 39.688] 180
(-0.001, 7.854] 179
(39.688, 512.329] 176
(10.5, 21.679] 172
bins #array([ 0. , 7.8542, 10.5 , 21.6792, 39.6875, 512.3292])
def fare_cut(age):
if age <= 7.8958:
return 0
if age <= 10.5:
return 1
if age <= 21.6792:
return 2
if age <= 39.6875:
return 3
return 4
df_titanic['fare_bin'] = df_titanic['fare'].map(fare_cut)
# cut 等距离分箱
bins = [0, 12, 18, 65, 100]
pd.cut(df_titanic['age'], bins).value_counts
2) Best-KS分桶
3) 最小熵法分箱
3.3.4 特征组合
多项式生成新特征【针对连续值】
df_titanic_numerical = df_titanic[['age','sibsp','parch','fare','family_size']]
df_titanic_numerical.head()
执行结果:
age sibsp parch fare family_size
0 22.0 1 0 7.2500 2
1 38.0 1 0 71.2833 2
2 26.0 0 0 7.9250 1
3 35.0 1 0 53.1000 2
4 35.0 0 0 8.0500 1
# 扩展数值特征
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=2, include_bias=False, interaction_only=False)
df_titanic_numerical_poly = poly.fit_transform(df_titanic_numerical)
pd.DataFrame(df_titanic_numerical_poly, columns=poly.get_feature_
sns.heatmap(pd.DataFrame(df_titanic_numerical_poly, columns=poly.get_feature_names()).corr())
3.4 特征选择
特征是否发散:如果一个特征不发散,例如方差接近于 0,也就是说样本在这个特征上基本上没有差异,这个特征对于样本的区分并没有什么用。
特征与目标的相关性:这点比较显见,与目标相关性高的特征,应当优选选择。除方差法外,本文介绍的其他方法均从相关性考虑。
Filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数来选择特征。
Wrapper:包装法,根据目标函数(通常是预测效果评分),每次选择若干特征或者排除若干特征。
Embedded:嵌入法,先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。类似于 Filter 方法,但是是通过训练来确定特征的优劣。我们使用 sklearn 中的 feature_selection 库来进行特征选择。
3.4.1 过滤式
from sklearn.feature_selection import VarianceThreshold
variancethreshold = VarianceThreshold() #实例化,默认方差为 0.方差<=0 的过滤掉
df_titanic_numerical = df_titanic[['age','sibsp','parch','fare','family_size']]
X_var = variancethreshold.fit_transform(df_titanic_numerical) #获取删除不合格特征后的新特征矩阵
variancethreshold.variances_
array([ 79.58,1.21467827,0.64899903,512.3292,2.60032675])
del_list = df_titanic_numerical.columns[variancethreshold.get_support()==0].to_list() #获得删除
df_titanic_numerical_fsvar = VarianceThreshold(np.median(df_titanic_numerical.var().values)).fit_trans
X_bvar = VarianceThreshold(.8 * (1 - .8)).fit_transform(df_titanic_numerical)
X_bvar.shape
执行结果:
(891, 5)
df_titanic_categorical = df_titanic[['sex', 'class', 'embarked', 'who', 'age_bin','adult_male','alone','fare_bin']]
df_titanic_numerical = df_titanic[['age','sibsp','parch','fare','family_size','pclass']]
df_titanic_categorical_one_hot = pd.get_dummies(
df_titanic_categorical,
columns=['sex', 'class', 'embarked', 'who', 'age_bin','adult_male','alone','fare_bin'],
drop_first=True)
df_titanic_combined = pd.concat([df_titanic_numerical,df_titanic_categorical_one_hot],axis=1)
y = df_titanic['survived']
X = df_titanic_combined.iloc[:,1:]
from sklearn.feature_selection import chi2
from sklearn.feature_selection import SelectKBest
chi_value, p_value = chi2(X,y)
#根据 p 值,得出 k 值
k = chi_value.shape[0] - (p_value > 0.05).sum() #要保留的特征的数量 14
#根据卡方值,选择前几特征,筛选后特征
X_chi = SelectKBest(chi2, k=14).fit_transform(X, y)
X_chi.shape
(89
from sklearn.feature_selection import f_classif
f_value, p_value = f_classif(X,y)
#根据 p 值,得出 k 值
k = f_value.shape[0] - (p_value > 0.05).sum()
#筛选后特征
X_classif = SelectKBest(f_classif, k=14).fit_transform(X, y)
from sklearn.feature_selection import mutual_info_classif as MIC
#互信息法
mic_result = MIC(X,y) #互信息量估计
k = mic_result.shape[0] - sum(mic_result <= 0) #16
X_mic = SelectKBest(MIC, k=16).fit_transform(X, y)
X_mic.shape
(891, 16)
3.4.2 包裹式
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
#递归特征消除法,返回特征选择后的数据
#参数 estimator 为基模型
#参数 n_features_to_select 为选择的特征个数
X_ref = RFE(estimator=LogisticRegression(), n_features_to_select=10).fit_transform(X, y)
from sklearn.ensemble import ExtraTreesClassifier
# feature extraction
model = ExtraTreesClassifier()
model.fit(X, y)
print(model.feature_importances_)
feature=list(zip(X.columns,model.feature_importances_))
feature=pd.DataFrame(feature,columns=['feature','importances'])
feature.sort_values(by='importances',ascending=False).head(20)
feature importances
2 fare 0.227659
15 adult_male_True 0.130000
10 who_man 0.108939
5 sex_male 0.078065
11 who_woman 0.059090
7 class_Third 0.055755
4 pclass 0.048733
3 family_size 0.038347
0 sibsp 0.035489
9 embarked_S 0.029512
1 parch 0.023778
20 fare_bin_(39.688, 512.329] 0.022985
14 age_bin_young 0.021404
12 age_bin_midlife 0.019379
6 class_Second 0.019301
17 fare_bin_(7.854, 10.5] 0.016448
19 fare_bin_(21.679, 39.688] 0.016006
18 fare_bin_(10.5, 21.679] 0.014871
16 alone_True 0.013093
13 age_bin_old 0.0112
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
import eli5
from eli5.sklearn import PermutationImportance
my_model = RandomForestClassifier(random_state=0).fit(train_X, train_y)
perm = PermutationImportance(my_model, random_state=1).fit(val_X, val_y)
eli5.show_weights(perm, feature_names = val_X.columns.tolist())
3.4.3 嵌入式
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
#带 L1 和 L2 惩罚项的逻辑回归作为基模型的特征选择,这个设置带 L1 惩罚项的逻辑回归作为基模型的特征选择
lr = LogisticRegression(solver='liblinear',penalty="l1", C=0.1)
X_sfm = SelectFromModel(lr).fit_transform(X, y)
X_sfm.shape
(891, 7
from sklearn.feature_selection import SelectFromModel
from sklearn.svm import LinearSVC
lsvc = LinearSVC(C=0.01,penalty='l1',dual=False).fit(X, y)
model = SelectFromModel(lsvc,prefit=True)
X_sfm_svm = model.transform(X)
X_sfm_svm.shape
(891, 7
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import GradientBoostingClassifier
#GBDT 作为基模型的特征选择
gbdt = GradientBoostingClassifier()
X_sfm_gbdt = SelectFromModel(gbdt).fit_transform(X, y)
X_sfm_gbdt.shape
(891, 5)
四、特征变换
1) 标准化(Standardization)
from sklearn.preprocessing import StandardScale
#标准化模型训练
Stan_scaler = StandardScaler()
Stan_scaler.fit(x)
x_zscore = Stan_scaler.transform(x)
x_test_zscore = Stan_scaler.transform(x_test)
joblib.dump(Stan_scaler,'zscore.m') #写入文件
2) 归一化(Normalization)
3) 区间缩放(scaling)
from sklearn import preprocessing
min_max_scaler = preprocessing.MinMaxScaler()
min_max_scaler.fit_transform(x)
x_minmax = min_max_scaler.transform(x)
x_test_minmax = min_max_scaler.transform(x_test)
joblib.dump(min_max_scaler,'min_max_scaler.m') #写入文件
3.5.2 非线性变换【统计变换】
1) log 变换
sns.distplot(df_titanic.fare,kde=False)
df_titanic['fare_log'] = np.log((1+df_titanic['fare']))
sns.distplot(df_titanic.fare_log,kde=False)
2) box-cox 变换
# 从数据分布中移除非零值
fare_positive_value = df_titanic[(~df_titanic['fare'].isnull()) & (df_titanic['fare']>0)]['fare']
import scipy.stats as spstats
# 计算最佳λ值
l, opt_lambda = spstats.boxcox(fare_positive_value)
print('Optimal lambda value:', opt_lambda) # -0.5239075895755266
# 进行 Box-Cox 变换
fare_boxcox_lambda_opt = spstats.boxcox(df_titanic[df_titanic['fare']>0]['fare'],lmbda=opt_lambda)
sns.distplot(fare_boxcox_lambda_opt,kde=Fal
3.5.3 离散变量处理
1) 标签编码(label encoder)
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
le.fit(["超一线", "一线", "二线", "三线"])
print('特征:{}'.format(list(le.classes_)))
# 输出 特征:['一线', '三线', '二线', '超一线']
print('转换标签值:{}'.format(le.transform(["超一线", "一线", "二线"])))
# 输出 转换标签值:array([3 0 2]...)
print('特征标签值反转:{}'.format(list(le.inverse_transform([2, 2, 1]))))
# 输出 特征标签值反转:['二线', '二线', '三线
2) 独热编码(one hot encoder )
使用 pandas 实现:
sex_list = ['MALE', 'FEMALE', np.NaN, 'FEMALE', 'FEMALE', np.NaN, 'MALE']
df = pd.DataFrame({'SEX': sex_list})
display(df)
df.fillna('NA', inplace=True)
df = pd.get_dummies(df['SEX'],prefix='IS_SEX')
display(df)
# 原始数据
SEX
0 MALE
1 FEMALE
2 NaN
3 FEMALE
4 FEMALE
5 NaN
6 MALE
# 填充后
IS_SEX_FEMALE IS_SEX_MALE IS_SEX_NA
0 0 1 0
1 1 0 0
2 0 0 1
3 1 0 0
4 1 0 0
5 0 0 1
pd.get_dummies(
df_titanic,
columns=[
'sex', 'class', 'pclass', 'embarked', 'who', 'family_size', 'age_bin'
],drop_first=True)
使用 sklearn 实现:
注:当特征是字符串类型时,需要先用 LabelEncoder() 转换成连续的数值型变量,再用 OneHotEncoder() 二值化
sklearn.preprocessing 中的 OneHotEncoder 将 shape=(None,1)的列向量中每个分量表示的下标(index)编码成 one hot 行向量。
import numpy as np
from sklearn.preprocessing import OneHotEncoder
行向量转列向量:
# 非负整数表示的标签列表
labels = [0,1,0,2]
# 行向量转列向量
labels = np.array(labels).reshape(len(labels), -1)
one hot 编码:
enc = OneHotEncoder()
enc.fit(labels)
targets = enc.transform(labels).toarray()
# 如果不加 toarray() 的话,输出的是稀疏的存储格式,即索引加值的形式,也可以通过参数指定 sparse = False 来达到同样的效果
编码结果:
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 1., 0., 0.],
[ 0., 0., 1.]])
3) 标签二值化(LabelBinarizer)
3.5.4 降维
from sklearn import datasets
iris_data = datasets.load_iris()
X = iris_data.data
y = iris_data.target
def draw_result(X, y):
"""
X: 降维后的数据
iris: 原数据
"""
plt.figure()
# 提取 Iris-setosa
setosa = X[y == 0]
# 绘制点:参数 1 x 向量,y 向量
plt.scatter(setosa[:, 0], setosa[:, 1], color="red", label="Iris-setosa")
# Iris-versicolor
versicolor = X[y == 1]
plt.scatter(versicolor[:, 0], versicolor[:, 1], color="orange", label="Iris-versicolor")
# Iris-virginica
virginica = X[y == 2]
plt.scatter(virginica[:, 0], virginica[:, 1], color="blue", label="Iris-virginica")
plt.legend()
plt.show()
draw_result(X, y
1) PCA(Principal Component Analysis)
求
X 均值 将
X 减去均值计算协方差矩阵 C = \frac{1}{m}XX^T 对协方差矩阵
C 特征值分解 从大到小排列
C 的特征值取前 k 个特征值对应的特征向量按行组成矩阵即为变换矩阵 P_{k\times n}
class PCA:
def __init__(self, dimension, train_x):
# 降维后的维度
self.dimension = dimension
# 原始数据集
self.train_x = train_x
@property
def result(self):
'返回降维后的矩阵'
# 1. 数据中心化
data_centering = self.train_x - np.mean(self.train_x, axis=0)
# 2. 计算协方差矩阵
cov_matrix = np.cov(data_centering, rowvar=False)
# 3. 特征值分解
eigen_val, eigen_vec = np.linalg.eig(cov_matrix)
# 4. 生成降维后的数据
p = eigen_vec[:, 0:self.dimension] # 取特征向量矩阵的前 k 维
return np.dot(data_centering,p)
调用方法:
pca = PCA(2,X)
iris_2d = pca.result
draw_result(iris_2d, y
import numpy as np
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
newX = pca.fit_transform(X)
draw_result(newX, y)
2) SVD(Singular Value Decomposition)
class SVD:
def __init__(self, dimension, train_x):
self.dimension = dimension
self.train_x = train_x
@property
def result(self):
'返回降维后的矩阵'
data_centering = self.train_x - np.mean(self.train_x, axis=0)
# SVD
U, Sigma, VT = np.linalg.svd(data_centering)
return np.dot(data_centering, np.transpose(VT)[:, :self.dimension])
调用方法:
svd = SVD(2,X)
iris_svd = svd.result
draw_result(iris_svd,y)
from sklearn.decomposition import TruncatedSVD
iris_2d = TruncatedSVD(2).fit_transform(X)
draw_result(iris_2d, y)
3) PCA 和 SVD 的关系
4) Fisher 线性判别分析(Linear Discriminant Analysis,LDA)
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
lda = LDA(n_components=2)
iris_2d = lda.fit_transform(X, y)
draw_result(iris_2d, y)
5) T-SNE
from sklearn.manifold import TSNE
tsne = TSNE(n_components=2)
iris_2d = tsne.fit_transform(X)
draw_result(iris_2d, y)
五 总结
特征变换要切记:
类别特征与数值特征的组合:
median(N1)_by(C1) \\ 中位数
mean(N1)_by(C1) \\ 算术平均数
mode(N1)_by(C1) \\ 众数
min(N1)_by(C1) \\ 最小值
max(N1)_by(C1) \\ 最大值
std(N1)_by(C1) \\ 标准差
var(N1)_by(C1) \\ 方差
freq(C2)_by(C1) \\ 频数
N1 - median(N1)_by(C1)
N1 - mean(N1)_by(C1)
用基因编程创造新特征
用决策树创造新特征:
树模型:
依赖样本距离来学习的模型(如线性回归、SVM、深度学习等):
作者简介 王岳为好未来机器学习算法专家 招聘信息
好未来技术团队正在热招前端、算法、后台开发等各个方向高级开发工程师岗位,大家可点击本公众号“技术招聘”栏目了解详情,欢迎感兴趣的伙伴加入我们!也许你还想看重磅丨科技教育公司“好未来”正式对外开源高性能PHP框架Fend 好未来AI团队斩获UbiComp 2020国际竞赛冠军 探索下一代字符识别技术 "考试"背后的科学:教育测量中的理论与模型(IRT篇)