大数据人工智能常用特征工程与数据预处理Python实践(1)

我戴着智能手表和智能手机跑步,跑步过程中的心率、配速、里程、爬升高度、步频等数据源源不断的提供给大数据平台。专业人士将大数据描述如下: “大数据是如此的庞大或者复杂,以至于传统的数据处理应用软件不足以处理它们。” 计算机已经变得如此强大,以至于我们现在有能力在每秒存储数百万条的数据记录。不幸的是,分析数据的能力却是一个瓶颈,继续使用传统的方法并不可取,大数据人工智能技术会为我们打开创新之路。

1. 关于数据分析与特征

我们阅读了《中国马拉松跑者研究蓝皮书》,截取片段感受数据分析与特征。

(1))中国各省份马拉松跑者TGI情况。
在这里插入图片描述
马拉松跑者TGI是指该区域人口参与马拉松情况,TGI越高者表示该区域人口参与马拉松率越高。

(2))普通人群与马拉松跑者BMI对比
在这里插入图片描述
BMI指数计算公式为:BMI=体重(千克)除以身高(米)的平方。中国人BMI标准:18.4及以下为过瘦,18.5~23.9为标准,24.0~27.9为轻度超标,28.0~29.9为中度超标,大于40.0为重度超标。

这里不讨论马拉松,而是以大数据人工智能视觉分析特征工程和数据预处理。

什么是特征工程呢?如上文所示的例子,现在设计一个身材分类器,分为过瘦、标准、轻度超标、中度超标、重度超标等5个等级。显然直接按体重判断是不合理的,而是按BMI指标规则,输入数据X为身高和体重 ,输出标签Y为身材等级。针对这个问题,BMI指数就是一个非常经典的特征工程,通过BMI指数,就能非常显然地帮助我们,刻画一个人身材如何。甚至,你可以抛弃原始的体重和身高数据。

2. 常用特征工程

有这么一句话在业界广泛流传:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。那特征工程到底是什么呢?顾名思义,其本质是一项工程活动,目的是最大限度地从原始数据中提取特征以供算法和模型使用。

2.1. 我们常用的特征工程

通过总结和归纳,我们常用的特征工程包括以下方面:
在这里插入图片描述

2.2. 特征工程主要步骤

以大数据人工智能的视角,建立大数据平台、数据仓库和数据清洗等工作内容,更多的是属于IT程序员的工作,而数据特征分析、处理、选择、变换工作,更多的是数据分析算法工程师的工作。

(1)探索性数据分析
在应用机器学习、深度学习流水线,甚至在使用机器学习、深度学习算法或特征工程工具之前,理论上,我们一般首先进行一些基本的描述性统计,并进行可视化分析数据操作,一边全面、系统的理解数据的特征与性质。

(2)特征理解
在了解了数据的大小和形状后,应该进一步仔细观察数据集的每一个列和大致特点,包括数据的分类和等级,以便给出数据清洗方案。

(3)特征预处理
这个阶段是关于改变数据值和数据列,我们根据数据分类和等级填充缺失,并按需执行虚拟变量转换和缩放操作。基于现有数据集,可以考虑构建新的特征,以便理解特征交互情况。

例如时间列,根据业务需要可以分解出月份和季节(春夏秋冬)、周(工作日与周末)等。

(4)特征选择
在选择阶段,用所有原始和新构建的数据列进行统计测试(通常是单变量分析),选择相关性、性能最佳的特征,消除噪声的影响、加速计算。

(5)特征转换
在这个阶段,将根据计算能力、算法模型,对特征的维度进行增减,通常情况下,维度缩减比较常见。

3. 数据清洗

3.1. 数据缺失

(1)删除含有缺失值的个案

简单删除法是在样本来达到目标的情况下,将存在缺失值的个案删除。

权重删除法是当缺失值的类型为非完全随机缺失的时候,可以通过对完整的数据加权来减小偏差。把数据不完全的个案标记后,将完整的数据个案赋予不同的权重,个案的权重可以通过logistic或probit回归求得,根据权重删除部分数据。

(2)可能值插补缺失值

