用scikit-learn做数据预处理

数据预处理是进行机器学习的必要环节,对原始数据进行加工,比如标准化、归一化、二进制化、特征编码、插补缺失值、生成多项式特征等。

scikit-learn 是 Python 下的机器学习工具包,集成了预处理、降维、聚类、分类等方法。我们用此工具来介绍数据预处理。

主要应用的是 preprocessing 类。

标准化 Standardization

常用的标准化方法为 z-score 法,目的是将传入的矩阵变为每列均值为0、方差为1的标准型,因为机器学习中的函数许多是以0为中心的,例如 sigmoid 函数,方差为1可以使数据分布均匀,防止某个特征数据过大影响模型的训练。

z-score 公式

我们用 sklearn 中的 preprocessing 类中的 scale 方法简单进行标准化。

>>> from sklearn import preprocessing
>>> import numpy as np
>>> X = np.array([[ 1., -1.,  2.],
...               [ 2.,  0.,  0.],
...               [ 0.,  1., -1.]])
>>> X_scaled = preprocessing.scale(X)

>>> X_scaled                                          
array([[ 0.  ..., -1.22...,  1.33...],
       [ 1.22...,  0.  ..., -0.26...],
       [-1.22...,  1.22..., -1.06...]])

或者可以将计算均值和方差与转换的步骤分开。

>>> scaler = preprocessing.StandardScaler().fit(X)
>>> scaler
StandardScaler(copy=True, with_mean=True, with_std=True)

>>> scaler.transform(X)                               
array([[ 0.  ..., -1.22...,  1.33...],
       [ 1.22...,  0.  ..., -0.26...],
       [-1.22...,  1.22..., -1.06...]])

fit 是计算过程,transform 是转换过程。transform 的一个好处是可以继续使用 fit 的数据,例如 transform 训练数据之后之后可以直接 transform 测试数据。

有时标准化时要求把数据缩放到某一个范围中,preprocessing 类也提供了 MinMaxScaler 方法,设置 MinMaxScaler 的参数 feature_range=(min, max) 。
当然最常用的就是(0,1)范围。

>>> X_train = np.array([[ 1., -1.,  2.],
...                     [ 2.,  0.,  0.],
...                     [ 0.,  1., -1.]])
...
>>> min_max_scaler = preprocessing.MinMaxScaler(feature_range=(0, 1))
>>> X_train_minmax = min_max_scaler.fit_transform(X_train)
>>> X_train_minmax
array([[ 0.5       ,  0.        ,  1.        ],
       [ 1.        ,  0.5       ,  0.33333333],
       [ 0.        ,  1.        ,  0.        ]])
归一化 Normalization

归一化是将每个样本缩放到单位范数(可以粗略地理解为向量的函数)的过程。如果后面要使用如二次型(点积)或者其它核方法计算两个样本之间的相似性这个方法会很有用。归一化的计算方法是 1除以p-范数。归一化之后的样本的 p-范数等于1。

向量的p-范数

preprocessing 类下的 normalize 方法可以直接归一化,并可以选择 l1 范数与 l2 范数,默认是 l2 范数。

>>> X = [[ 1., -1.,  2.],
...      [ 2.,  0.,  0.],
...      [ 0.,  1., -1.]]
>>> X_normalized = preprocessing.normalize(X, norm='l2')

>>> X_normalized                                      
array([[ 0.40..., -0.40...,  0.81...],
       [ 1.  ...,  0.  ...,  0.  ...],
       [ 0.  ...,  0.70..., -0.70...]])

normalize 也同样有 fit 方法与 transform 方法。

>>> normalizer = preprocessing.Normalizer().fit(X)  # fit does nothing
>>> normalizer
Normalizer(copy=True, norm='l2')

>>> normalizer.transform(X)                            
array([[ 0.40..., -0.40...,  0.81...],
       [ 1.  ...,  0.  ...,  0.  ...],
       [ 0.  ...,  0.70..., -0.70...]])
.
>>> normalizer.transform([[-1.,  1., 0.]])             
array([[-0.70...,  0.70...,  0.  ...]])
二进制化 Binarization

二进制化的方法是设定一个阈值,样本值比阈值大的为1,小的为0。

文本处理领域愿意使用二进制化,虽然归一化和 TF-IDF 加工的特征表现得更好,但使用二进制化来简化数据更为普遍(可能简化概率推理)。

