13.4 scikit-learn介绍
scikit-learn是一个广泛使用、用途多样的Python机器学习库。它包含多种标准监督和非监督机器学习方法和模型选择和评估、数据转换、数据加载和模型持久化工具。这些模型可以用于分类、聚合、预测和其它任务。
机器学习方面的学习和应用scikit-learn和TensorFlow解决实际问题的线上和纸质资料很多。本节中,我会简要介绍scikit-learn API的风格。
写作此书的时候,scikit-learn并没有和pandas深度结合,但是有些第三方包在开发中。尽管如此,pandas非常适合在模型拟合前处理数据集。
举个例子,我用一个Kaggle竞赛的经典数据集,关于泰坦尼克号乘客的生还率。我们用pandas加载测试和训练数据集:
In [86]: train = pd.read_csv('datasets/titanic/train.csv')In [87]: test = pd.read_csv('datasets/titanic/test.csv')In [88]: train[:4]Out[88]:PassengerId Survived Pclass \0 1 0 31 2 1 12 3 1 33 4 1 1Name Sex Age SibSp \0 Braund, Mr. Owen Harris male 22.0 11 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 12 Heikkinen, Miss. Laina female 26.0 03 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1Parch Ticket Fare Cabin Embarked0 0 A/5 21171 7.2500 NaN S1 0 PC 17599 71.2833 C85 C2 0 STON/O2. 3101282 7.9250 NaN S3 0 113803 53.1000 C123 S
statsmodels和scikit-learn通常不能接收缺失数据,因此我们要查看列是否包含缺失值:
In [89]: train.isnull().sum()Out[89]:PassengerId 0Survived 0Pclass 0Name 0Sex 0Age 177SibSp 0Parch 0Ticket 0Fare 0Cabin 687Embarked 2dtype: int64In [90]: test.isnull().sum()Out[90]:PassengerId 0Pclass 0Name 0Sex 0Age 86SibSp 0Parch 0Ticket 0Fare 1Cabin 327Embarked 0dtype: int64
在统计和机器学习的例子中,根据数据中的特征,一个典型的任务是预测乘客能否生还。模型现在训练数据集中拟合,然后用样本外测试数据集评估。
我想用年龄作为预测值,但是它包含缺失值。缺失数据补全的方法有多种,我用的是一种简单方法,用训练数据集的中位数补全两个表的空值:
In [91]: impute_value = train['Age'].median()In [92]: train['Age'] = train['Age'].fillna(impute_value)In [93]: test['Age'] = test['Age'].fillna(impute_value)
现在我们需要指定模型。我增加了一个列IsFemale,作为“Sex”列的编码:
In [94]: train['IsFemale'] = (train['Sex'] == 'female').astype(int)In [95]: test['IsFemale'] = (test['Sex'] == 'female').astype(int)
然后,我们确定一些模型变量,并创建NumPy数组:
In [96]: predictors = ['Pclass', 'IsFemale', 'Age']In [97]: X_train = train[predictors].valuesIn [98]: X_test = test[predictors].valuesIn [99]: y_train = train['Survived'].valuesIn [100]: X_train[:5]Out[100]:array([[ 3., 0., 22.],[ 1., 1., 38.],[ 3., 1., 26.],[ 1., 1., 35.],[ 3., 0., 35.]])In [101]: y_train[:5]Out[101]: array([0, 1, 1, 1, 0])
我不能保证这是一个好模型,但它的特征都符合。我们用scikit-learn的LogisticRegression模型,创建一个模型实例:
In [102]: from sklearn.linear_model import LogisticRegressionIn [103]: model = LogisticRegression()
与statsmodels类似,我们可以用模型的fit方法,将它拟合到训练数据:
In [104]: model.fit(X_train, y_train)Out[104]:LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,penalty='l2', random_state=None, solver='liblinear', tol=0.0001,verbose=0, warm_start=False)
现在,我们可以用model.predict,对测试数据进行预测:
In [105]: y_predict = model.predict(X_test)In [106]: y_predict[:10]Out[106]: array([0, 0, 0, 0, 1, 0, 1, 0, 1, 0])
如果你有测试数据集的真是值,你可以计算准确率或其它错误度量值:
(y_true == y_predict).mean()
在实际中,模型训练经常有许多额外的复杂因素。许多模型有可以调节的参数,有些方法(比如交叉验证)可以用来进行参数调节,避免对训练数据过拟合。这通常可以提高预测性或对新数据的健壮性。
交叉验证通过分割训练数据来模拟样本外预测。基于模型的精度得分(比如均方差),可以对模型参数进行网格搜索。有些模型,如logistic回归,有内置的交叉验证的估计类。例如,logisticregressioncv类可以用一个参数指定网格搜索对模型的正则化参数C的粒度:
In [107]: from sklearn.linear_model import LogisticRegressionCVIn [108]: model_cv = LogisticRegressionCV(10)In [109]: model_cv.fit(X_train, y_train)Out[109]:LogisticRegressionCV(Cs=10, class_weight=None, cv=None, dual=False,fit_intercept=True, intercept_scaling=1.0, max_iter=100,multi_class='ovr', n_jobs=1, penalty='l2', random_state=None,refit=True, scoring=None, solver='lbfgs', tol=0.0001, verbose=0)
要手动进行交叉验证,你可以使用cross_val_score帮助函数,它可以处理数据分割。例如,要交叉验证我们的带有四个不重叠训练数据的模型,可以这样做:
In [110]: from sklearn.model_selection import cross_val_scoreIn [111]: model = LogisticRegression(C=10)In [112]: scores = cross_val_score(model, X_train, y_train, cv=4)In [113]: scoresOut[113]: array([ 0.7723, 0.8027, 0.7703, 0.7883])
默认的评分指标取决于模型本身,但是可以明确指定一个评分。交叉验证过的模型需要更长时间来训练,但会有更高的模型性能。
