机器学习必备技能之“数据预处理”

Ft 2020-07-14 PM 179℃ 0条

TUSHARE 金融与技术学习兴趣小组

编译整理 | 一只小绿怪兽

译者简介:北京第二外国语学院国际商务专业研一在读,目前在学习Python编程和量化投资相关知识。

作者:Datacamp

Machine Learning 机器学习,是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

它是人工智能的核心,是使计算机具有智能的根本途径,其应用遍及人工智能的各个领域,它主要使用归纳、综合而不是演绎。

上面的官方定义看起来很吓人,简单来说,机器学习的核心是,让机器通过算法从现有数据中学习,然后对新数据做出预测。

在利用机器学习模型进行预测之前,非常重要的一步是对要输入的数据进行预处理,也就是本文要介绍的内容,主要包括对数据进行标准化、创建最有代表性的特征、并选择适合模型的最佳特征。

【工具】Python 3

【数据】tushare.pro 、Datacamp

【注意】本文注重的是方法的讲解,请大家灵活掌握。

01 数据清洗

在做任何分析之前,第一步,都是要对数据进行清洗。关于常见的数据清洗方法,在文章《这些方法解决了数据清洗80%的工作量》中已经介绍过了,这里就简单回顾一下。

① 删除某列有缺失值的行。

print(volunteer.head())

   opportunity_id  content_id  vol_requests  event_time ... Census Tract  BIN BBL NTA
0            4996       37004            50           0 ...          NaN  NaN NaN NaN
1            5008       37036             2           0 ...          NaN  NaN NaN NaN
2            5016       37143            20           0 ...          NaN  NaN NaN NaN
3            5022       37237           500           0 ...          NaN  NaN NaN NaN
4            5055       37425            15           0 ...          NaN  NaN NaN NaN

[5 rows x 35 columns]


print(volunteer.shape)
(665, 35)

# 查看'category_desc'列有多少缺失值
print(volunteer['category_desc'].isnull().sum())
# 选中'category_desc'列不为空值的行
volunteer_subset = volunteer[volunteer['category_desc'].notnull()]
print(volunteer_subset.shape)

48
(617, 35)

② 用.astype()转换某列的数据类型。

print(volunteer.dtypes) 

opportunity_id          int64
content_id              int64
vol_requests            int64
event_time              int64
title                  object
hits                   object

# 查看hits列的前5行
print(volunteer["hits"].head())

0    737
1     22
2     62
3     14
4     31
Name: hits, dtype: int64

# 把hits列的数据类型转换成整数int 
volunteer["hits"] = volunteer["hits"].astype('int')

# 查看数据类型
print(volunteer.dtypes)

opportunity_id          int64
content_id              int64
vol_requests            int64
event_time              int64
title                  object
hits                    int64

③ 划分训练集和测试集。

我们将数据分成两个部分,训练集用于建立模型,而测试集则用于评估模型的预测能力,这么做的目的是防止模型的过拟合。

sklearn是机器学习中一个常用的Python第三方模块,我们可以直接调用这个模块中的train_test_split【1】函数对数据集进行划分。默认是将数据集大小的75%设置为训练集,25%设置为测试集,如下示例。

from sklearn.model_selection import train_test_split
import numpy as np

X, y = np.arange(8).reshape((4, 2)), range(4)
print(X)
print(list(y))

[[0 1]
 [2 3]
 [4 5]
 [6 7]]
[0, 1, 2, 3]

X_train, X_test, y_train, y_test = train_test_split(X, y)
print(X_train,  X_test, y_train, y_test)

[[4 5]
 [6 7]
 [2 3]] [[0 1]] [2, 3, 1] [0]

在大多情况下,使用train_test_split函数中的默认参数设置不会有什么问题,但如果数据集不是均匀分布的,则划分的训练集和测试集中的数据可能就不具有代表性,会使模型的预测效果出现误差。

这时,分层抽样是一个更好的选择,可以通过设置参数stratify来实现。

下面的示例中,列class里面有100个样本,80个class1和20个class2,我们希望通过分层抽样,得到这样的划分:

【训练集】75个样本,60个class1,15个class2

【测试集】25个样本,20个class1,5个class2

print(df['class'].value_counts())

class1    80
class2    20
Name: class, dtype: int64

X = df[['number']]
y = df[['class']]

# 设置参数stratify
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y)
print(y_train['class'].value_counts())
print(y_test['class'].value_counts())

class1    60
class2    15
Name: class, dtype: int64
class1    20
class2     5
Name: class, dtype: int64

# 如果未设置stratify,效果如下
X_train, X_test, y_train, y_test = train_test_split(X, y)
print(y_train['class'].value_counts())
print(y_test['class'].value_counts())

class1    57
class2    18
Name: class, dtype: int64
class1    23
class2     2
Name: class, dtype: int64

02 数据标准化

