sklearn是一个基于Python的机器学习包,它提供了一个各种数据转换的集合,用于根据需要修改数据。许多简单的数据清理 过程,如删除列等,往往是在数据上手动完成的,所以我们需要使用自定义代码。sklearn包提供了一种机制来规范这些独特的数据转换,这样它们就可以像其他转换一样使用,既可以直接用于数据,也可以作为建模管道的一部分。在这篇文章中,你将学习如何为sklearn创建和应用自定义数据转换。以下是要介绍的文章。
目录
- 如何使用sklearn建立一个自定义数据转换器?
- 创建自定义变换器
让我们先来了解一下自定义数据转换器。
如何使用sklearn建立一个自定义数据转换器?
sklearn是一个基于Python的机器学习包,它直接提供了许多不同的数据准备策略,如缩放数字输入变量和修改变量概率分布。修改原始数据以使其适合机器学习算法的过程被称为数据准备。
当使用数据抽样方法(如k-fold交叉验证)评估模型性能时,这些转换将允许在不泄露数据的情况下对数据集进行拟合和应用转换。
虽然sklearn提供的数据准备技术很全面,但可能有必要执行额外的数据准备过程。这些额外的过程通常是在建模前手动进行的,需要创建定制的代码。危险的是,这些数据准备阶段会被不连贯地执行。
这个方法是使用FunctionTransformer类来构建sklearn中的自定义数据转换。这个类让用户定义一个将被调用以改变数据的函数。定义函数并进行任何有效的改变,如修改数值或消除数据列(不是删除行)。然后,该类可以在sklearn中使用,就像其他数据转换一样,例如,直接转换数据或在建模管道中。
在继续创建自定义变换器之前,有几件事情值得熟悉一下:
- 在管道中使用scikit-learn变换器或使用fit transform()技术。
- 类的创建、继承,以及Python中的super()方法。
创建自定义转化器
我们只需要满足几个基本参数就可以开发一个自定义变换器:
- 初始化一个转化器类。
- 来自sklearn.base模块的BaseEstimator和TransformerMixin类被这个类继承。
- 实例方法fit()和transform()由该类()实现。为了与Pipelines兼容,这些方法必须有X和Y两个参数,而transform()必须返回pandas DataFrame或NumPy数组。
创建一个基本的自定义转化器
from numpy.random import randint
from sklearn.base import BaseEstimator, TransformerMixin
class basictransformer(BaseEstimator, TransformerMixin):
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
X["cust_num"] = randint(0, 10, X.shape[0])
return X
df_basic = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})
pipe = Pipeline(
steps=[
("use_custom_transformer", basicTransformer())
]
)
transformed_df = pipe.fit_transform(df_basic)
df_basic
建立一个自定义类,在其中定义fit和transform函数。这两个函数对于管道的顺利运行都是必要的。该管道将执行类中提到的所有操作。而输出的数据框将如下图所示:

让我们建立一个自定义的转化器,并将其应用于数据框,预测一些数值。从导入必要的操作库开始:
import numpy as np
import pandas as pd
from sklearn.metrics import mean_squared_error,r2_score
from sklearn.pipeline import FeatureUnion, Pipeline, make_pipeline
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
读取、预处理和数据分析
本文使用了一个与保险业有关的数据集,其中保险费用将根据不同的特征和观察结果进行预测:
df=pd.read_csv("/content/insurance.csv")
df_util=pd.get_dummies(data=df,columns=['sex','smoker','region'],drop_first=True)


这张图是代表保险费用在客户身体质量指数(BMI)方面的分布,并按照客户的年龄进行分类。
按照70:30的标准比例拆分数据进行训练和验证:
X=df_util.drop(['charges'],axis=1)
y=df_util['charges']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.30, random_state=42)
创建一个自定义的转化器,并使用该转化器对学习者的训练数据进行转化:
class CustomTransformer(BaseEstimator, TransformerMixin):
def __init__(self, feature_name, additional_param = "SM"):
print('\n...intializing\n')
self.feature_name = feature_name
self.additional_param = additional_param
def fit(self, X, y = None):
print('\nfiting data...\n')
print(f'\n \U0001f600 {self.additional_param}\n')
return self
def transform(self, X, y = None):
print('\n...transforming data \n')
X_ = X.copy()
X_[self.feature_name] = np.log(X_[self.feature_name])
return X
print("creating second pipeline...")
pipe2 = Pipeline(steps=[
('experimental_trans', CustomTransformer('bmi')),
('linear_model', LinearRegression())
])
print("fiting pipeline 2")
pipe2.fit(X_train, y_train)
preds2 = pipe2.predict(X_test)
print(f"RMSE: {np.sqrt(mean_squared_error(y_test, preds2))}\n")

采用流水线的原因是很难用单个代码块按顺序应用所有这些阶段。因为流水线在单个代码块中保持顺序,所以流水线本身成为一个估算器,能够在一个语句中完成所有操作。
如果与上述基本转化器相比,该类中还增加了一些额外的东西。在这个转化器中,用户可以提到需要执行操作的特征的名称。这个过程被称为传递参数。
线性回归模型是使用自定义转化器建立的。变换器将学习者的数值转换为对数,以减少对较大数值的偏差。这种偏差在线性回归模型中很常见。

上图是观察到的保险费用和预测的保险费用之间的回归图。可以看出,回归线充分地解释了这种关系。
因此,到目前为止,我们能够建立自定义的变压器,并利用它来预测数值。但是,如果我们想定制sklearn提供的现有转化器呢?让我们自定义序数编码器并在上面使用的数据上实现它。
from sklearn.preprocessing import OrdinalEncoder
from sklearn.preprocessing import OrdinalEncoder
class CustEncoder(OrdinalEncoder):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def transform(self, X, y=None):
transformed_data = super().transform(X)
encoded_data = pd.DataFrame(transformed_data, columns=self.feature_names_in_)
return encoded_data
data = df[['sex','smoker','region']]
enc = CustEncoder(dtype=int)
new_data = enc.fit_transform(data)
new_data[:8]
通过使用super()方法,任何预定义的转化器都可以根据需要进行定制:

结论
自定义变换器为数据预处理提供了高度的自由和控制。我们发现它们在本文中对数据处理过程中的一个阶段的封装特别有用,使代码更容易理解。更多的自定义变换器可以根据需求使用scikit learn库来构建;试一试吧;这将是值得的。