如何为管道中的异常值删除实现 Python 自定义类?

Posted

技术标签:

【中文标题】如何为管道中的异常值删除实现 Python 自定义类?【英文标题】:How to implement a Python custom class for outliers removal in pipeline? 【发布时间】:2021-05-24 13:39:54 【问题描述】:

我正在尝试通过 Isolation Forest 算法实现一个 Python 自定义类,用于异常值检测和删除。我的计划是在GridSearchCV 中使用它来调整神经网络(回归)的超参数。这是我的代码,

class OutlierExtractor(BaseEstimator, TransformerMixin):
    def __init__(self, contamination):
        self.contamination = contamination
        self.mask = None

    def fit(self, X, y):
        iso = IsolationForest(contamination = self.contamination)
        yhat = iso.fit_predict(X)
        mask = yhat != -1
        self.mask = mask
        return self
    
    def transform(self, X, y):
        X = X[self.mask, :]
        y = y[self.mask]
        return (X, y)

和管道

estimator = Pipeline([
            ('outliers', OutlierExtractor(0.1)),...
            ]

但是,运行grid_result = grid.fit(X, Y) 会给出错误transform() missing 1 required positional argument: 'y'。 如何解决? 此外,如果能够对污染参数进行调整,那就太好了。

【问题讨论】:

【参考方案1】:

运行grid_result = grid.fit(X, Y) 它给出了错误transform() missing 1 required positional argument: 'y'

尽管您没有提供grid 的完整回溯和实现细节,但我几乎可以肯定问题出在您的OutlierExtractor.transform 方法中。它不符合 scikit-learn 转换器 API,其中 transform 方法预计仅返回(修改的)样本 X,但您同时返回 Xy。错误可能是由其他原因引起的,您可能必须先解决这些问题。

如何解决?此外,如果能够对污染参数进行调整,那就太好了。

恐怕无法在 scikit-learn 管道中设置异常值检测。修复 transform 也无济于事。理想情况下,我们希望在Pipeline 中支持中间 异常值检测(我们有Pipeline.fit_predict 仅用于最后 步异常值检测,例如当IsolationForest是管道中的最终预测器)。但是,这还没有实现。如果我没记错的话,scikit-learn 的官方 github 存储库中有一个关于这个问题的问题。另外,这里有一个 scikit-learn 增强提案SLEP001,它也涉及异常值检测。

为了在模型选择中包含IsolationForest,您需要手动为其创建一个参数网格,并为该网格的每个条目启动GridSearchCV。这是一个最小的例子:

from sklearn.ensemble import IsolationForest
from sklearn.model_selection import ParameterGrid  # or ParameterSampler
from sklearn.model_selection import train_test_split, GridSearchCV

X, y = # your data
grid = GridSearchCV( # your model grid search )

isolation_forest = IsolationForest()
isolation_forest_params = 
    'max_features': (0.5, 0.75, 1.0),
    'bootstrap': (False, True),
    'contamination': (0.1, 0.2, 0.3),

isolation_forest_param_grid = ParameterGrid(isolation_forest_params)

# Here we split data once but you might want to use
# nested cross-validated grid search instead.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1)

best_score, best_params = 0, 
for params in isolation_forest_param_grid:
    isolation_forest.set_params(**params)
    outlier_mask = isolation_forest.fit_predict(X_train)
    X_inliers, y_inliers = X_train[outlier_mask == 1], y_train[outlier_mask == 1]

    grid.fit(X_inliers, y_inliers)
    score = grid.score(X_test, y_test)
    if score > best_score:
        best_score = score
        best_params = grid.best_params_
        # Prepending 'if' prefix so that parameter names will not overlap.
        best_params.update(f'if__k': v for k, v in params.items())

【讨论】:

以上是关于如何为管道中的异常值删除实现 Python 自定义类?的主要内容,如果未能解决你的问题,请参考以下文章

Android:如何为 Android ListView 实现这样的操作?

检测和删除异常值作为管道的步骤

如何为通过 SwiftUI 中的自定义结构传递的 @State 值设置动画

如何为 Spring Boot Rest 使用自定义异常?

System.Text.Json:如何为枚举值指定自定义名称?

如何为事务管理编写自定义过滤器