>>> X = [[ 1., -1.,  2.],
...      [ 2.,  0.,  0.],
...      [ 0.,  1., -1.]]

>>> binarizer = preprocessing.Binarizer().fit(X)  # fit does nothing
>>> binarizer
Binarizer(copy=True, threshold=0.0)

>>> binarizer.transform(X)
array([[ 1.,  0.,  1.],
       [ 1.,  0.,  0.],
       [ 0.,  1.,  0.]])

阈值调整需要设置 threshold 参数,下面代码是设置阈值1.1的情况。

>>> binarizer = preprocessing.Binarizer(threshold=1.1)
>>> binarizer.transform(X)
array([[ 0.,  0.,  1.],
       [ 1.,  0.,  0.],
       [ 0.,  0.,  0.]])
类别特征编码 Encoding categorical features

比如现在有特征 ["male", "female"] ["from Europe", "from US", "from Asia"],
["uses Firefox", "uses Chrome", "uses Safari", "uses Internet Explorer"],
平常我们将特征进行整数编码.

["male", "from US", "uses Internet Explorer"] 编码应该是 [0, 1, 3]

["female", "from Asia", "uses Chrome"]的编码应该是[1,2,1]

但是 scikit-learn 估计器不能直接使用这种整数型的编码,它的输入最好是连续型的,估计器也可能把整数编码特征特征误解为有序的数据,这会有害于模型训练。

类别特征编码用的是 OneHotEncoder 方法,占第几位的特征值就是1,其余为0。例如 ["male", "female"] 有两个特征,male 占第1个位置,剩下的0,male 就是 [1,0],female 就是 [0,1]; ["from Europe", "from US", "from Asia"]有3个特征,"from Europe"就是 [1,0,0],"from US" 就是 [0,1,0],"from Asia"就是 [0,0,1],以此类推。

["male", "from US", "uses Internet Explorer"]的整数编码[0,1,3]的二进制编码就是
[1,0, 0,1,0, 0,0,0,1]。

代码实现用的是 preprocessing 类下的 OneHotEncoder 方法。

>>> enc = preprocessing.OneHotEncoder()
>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])  
OneHotEncoder(categorical_features='all', dtype=<... 'numpy.float64'>,
       handle_unknown='error', n_values='auto', sparse=True)
>>> enc.transform([[0, 1, 3]]).toarray()
array([[ 1.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  1.]])
插补缺失值 Imputation of missing values

以往对于数据中有丢失值的情况,做法是把该数据所在行和列都删掉,这样的后果是容易丢失重要的数据。

imputer 的方法利用平均值、中位数或出现频率最高的数据对缺失的数据进行填补。代码如下,NaN 即位丢失的值。

>>> import numpy as np
>>> from sklearn.preprocessing import Imputer
>>> imp = Imputer(missing_values='NaN', strategy='mean', axis=0)
>>> imp.fit([[1, 2], [np.nan, 3], [7, 6]])
Imputer(axis=0, copy=True, missing_values='NaN', strategy='mean', verbose=0)
>>> X = [[np.nan, 2], [6, np.nan], [7, 6]]
>>> print(imp.transform(X))                           
[[ 4.          2.        ]
 [ 6.          3.666...]
 [ 7.          6.        ]]

strategy 告诉了本代码用 mean 平均值找补,fit 是用它括号里的数据计算平均值,transform 是应用变换。

生成多项式特征 Generating polynomial features

生成多项式的预处理方式是为了给输入数据增加复杂性。处理后的特征会获得高阶的数据和交叉的数据。

用到的是 preprocessing 下的 PolynomialFeatures 方法。

>>> import numpy as np
>>> from sklearn.preprocessing import PolynomialFeatures
>>> X = np.arange(6).reshape(3, 2)
>>> X                                                 
array([[0, 1],
       [2, 3],
       [4, 5]])
>>> poly = PolynomialFeatures(2)
>>> poly.fit_transform(X)                             
array([[  1.,   0.,   1.,   0.,   0.,   1.],
       [  1.,   2.,   3.,   4.,   6.,   9.],
       [  1.,   4.,   5.,  16.,  20.,  25.]])

PolynomialFeatures(2) 指的是最多生成二次项。
X的特征值由(X1,X2)变成了(1,X1,X2,X12,X1X2,X22)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容