可能值插补缺失值的思想来源是以最可能的值来插补缺失值比全部删除不完全样本所产生的信息丢失要少。在数据挖掘中,因为一个属性值的缺失而放弃大量的其他属性值,这种删除是对信息的极大浪费,所以产生了以可能值对缺失值进行插补的思想与方法,常用的有如下几种方法:

  • 均值插补。数据的属性分为定距型和非定距型。如果缺失值是定距型的,就以该属性存在值的平均值来插补缺失的值;如果缺失值是非定距型的,就根据统计学中的众数原理,用该属性的众数(即出现频率最高的值)来补齐缺失的值。

  • 利用同类均值插补。同均值插补的方法都属于单值插补,不同的是,它用层次聚类模型预测缺失变量的类型,再以该类型的均值插补。

  • 极大似然估计(Max Likelihood ,ML)。在缺失类型为随机缺失的条件下,假设模型对于完整的样本是正确的,那么通过观测数据的边际分布可以对未知参数进行极大似然估计(Little and Rubin)。

  • 多重插补(Multiple Imputation,MI)。多值插补的思想来源于贝叶斯估计,认为待插补的值是随机的,它的值来自于已观测到的值。

3.2. 离群值

3.2.1. 什么是离群值

离群值(outlier),也称逸出值,是指在数据中有一个或几个数值与其他数值相比差异较大。chanwennt准则规定,如果一个数值偏离观测平均值的概率小于等于1/(2n),则该数据应当舍弃(其中n为观察例数,概率可以根据数据的分布进行估计)。

大多数统计分析,如平均数、标准差和相关性,以及基于这些参数的任何统计,对离群值都非常敏感。如下图所示,左侧的图在“离群点”干扰下,线性回归线出现了较大的偏差。
在这里插入图片描述
事实上,在一个数据丰富的数据库中,离群数据和非离群数据之间并没有根本区别。例如前NBA中国球员姚明身高2.26米,在我们普通人群的身高数据集中,就得算离群点,而在NBA中锋的数据集中,也只是第二身高。

3.2.2. 如何识别离群值

如何识别离群值,传统方法比较多。
在这里插入图片描述
基于大数据思维,通常采用聚类等方法。

3.2.3. 离群值检测工具PyOD

在Python大数据生态圈中,有现成的离群值检测工具PyOD,是一个Python工具包,用于检测多变量数据中的离群值。它的API 提供了大约20个离群值检测算法。

可以直接使用:pip install pyod 安装。

如下图所示所示演示数据集,通过多种算法进行离群值检测。
在这里插入图片描述
分析结果如下:
在这里插入图片描述
代码:

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
from pyod.models.abod import ABOD
from pyod.models.knn import KNN
from pyod.models.iforest import IForest
#%matplotlib inline #Jupyter notebook中使用
import matplotlib.font_manager
from pyod.utils.data import generate_data, get_outliers_inliers

#generate random data with two features
X_train, Y_train = generate_data(n_train=200,train_only=True, n_features=2)
# by default the outlier fraction is 0.1 in generate data function 
outlier_fraction = 0.1
# store outliers and inliers in different numpy arrays
x_outliers, x_inliers = get_outliers_inliers(X_train,Y_train)

n_inliers = len(x_inliers)
n_outliers = len(x_outliers)
#separate the two features and use it to plot the data 
F1 = X_train[:,[0]].reshape(-1,1)
F2 = X_train[:,[1]].reshape(-1,1)
# create a meshgrid 
xx , yy = np.meshgrid(np.linspace(-10, 10, 200), np.linspace(-10, 10, 200))

random_state = np.random.RandomState(42)
outliers_fraction = 0.05

classifiers = {
 'Angle-based Outlier Detector (ABOD)' : ABOD(contamination=outlier_fraction),
 'K Nearest Neighbors (KNN)' : KNN(contamination=outlier_fraction),
 'Isolation Forest': IForest(contamination=outliers_fraction,random_state=random_state)
}

