【新智元导读】Scikit-Learn发布0.20预览版,Scikit-Learn与Pandas的新融合会使以往的工作流程更为简单,其功能也更为丰富、更具鲁棒性。
Scikit-Learn的0.20版本,将会是进行近年来最重磅的升级。
对于许多数据科学家来说,一个典型的工作流程是在Scikit-Learn进行机器学习之前,用Pandas进行探索性的数据分析。新版本的Scikit-Learn将会让这个过程变得更加简单、功能更加丰富、更鲁棒以及更加标准化。
注:本文中的0.20版本的是指预览版,最终版本目前还没有发布。
几日前,官方刚刚发布这个0.20的预览版。用户可以通过conda命令进行安装:
conda install scikit-learn=0.20rc1 -c conda-forge/label/rc -c conda-forge
也可以通过pip命令进行安装:
pip install — pre scikit-learn
ColumnTransformer、升级版OneHotEncoder介绍
随着0.20版本的升级,从Pandas到Scikit-Learn的许多工作流会变得比较相似。ColumnTransformer估计器会将一个转换应用到Pandas DataFrame(或数组)列的特定子集。
OneHotEncoder估计器不是“新生物”,但已经升级为编码字符串列。以前,它只对包含数字分类数据的列进行编码。
接下来,让我们看看这些新添加的功能是如何处理Pandas DataFrame中的字符串列的。
Kaggle最早的机器学习竞赛题目之一是《住房价格:先进的回归技术》。其目标是在给定80个特征情况下,预测房价。
数据一览
在DataFrame中读取数据并输出前几行。
>>> import pandas as pd >>> import numpy as np >>> train = pd.read_csv(‘data/housing/train.csv’) >>> train.head()
>>> train.shape (1460, 81)
从训练集中删除目标变量
目标变量是SalePrice,我们将它作为数组移除并分配给它自己的变量。我们将在后面的机器学习中用到它。
>>> y = train.pop('SalePrice').values
编码单个字符串列
首先,我们编码一个字符串列HoustStyle,它具有房子外观的值。让我们输出每个字符串值的唯一计数。
>>> vc = train['HouseStyle'].value_counts() >>> vc 1Story 726 2Story 445 1.5Fin 154 SLvl 65 SFoyer 37 1.5Unf 14 2.5Unf 11 2.5Fin 8 Name: HouseStyle, dtype: int64
这一列中有8个唯一值(unique value)。
scikitlearn Gotcha必须有2D数据
大多数Scikit-Learn估计器严格要求数据是的2D的。从技术角度讲,如果我们选择上面的列作为train[“HouseStyle”],Pandas Series是数据的单一维度。我们可以强制Pandas创建一个单列DataFrame,方法是将一个单项列表传递到方括号中,如下所示:
>>> hs_train = train[['HouseStyle']].copy() >>> hs_train.ndim 2
Scikit-Learn API对于所有的估计器都是一致的,它根据下面三个步骤来匹配(训练)数据。
下面,我们导入一个hotencoder,将它实例化,并确保返回一个密集(而不是稀疏)的数组,然后用fit_transform方法对单个列进行编码。
>>> from sklearn.preprocessing import OneHotEncoder >>> ohe = OneHotEncoder(sparse=False) >>> hs_train_transformed = ohe.fit_transform(hs_train) >>> hs_train_transformed array([[0., 0., 0., ..., 1., 0., 0.], [0., 0., 1., ..., 0., 0., 0.], [0., 0., 0., ..., 1., 0., 0.], ..., [0., 0., 0., ..., 1., 0., 0.], [0., 0., 1., ..., 0., 0., 0.], [0., 0., 1., ..., 0., 0., 0.]])
正如预期的那样,它将每个唯一的值编码为自己的二进制列。
>>> hs_train_transformed.shape (1460, 8)
注意,我们的输出是一个NumPy数组,而不是Pandas DataFrame。Scikit-Learn最初不是为了直接与Pandas整合而建的。所有的Pandas对象都在内部转换成NumPy数组,并且在转换后总是返回NumPy数组。
我们仍然可以通过其get_feature_names方法从OneHotEncoder对象获得列名。
>>> feature_names = ohe.get_feature_names() >>> feature_names array(['x0_1.5Fin', 'x0_1.5Unf', 'x0_1Story', 'x0_2.5Fin', 'x0_2.5Unf', 'x0_2Story', 'x0_SFoyer', 'x0_SLvl'], dtype=object)
接下来让我们验证估计值是否正确。首先是第一行编码的数据。
>>> row0 = hs_train_transformed[0] >>> row0 array([0., 0., 0., 0., 0., 1., 0., 0.])
这将数组中的第6个值编码为1。让我们使用布尔索引(boolean index)来显示特征名称。
>>> feature_names[row0 == 1] array(['x0_2Story'], dtype=object)
现在,让我们验证原始DataFrame列中的第一个值是否相同。
>>> hs_train.values[0] array(['2Story'], dtype=object)
使用inverse_transform来实现自动化
与大多数transformer对象一样,有一个inverse_transform方法可以返回原始数据。在这里,我们必须将row0包装在一个列表中,使其成为一个2D数组。
>>> ohe.inverse_transform([row0]) array([['2Story']], dtype=object)
我们可以通过转置整个转换后的数组来验证所有的值。
>>> hs_inv = ohe.inverse_transform(hs_train_transformed) >>> hs_inv array([['2Story'], ['1Story'], ['2Story'], ..., ['2Story'], ['1Story'], ['1Story']], dtype=object) >>> np.array_equal(hs_inv, hs_train.values) True
无论我们对训练集做什么转换,我们都必须应用到测试集。
>>> test = pd.read_csv('data/housing/test.csv') >>> hs_test = test[['HouseStyle']].copy() >>> hs_test_transformed = ohe.transform(hs_test) >>> hs_test_transformed array([[0., 0., 1., ..., 0., 0., 0.], [0., 0., 1., ..., 0., 0., 0.], [0., 0., 0., ..., 1., 0., 0.], ..., [0., 0., 1., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 1., 0.], [0., 0., 0., ..., 1., 0., 0.]])
我们又得到了8列。
>>> hs_test_transformed.shape (1459, 8)
现在,我们必须impute缺失数据。预处理模块中旧的Imputer已经被弃用。一个新的模块——impute,由一个新的估计值SimpleImputer和一个新的策略“常量”组成。默认情况下,此策略将用字符串“missing_value”来填充缺失值。我们可以选择使用fill_value参数设置它。
>>> hs_train = train[['HouseStyle']].copy() >>> hs_train.iloc[0, 0] = np.nan >>> from sklearn.impute import SimpleImputer >>> si = SimpleImputer(strategy='constant', fill_value='MISSING') >>> hs_train_imputed = si.fit_transform(hs_train) >>> hs_train_imputed array([['MISSING'], ['1Story'], ['2Story'], ..., ['2Story'], ['1Story'], ['1Story']], dtype=object)
接下来,我们可以像以前那样 |