当模型属于线性空间模型;数据集中的某个特征方差很大;数据集的特征是连续的且量纲不同;或者存在线性假定的时候,我们需要进行数据标准化处理。

本文主要介绍两种方法,一个是log函数标准化法,另一个是特征缩放法。

① log函数标准化法

如果发现数据集中某一列特征的方差很大,可以用log函数进行处理,在Python中log()函数默认是以e为底的对数函数。

从下面的示例中可以观察到,在没有用log()函数进行处理之前,col2列数据的方差很大,但经过log()函数处理之后,两列数据方差的差距明显缩小。

col1   col2
0  1.00    3.0
1  1.20   45.5
2  0.75   28.0
3  1.60  100.0

print(df.var())
col1       0.128958
col2    1691.729167
dtype: float64

import numpy as np
df['log_2'] = np.log(df['col2'])
print(df)

   col1   col2     log_2
0  1.00    3.0  1.098612
1  1.20   45.5  3.817712
2  0.75   28.0  3.332205
3  1.60  100.0  4.605170

print(np.var(df[['col1', 'log_2']]))
col1     0.096719
log_2    1.697165
dtype: float64

② 特征缩放法

当特征的量纲不同、使用线性模型时,可以用特征缩放的方法进行标准化,目的是把数据转化成标准正态分布,可以通过调用sklearn中的StandardScaler类实现。

在如下示例中,可以观察到df中各列内部数据的差距不是很大,但是列与列之间的大小却有明显差距,需要进行标准化处理。

col1  col2   col3
0  1.00  48.0  100.0
1  1.20  45.5  101.3
2  0.75  46.2  103.5
3  1.60  50.0  104.0

print(df.var())

col1    0.128958
col2    4.055833
col3    3.526667
dtype: float64


from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
df_scaled = pd.DataFrame(ss.fit_transform(df), columns=df.columns)

print(df_scaled)

       col1      col2      col3
0 -0.442127  0.329683 -1.352726
1  0.200967 -1.103723 -0.553388
2 -1.245995 -0.702369  0.799338
3  1.487156  1.476409  1.106776

print(df.var())

col1    1.333333
col2    1.333333
col3    1.333333
dtype: float64

03 特征工程
特征工程是根据原始特征创建新特征的过程,目的是让特征更准确地预测未知数据,这需要我们对数据集有很深入的理解和把握。

比如说,如果目标是想要评估一个班级整体的学习情况,那每个学生的考试成绩本身是没有太大参考价值的,而平均值是更好的一个选择。

不同的数据集和模型所采用的特征工程方法是不同的,本文只介绍其中的几个供大家参考。

情景一:分类变量型特征

分类变量一般是文本数据,需要先转化成数字,再输入到模型中,可以通过Pandas和sklearn两种方式实现。

① 调用sklearn中的LabelEncoder函数。

hiking[["Accessible"]].head()

  Accessible
0          Y
1          N
2          N
3          N
4          N

from sklearn.preprocessing import LabelEncoder

enc = LabelEncoder()
hiking["Accessible_enc"] = enc.fit_transform(hiking["Accessible"])

print(hiking[["Accessible_enc", "Accessible"]].head())

   Accessible_enc Accessible
0               1          Y
1               0          N
2               0          N
3               0          N
4               0          N

② 调用Pandas中的get_dummies()【2】函数。这里我们导入tushare.pro中的行业数据作为示例进行演示。

import tushare as ts

pro = ts.pro_api()

df = pro.stock_basic(exchange='', list_status='L', fields='ts_code, industry')
df = df.head()
print(df)

     ts_code industry
0  000001.SZ       银行
1  000002.SZ     全国地产
2  000004.SZ     生物制药
3  000005.SZ     环境保护
4  000006.SZ     区域地产

df_enc = pd.get_dummies(df['industry'])
df_enc.index = df['ts_code']
print(df_enc)

           全国地产  区域地产  环境保护  生物制药  银行
ts_code                              
000001.SZ     0     0     0     0   1
000002.SZ     1     0     0     0   0
000004.SZ     0     0     0     1   0
000005.SZ     0     0     1     0   0
000006.SZ     0     1     0     0   0

情景二:数字型特征

① 取平均值

print(running_times_5k)

      name  run1  run2  run3  run4  run5   
0      Sue  20.1  18.5  19.6  20.3  18.3  
1     Mark  16.5  17.1  16.9  17.6  17.3  
2     Sean  23.5  25.1  25.2  24.6  23.9 
3     Erin  21.7  21.1  20.9  22.1  22.2  
4    Jenny  25.8  27.1  26.1  26.7  26.9  
5  Russell  30.9  29.6  31.4  30.4  29.9  


run_columns = ["run1", "run2", "run3", "run4", "run5"]
running_times_5k["mean"] = running_times_5k.apply(lambda row: row[run_columns].mean(), axis=1)

print(running_times_5k)

      name  run1  run2  run3  run4  run5   mean