# scatter plot 
plt.scatter(F1,F2)
plt.xlabel('F1')
plt.ylabel('F2')
#set the figure size
plt.figure(figsize=(10, 10))
for i, (clf_name,clf) in enumerate(classifiers.items()) :
    # fit the dataset to the model
    clf.fit(X_train)
    # predict raw anomaly score
    scores_pred = clf.decision_function(X_train)*-1
    # prediction of a datapoint category outlier or inlier
    y_pred = clf.predict(X_train)
    # no of errors in prediction
    n_errors = (y_pred != Y_train).sum()
    print('No of Errors : ',clf_name, n_errors)
    # rest of the code is to create the visualization
    # threshold value to consider a datapoint inlier or outlier
    threshold = stats.scoreatpercentile(scores_pred,100 *outlier_fraction)
    # decision function calculates the raw anomaly score for every point
    Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()]) * -1
    Z = Z.reshape(xx.shape)
    subplot = plt.subplot(1, 3, i + 1)
    # fill blue colormap from minimum anomaly score to threshold value
    subplot.contourf(xx, yy, Z, levels = np.linspace(Z.min(), threshold, 10),cmap=plt.cm.get_cmap(name='Blues_r'))
    # draw red contour line where anomaly score is equal to threshold
    a = subplot.contour(xx, yy, Z, levels=[threshold],linewidths=2, colors='red')
    # fill orange contour lines where range of anomaly score is from threshold to maximum anomaly score
    subplot.contourf(xx, yy, Z, levels=[threshold, Z.max()],colors='orange')
    # scatter plot of inliers with white dots
    b = subplot.scatter(X_train[:-n_outliers, 0], X_train[:-n_outliers, 1], c='white',s=20, edgecolor='k') 
    # scatter plot of outliers with black dots
    c = subplot.scatter(X_train[-n_outliers:, 0], X_train[-n_outliers:, 1], c='black',s=20, edgecolor='k')
    subplot.axis('tight')
    subplot.legend(
    [a.collections[0], b, c],
    ['learned decision function', 'true inliers', 'true outliers'],
    prop=matplotlib.font_manager.FontProperties(size=9),
    loc='lower right')
    subplot.tick_params(labelsize=8)
    subplot.set_title(clf_name,fontsize = 10)
    subplot.set_xlim((-10, 10))
    subplot.set_ylim((-10, 10))
plt.show()

附表1:个体检测算法
在这里插入图片描述
附表2:离群集合与离群检测器组合框架
在这里插入图片描述
附表3:功能函数
在这里插入图片描述

3.2.4. 离群值的处理方法

离群值已经被找出来了,那么怎么处理呢?实际处理中没有固定的方法,要根据分析的目的和算法来确定。

(1)删除
删除是最直接、最简单的方法,如果想找出一般的规律,而且离群值也不太多,可以考虑删除。因为离群值可能会影响结论。例如很多比赛节目中打分计算选手最后得分往往去掉一个最高分,去掉一个最低分,可能就是这个道理。比如我们现在研究马拉松成绩与其影响因素,马拉松跑进2小时的基普乔格装备和环境特征,这时候离群值显然会拉高整体的水平,影响判断,所以可以考虑删除,我们大众选手无法比。

(2)放任不管
因为离群值代表的也是真实发生的事件,背后是具体的行为。有些值即使异常,也不会影响模型。比如我们研究加油站车辆加油量和价格的关系,想做分类分析,也就是看用户对油价敏感度。我们能够发现农机油罐车的离群值,虽然他们游离于群体之外,但是在对价格敏感分类的时候并没有使模型造成太大偏差。所以这种离群值对我们的模型来说很合理。

(3)数据处理

  • 对数转换
  • 缩尾
  • 截尾
  • 视为缺失值进行填充

3.3. 数据不平衡处理

在学术研究与教学中,很多算法都有一个基本假设,那就是数据分布是均匀的。当我们把这些算法直接应用于实际数据时,大多数情况下都无法取得理想的结果。因为实际数据往往分布得很不均匀,都会存在“长尾现象”,也就是所谓的“二八原理”。

对于数据源充裕的情况下,我们可以通过采样及其权重方法,使数据集的数据分布符合客观规律,例如常用的正态分布。例如均匀的二分类问题,我们可以直接平均采样两个分类,以实际较少的分类为基准采样。

对于数据样本不足,特别是部分数据很少的情况,我们需要按客观规律补足数据,这部分内容将在后续的文档中单独讨论。

4. 特征预处理

我们在进行特征抽取后,需要根据算法的要求,使用特定的统计方法(数学方法)将数据转换成其所需格式。对于不同的数据类型有不同的转换方法。

