scikit-learn的介绍
一、机器学习的一般步骤
链接:机器学习的一般步骤
二、预处理数据
链接:预处理数据
三、交叉验证
链接:交叉验证
四、超参数优化
链接:超参数优化
五、文本数据处理
异构数据:当使用文本数据时
到目前为止,我们使用
scikit-learn
来训练使用数值数据的模型。
X是仅包含浮点值的NumPy数组。但是,数据集可能包含文本类型等。
import os
import pandas as pd
data = pd.read_csv(os.path.join('data', 'titanic_openml.csv'), na_values='?')
data.head()
输出:
泰坦尼克号数据集包含分类,文本和数字特征。 我们将使用此数据集来预测乘客是否在泰坦尼克号中幸存下来。
让我们将数据拆分为训练和测试集,并将幸存列用作目标。
y = data['survived']
X = data.drop(columns='survived')
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
- 首先,可以尝试使用
LogisticRegression
分类器,看看它的表现有多好。
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression()
clf.fit(X_train, y_train) #这里肯定会报错。
- 因为,大多数分类器都设计用于处理数值数据。 因此,我们需要将文本数据转换为数字数据。
- 最简单的方法是使用独热编码
OneHotEncoder
对每个文本特征进行编码。 让我们以 sex 与 embarked 列为例。 - 请注意,我们还会遇到一些缺失的数据。 我们将使用
SimpleImputer
用常量值替换缺失值。
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder
from sklearn.pipeline import make_pipeline
ohe = make_pipeline(SimpleImputer(strategy='constant'), OneHotEncoder())
X_encoded = ohe.fit_transform(X_train[['sex', 'embarked']])
X_encoded.toarray()
输出:
array([[0., 1., 0., 0., 1., 0.],
[0., 1., 1., 0., 0., 0.],
[0., 1., 0., 0., 1., 0.],
...,
[0., 1., 0., 0., 1., 0.],
[1., 0., 0., 0., 1., 0.],
[1., 0., 0., 0., 1., 0.]])
这样,可以对文本特征进行编码。 但是,我们也希望标准化数字特征。
因此,我们需要将原始数据分成2个子组并应用不同的预处理:(i)分类数据的独热编;(ii)数值数据的标准缩放(归一化)。
我们还需要处理两种情况下的缺失值: 对于分类列,我们将字符串'missing_values'
替换为缺失值,该字符串将自行解释为类别。
对于数值数据,我们将用感兴趣的特征的平均值替换缺失的数据。
col_cat = ['sex', 'embarked'] # 文本型数据
col_num = ['age', 'sibsp', 'parch', 'fare'] #数值型数据
X_train_cat = X_train[col_cat]
X_train_num = X_train[col_num]
X_test_cat = X_test[col_cat]
X_test_num = X_test[col_num]
from sklearn.preprocessing import StandardScaler
scaler_cat = make_pipeline(SimpleImputer(strategy='constant'), OneHotEncoder())
X_train_cat_enc = scaler_cat.fit_transform(X_train_cat)
X_test_cat_enc = scaler_cat.transform(X_test_cat)
scaler_num = make_pipeline(SimpleImputer(strategy='mean'), StandardScaler())
X_train_num_scaled = scaler_num.fit_transform(X_train_num)
X_test_num_scaled = scaler_num.transform(X_test_num)
- 在训练集上将文本数据和数字数据进行合并, 在测试集上也将文本数据和数字数据进行合并。
import numpy as np
from scipy import sparse
X_train_scaled = sparse.hstack((X_train_cat_enc,
sparse.csr_matrix(X_train_num_scaled))) # 文本数据和数字数据进行合并
X_test_scaled = sparse.hstack((X_test_cat_enc,
sparse.csr_matrix(X_test_num_scaled))) # 文本数据和数字数据进行合并
- 合并完成后,我们现在可以组合所有数值的信息。最后,我们使用
LogisticRegression
分类器作为模型。
clf = LogisticRegression(solver='lbfgs')
clf.fit(X_train_scaled, y_train)
accuracy = clf.score(X_test_scaled, y_test)
print('Accuracy score of the {} is {:.2f}'.format(clf.__class__.__name__, accuracy))
输出:
Accuracy score of the LogisticRegression is 0.79
- 上面案例是首先转换数据,然后拟合/评分分类器。但是,我们还希望对矩阵的不同列进行不同的处理。应使用
make_column_transformer
函数。它用于在不同的列上自动应用不同的管道。
from sklearn.impute import SimpleImputer
from sklearn.compose import make_column_transformer
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import cross_validate
pipe_cat = make_pipeline(SimpleImputer(strategy='constant'), OneHotEncoder(handle_unknown='ignore'))
pipe_num = make_pipeline(StandardScaler(), SimpleImputer())
preprocessor = make_column_transformer((col_cat, pipe_cat), (col_num, pipe_num))
pipe = make_pipeline(preprocessor, LogisticRegression(solver='lbfgs'))
param_grid = {'columntransformer__pipeline-2__simpleimputer__strategy': ['mean', 'median'],
'logisticregression__C': [0.1, 1.0, 10]}
grid = GridSearchCV(pipe, param_grid=param_grid, cv=3, n_jobs=-1)
scores = pd.DataFrame(cross_validate(grid, X, y, scoring='balanced_accuracy', cv=5, n_jobs=-1, return_train_score=True))
scores[['train_score', 'test_score']].boxplot()
输出:
<matplotlib.axes._subplots.AxesSubplot at 0x27e17d62470>
练习
加载位于./data/adult_openml.csv中的成人数据集。
制作自己的ColumnTransformer预处理器,并用分类器管道化它。对其进行微调并在交叉验证中检查预测准确性。
- Read the adult dataset located in ./data/adult_openml.csv using pd.read_csv.
- 使用pd.read_csv读取位于./data/adult_openml.csv中的成人数据集。
import os
import pandas as pd
data = pd.read_csv(os.path.join('data', 'adult_openml.csv'))
data.shape
输出:
(48842, 15)
data.head()
- 将数据集拆分为数据和目标。 目标对应于类列。
- 对于数据,删除列
fnlwgt
,capitalgain
和capitalloss
。
y = data['class']
X = data.drop(columns=['class', 'fnlwgt', 'capitalgain', 'capitalloss'])
X.head()
y.head()
- 目标未编码。
- 使用
sklearn.preprocessing.LabelEncoder
对类进行编码。
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
y = encoder.fit_transform(y)
y
输出:
array([0, 0, 0, ..., 0, 0, 1])
- 创建一个包含分类列名称的列表。 同样,对数值数据也一样。
col_cat = ['workclass', 'education', 'marital-status', 'occupation', 'relationship', 'race', 'native-country', 'sex']
col_num = ['age', 'hoursperweek']
- 创建一个管道以对分类数据进行独热编码。 使用
KBinsDiscretizer
对数值数据进行处理。 从sklearn.preprocessing
导入它。
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import KBinsDiscretizer
pipe_cat = OneHotEncoder(handle_unknown='ignore')
pipe_num = KBinsDiscretizer()
- 使用
make_column_transformer
创建预处理器,将创建好的管道应用于文本列和数字列。
from sklearn.compose import make_column_transformer
preprocessor = make_column_transformer((col_cat, pipe_cat, ), (col_num, pipe_num))
- 使用
LogisticRegression
分类器对预处理器进行管道传输。 随后定义网格搜索以找到最佳参数C.使用cross_validate
在交叉验证方案中训练和测试此工作流程。
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import cross_validate
pipe = make_pipeline(preprocessor, LogisticRegression(solver='lbfgs', max_iter=1000))
param_grid = {'logisticregression__C': [0.1, 1.0, 10]}
grid = GridSearchCV(pipe, param_grid=param_grid, cv=5, n_jobs=-1)
scores = pd.DataFrame(cross_validate(grid, X, y, scoring='balanced_accuracy', cv=3, n_jobs=-1, return_train_score=True))
scores[['train_score', 'test_score']].boxplot(whis=10)
输出:
<matplotlib.axes._subplots.AxesSubplot at 0x1efba9f7d30>
(完。)