0      Sue  20.1  18.5  19.6  20.3  18.3  19.36
1     Mark  16.5  17.1  16.9  17.6  17.3  17.08
2     Sean  23.5  25.1  25.2  24.6  23.9  24.46
3     Erin  21.7  21.1  20.9  22.1  22.2  21.60
4    Jenny  25.8  27.1  26.1  26.7  26.9  26.52
5  Russell  30.9  29.6  31.4  30.4  29.9  30.44

② 提取日期中的月份

import tushare as ts

pro = ts.pro_api()

df = pro.daily(ts_code='000001.SZ', start_date='20180701', end_date='20180706')[['ts_code', 'trade_date', 'close']]
df.sort_values('trade_date', inplace=True)                              # 升序排列
df['trade_date'] = pd.to_datetime(df['trade_date'])                     # 将时间转化成日期类型
df["trade_date_month"] = df["trade_date"].apply(lambda row: row.month)  # 提取月份

print(df)

     ts_code trade_date  close  trade_date_month
4  000001.SZ 2018-07-02   8.61                 7
3  000001.SZ 2018-07-03   8.67                 7
2  000001.SZ 2018-07-04   8.61                 7
1  000001.SZ 2018-07-05   8.60                 7
0  000001.SZ 2018-07-06   8.66                 7

情景三:文本型特征

文本型数据相对会复杂一点,一般来说可以分成两步。第一步,先从文本中提取有效信息,可能是字符串的一部分,也可能是数字,第二步,把它们转化成特征。在下面的示例中,简单介绍了如何用正则表达式re提取文本中的数字。

import re

print(hiking[['Length']].head())

       Length
0   0.8 miles
1    1.0 mile
2  0.75 miles
3   0.5 miles
4   0.5 miles

# 定义函数:提取文本中的数字
def return_mileage(length):
    pattern = re.compile(r"\d+\.\d+")
    mile = re.match(pattern, length)

    if mile is not None:
        return float(mile.group(0))

# 将该函数应用到Length列中
hiking["Length_num"] = hiking["Length"].apply(lambda row: return_mileage(row))
print(hiking[["Length", "Length_num"]].head())

       Length  Length_num
0   0.8 miles        0.80
1    1.0 mile        1.00
2  0.75 miles        0.75
3   0.5 miles        0.50
4   0.5 miles        0.50

04 特征选择
特征选择,是指从已有的特征库中,选出一些最有效特征以降低数据集维度的过程,从而最优化模型的预测效果,是提高学习算法性能的一个重要手段。

① 去除冗余特征。

比如,在线性回归模型中,由于假设特征之间是相互独立的,需要删除相关性强的特征。可以直接用.drop()函数删除。

print(df)

      A     B     C
0  3.06  3.92  1.04
1  2.76  3.40  1.05
2  3.24  3.17  1.03

print(df.corr())

          A         B         C
A  1.000000 -0.159921 -0.989743
B -0.159921  1.000000  0.299299
C -0.989743  0.299299  1.000000

# 创建列表:包含冗余数据列名
to_drop = ['C']

# 删掉这些列
df_subset = df.drop(to_drop, axis=1)

      A     B
0  3.06  3.92
1  2.76  3.40
2  3.24  3.17

② 主成分分析法降维。

Principal Component Analysis,即主成分分析PCA,是指把多指标合成为少数几个相互无关的综合指标的过程,其中每个主成分都能够反映原始变量的绝大部分信息,而且所含信息互不重复,可以起到降低维度的作用。

主成分分析法是一种数学变换的方法, 它把给定的一组相关变量通过线性变换转成另一组不相关的变量,这些新的变量按照方差依次递减的顺序排列。

同样,我们可以直接调用sklearn中的PCA类【3】。

print(X)

      A     B     C
0  3.06  3.92  1.04
1  2.76  3.40  1.05
2  3.24  3.17  1.03

from sklearn.decomposition import PCA

# 可以通过设置参数n_components降维,默认与原始数据的维度相同
pca = PCA()

transformed_X = pca.fit_transform(X)
print(transformed_X)

[[ 4.11310289e-01 -1.07865458e-01  7.28764779e-18]
 [-5.33422295e-02  2.72395027e-01  7.28764779e-18]
 [-3.57968060e-01 -1.64529570e-01  7.28764779e-18]]

# 查看不同特征的方差占比
print(pca.explained_variance_ratio_)

[7.26668849e-01 2.73331151e-01 3.85723283e-34]

05 总结

本文主要介绍了在应用机器学习模型之前的准备工作——数据预处理,包括划分训练集和测试集、数据标准化、特征工程、特征选择这四个部分。

相关的官方文档和参考资料已附在下面,感兴趣的小伙伴可以自行查阅更多内容!

您的大名:
万水千山总是情,给个打赏行不行。 打赏
标签: python, 机器学习

非特殊说明,本博所有文章均为博主原创。

评论啦~