(1)类别特征:one-hot encoding、hash encoding、label encoding(标签编码)、count encoding(频数编码)、label-count encoding、target encoding(二分类)、category embedding、Nan encoding、polynomial encoding、expansion encoding、consolidation encoding、dummy encoding(哑变量编码)。
(2)数值特征:rounding、binning、scaling、imputation、interactions、no linear encoding、row statistics。
(3)时间特征
(4)空间特征
(5)自然语言处理
(6)深度学习/NN
(9)Leakage

4.1. 数据归一化与标准化

我们的数据一般都是有单位的,比如常用身高的单位有米、厘米,这个无量纲化并不是说统一量纲为米,而是说,无论是米还是厘米,最后都会变成1,也就是没有了单位。无量纲化使不同规格的数据转换到同一规格。常见的无量纲化方法有标准化和归一化。

能不归一化最好不归一化,之所以进行数据归一化是因为各维度的量纲不相同。而且需要看情况进行归一化。

特征缩放(feature scaling)可能是最广为人知的预处理技巧了,它的目的是保证所有的特征数值具有相同的数量级。 也就是把分析对象的属性数据按比例缩放,使其落入一个小的特定区间(如[-1, 1]或[0,1])。

对特征数据进行规范化常用于涉及神经网络或距离度量的分类算法和聚类算法中。比如使用神经网络向后传播算法进行分类挖掘时,对训练元组中度量每个属性的输入值进行规范化有助于加快学习阶段的速度。对于基于距离度量相异度的方法,数据规范化可以让所有的属性具有相同的权重。

4.1.1. 归一化

(1)最大、最小值归一化(缩放)
x ′ = x i − x m i n x m a x − x m i n x'=\frac{x_{i}-x_{min}}{x_{max}-x_{min}} x=xmaxxminxixmin

其中:
x ′ x' x—输出新值,范围为 [ 0 , 1 ] [0,1] [0,1]
x i x_{i} xi—输入值(原始值)
x m i n x_{min} xmin—输入最小值
x m a x x_{max} xmax—输入最大值

(2)平均归一化
x ′ = x i − x m i n x m a x − x m i n x'=\frac{x_{i}-x_{min}}{x_{max}-x_{min}} x=xmaxxminxixmin

其中:
x ′ x' x—输出新值,范围为 [ − 1 , 1 ] [-1,1] [1,1]
μ \mu μ表示 x i x_{i} xi均值。

(3)非线性归一化

对数函数转换:
x ′ = l o g 10 x x' = log_{10}x x=log10x
反余切函数转换:
x ′ = a t a n ( x ) × 2 / π x' = atan(x) \times 2/ \pi x=atan(x)×2/π
在这里插入图片描述

4.1.2. 标准化(Z-Score)

x ′ = x i − μ σ x' = \frac{x_{i}- \mu }{\sigma} x=σxiμ
其中:
x ′ x' x—新值
x i x_{i} xi—输入值(原始值)
μ \mu μ σ \sigma σ表示 X i X_{i} Xi均值和标准差。

4.1.3. 中心化

x ′ = x − μ x' = x - \mu x=xμ

演示实例代码:

from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
import pandas as pd
import matplotlib.pyplot as plt

def get_data():
    cols_name=['fuelle_date','fuelle','amount','fuel_interva']    
    df = pd.read_hdf("Price_sensitive_DataV3.h5")
    df = df[(df['fuelle_date'] >'2019-11-30') & (df['fuelle_date'] <'2020-05-30')]
    df = df[cols_name]

    return df

def contrast_Normalization(df):
    plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签
    plt.rcParams['axes.unicode_minus']=False
    y_lim = 750
    #df.plot(kind='density', subplots=True, fontsize=8)  
    df.plot(kind='line', x='fuelle_date', subplots=True, fontsize=8, ylim=(0, y_lim))
    
    df1 = (df[['fuelle','amount','fuel_interva']]-df[['fuelle','amount','fuel_interva']].mean())/df[['fuelle','amount','fuel_interva']].std()
    df1 = pd.concat([df['fuelle_date'],df1],axis=1)
    y_lim = 12
    df1.plot(kind='line', x='fuelle_date', subplots=True, fontsize=8, ylim=(0, y_lim))
    
    df2 = (df[['fuelle','amount','fuel_interva']]-df[['fuelle','amount','fuel_interva']].min())/(df[['fuelle','amount','fuel_interva']].max()-df[['fuelle','amount','fuel_interva']].min())
    df2 = pd.concat([df['fuelle_date'],df2],axis=1)
    y_lim = 1
    df2.plot(kind='line', x='fuelle_date', subplots=True, fontsize=8, ylim=(0, y_lim))        
    plt.show()
    
    return
    
if __name__ == '__main__':
    df = get_data()
    contrast_Normalization(df)

fit_transform方法是fit和transform的结合,fit_transform(X_train) 意思是找出X_train的 μ \mu μ σ \sigma σ,并应用在X_train上。
这时对于X_test,我们就可以直接使用transform方法。因为此时StandardScaler已经保存了X_train的。

在这里插入图片描述

替换为sklearn库方法:

def contrast_Normalization(df):
    plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签
    plt.rcParams['axes.unicode_minus']=False
    y_lim = 750
    #df.plot(kind='density', subplots=True, fontsize=8)  
    df.plot(kind='line', x='fuelle_date', subplots=True, fontsize=8, ylim=(0, y_lim))
    
    fuelle = df['fuelle'].values
    amount = df['amount'].values
    fuel_interva = df['fuel_interva'].values
    fuelle_date = df['fuelle_date'].to_list()

    # 标准化
    ss = StandardScaler()
    fuelle0 = ss.fit_transform(fuelle.reshape(-1,1))
    amount0 = ss.fit_transform(amount.reshape(-1,1))
    fuel_interva0 = ss.fit_transform(fuel_interva.reshape(-1,1))  
    '''
    b = fuelle0.reshape(1,-1)
    c = b[0]
    tmp = c.tolist()
    '''
    df1 = pd.DataFrame({'fuelle_date':fuelle_date,'fuelle':(fuelle0.reshape(1,-1))[0].tolist(),'amount':(amount0.reshape(1,-1))[0].tolist(),'fuel_interva':(fuel_interva0.reshape(1,-1))[0].tolist()})
    y_lim = 12
    df1.plot(kind='line', x='fuelle_date', subplots=True, fontsize=8, ylim=(0, y_lim))
    # 归一化
    mm = MinMaxScaler()
    fuelle1 = mm.fit_transform(fuelle.reshape(-1,1))
    amount1 = mm.fit_transform(amount.reshape(-1,1))
    fuel_interva1 = mm.fit_transform(fuel_interva.reshape(-1,1))
    df2 = pd.DataFrame({'fuelle_date':fuelle_date,'fuelle':(fuelle1.reshape(1,-1))[0].tolist(),'amount':(amount1.reshape(1,-1))[0].tolist(),'fuel_interva':(fuel_interva1.reshape(1,-1))[0].tolist()})
    y_lim = 1
    df2.plot(kind='line', x='fuelle_date', subplots=True, fontsize=8, ylim=(0, y_lim))    
        
    plt.show()
    
    return

4.2. One-Hot编码

在分析建模过程中,我们经常会遇到各种类型的属性,如果是标称型属性(离散型数据),也就是不具备序列性、不能量化比较大小的属性,通俗的说就是各种不可比的分类,通常我们不能用简单的数值来粗暴替换。因为属性的数值大小会影响到权重矩阵的计算,不存在大小关系的属性,其权重也不应该发生相应的变化,那么我们就需要用到One-hot编码(也有人称独热编码)这种特殊的编码方式了。

4.2.1. One-hot编码

又称为有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都有独立的寄存器位,并且在任意时候只有一位有效。一句话概括,one hot编码是将类别变量转换为机器学习算法易于利用的“二进制”形式的过程。

看一个简单的例子:假设我们有一个特征是成品油,样本数据情况如下:

 data = [['92#汽油',5.74,50000],
        ['95#汽油',6.14,13000],
        ['0#柴油',5.21,30000]]

编码后的样本矩阵变为:

 data = [[1,0,0,5.74,50000],
        [0,1,0,6.14,,13000],
        [0,0,1,5.21,30000]]

4.2.2. Sklearn实现举例

代码:
price_sensitive数据为[0,1,2],分别代表价格不敏感、一般敏感、敏感三种分类。

from sklearn.preprocessing import OneHotEncoder

import numpy as np
import pandas as pd

def get_data():
    cols_name=['price_sensitive','fuelle_date','fuelle','amount','fuel_interva']
    
    df = pd.read_hdf("Price_sensitive_DataV3.h5")
    df = df[(df['fuelle_date'] >'2019-11-30') & (df['fuelle_date'] <'2020-05-30')]
    df = df[cols_name]

    return df

def Process_one_hot(data):
    price_sensitive = data['price_sensitive'].values
    encoder=OneHotEncoder(sparse=False) # One-Hot编码
    ans=encoder.fit_transform(price_sensitive.reshape((-1,1)))
    print(encoder.inverse_transform(ans))#此为反向编码,当你求得最终的结果时候,
    #可以进行反向编码以获得我们原来数据集中的编码形式
    return ans

if __name__ == '__main__':
    data=get_data()

    lable=Process_one_hot(data)
    print(lable)

4.2.3. 什么情况下用独热编码

  • 用:独热编码用来解决类别型数据的离散值问题;
  • 不用:将离散型特征进行one-hot编码的作用,是为了让距离计算更合理,但如果特征是离散的,并且不用one-hot编码就可以很合理的计算出距离,那么就没必要进行one-hot编码。 有些基于树的算法在处理变量时,并不是基于向量空间度量,数值只是个类别符号,即没有偏序关系,所以不用进行独热编码。 Tree Model不太需要one-hot编码: 对于决策树来说,one-hot的本质是增加树的深度。
    总的来说,要是one hot encoding的类别数目不太多,建议优先考虑。

4.3. 数据变换

通过函数变换改变原始数据的分布,变换后数据呈正态分布,以及改善数据分布高度倾斜。 常用的数据变换方法:

  • log变换 x=ln(x)
  • box-cox变换,自动寻找最佳正态分布变换函数的方法

x ′ = { x λ − 1 λ λ ≠ 0 l n ( x ) λ = 0 x' = \left\{\begin{matrix} \frac{x^{\lambda }-1}{\lambda} & \lambda \neq 0\\ ln(x) & \lambda = 0 \end{matrix}\right. x={λxλ1ln(x)λ=0λ=0

下面是用Python执行对数变换的代码片段。

# 数据变换,其df = get_data(),见前面的代码引用
def Data_Transformation(df):
    plt.rcParams['font.sans-serif']=['SimHei'] #显示中文标签
    plt.rcParams['axes.unicode_minus']=False
    
    df = df[['amount']]
    df.plot(kind='hist', subplots=True, fontsize=8)
    
    df['log_amount'] = np.log(1 + df['amount'].values) #防止出现0
    df1 = df[['log_amount']]
    df1.plot(kind='hist', subplots=True, fontsize=8)
    
    plt.show()

在这里插入图片描述
左侧为原始图形,数据分布基本呈正态分布,而右侧取log后,数据分布不合理(演示例子)。

附:关于数据等级

  • 定类等级,定性数据,例如血型A、B、O、AB;
  • 定序等级,按顺序的定性数据,例如成绩评价:优、良、中、差;
  • 定距等级,适合比较值之间的差异,例如温度高出多少,日平均气温;
  • 定比等级,适用于任何数学运算,例如资金的差距、比例等。

由于时间和水平有限,后续将继续补充,欢迎读者反馈讨论。

参考:

《使用sklearn做单机特征工程》 博客园 jasonfreak 2016年5月
《中国马拉松跑者研究蓝皮书》 中国田径协会 华米科技 2020年12月
《数据缺失值的4种处理方法》 博客园 ,刘小子 ,2017.12
《几种常见的离群点检验方法》 博客园 , 知是行之始,行是知之成 ,2019年4月
《了解离群值以及如何使用Python中的PyOD检测离群值》 Python Free 2020年2月
《 sklearn 中文文档》
《特征预处理》 知乎 , qihengshan , 2020年4月
《Python sklearn决策树算法实践》CSDN博客, 肖永威 2018年4月
《Pandas(数据表)深入应用经验小结(查询、分组、上下行间计算等)》 CSDN博客 ,肖永威 ,2020年8月
《特征工程入门与实践》庄嘉盛译, 人民邮电出版社 ,2019年

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肖永威

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值