【问题标题】:scikit-learn transformer that bins data based on user supplied cut pointsscikit-learn 转换器,根据用户提供的切割点对数据进行分类
【发布时间】:2020-01-03 00:48:29
【问题描述】:

我正在尝试在 scikit-learn 管道中包含一个转换器,它将根据我自己提供的切点将一个连续的数据列分成 4 个值。 KBinsDiscretizer 的当前参数不起作用,主要是因为 strategy 参数只接受 {‘uniform’, ‘quantile’, ‘kmeans’}

pandas 中已经有 cut() 函数,所以我想我需要创建一个自定义转换器来包装 cut() 函数行为。

期望行为(非实际)

X = [[-2, -1, -0.5, 0, 0.5, 1, 2]]
est = Discretizer(bins=[-float("inf"), -1.0, 0.0, 1.0, float("inf")], 
                  encode='ordinal')
est.fit(X)  
est.transform(X)
# >>> array([[0., 0., 1., 1., 2., 2., 3.]])

上面的结果假设 bin 包括最右边的边缘和最低的边缘。像这样pd.cut() 命令将提供:

import pandas as pd
import numpy as np
pd.cut(np.array([-2, -1, -0.5, 0, 0.5, 1, 2]),
       [-float("inf"), -1.0, 0.0, 1.0, float("inf")], 
       labels=False, right=True, include_lowest=True)
# >>> array([0, 0, 1, 1, 2, 2, 3])

【问题讨论】:

    标签: python pandas numpy scikit-learn sklearn-pandas


    【解决方案1】:

    唯一的问题是您只是在转换传入的数据,而不是在拟合阶段从训练中学习 bin 并在转换阶段使用该信息。理想情况下,您应该在拟合期间学习 bin 边缘并在变换期间分配 bin。

    【讨论】:

      【解决方案2】:

      这似乎对我作为自定义转换器有用。 scikit-learn 需要数字数组,所以我不确定您是否可以实现 pd.cut() 的功能,该功能将返回标签。出于这个原因,我在下面的实现中将其硬编码为False

      import pandas as pd
      from sklearn.base import BaseEstimator, TransformerMixin
      
      class CutTransformer(BaseEstimator, TransformerMixin):
          def __init__(self, bins, right=True, retbins=False,
                       precision=3, include_lowest=False,
                       duplicates='raise'):
              self.bins = bins
              self.right = right
              self.labels = False
              self.retbins = retbins
              self.precision = precision
              self.include_lowest = include_lowest
              self.duplicates = duplicates
      
          def fit(self, X, y=None):
              return self
      
          def transform(self, X, y=None):
              assert isinstance(X, pd.DataFrame)
              for jj in range(X.shape[1]):
                  X.iloc[:, jj] = pd.cut(x=X.iloc[:, jj].values, **self.__dict__)
              return X
      

      一个例子

      df = pd.DataFrame(data={'rand': np.random.rand(5)})
      df
          rand
      0   0.030653
      1   0.542533
      2   0.159646
      3   0.963112
      4   0.539530
      
      ct = CutTransformer(bins=np.linspace(0, 1, 5))
      ct.transform(df)
          rand
      0   0
      1   2
      2   0
      3   3
      4   2
      

      【讨论】:

        【解决方案3】:

        使用FunctionTransformer() 方法可以替代具有更多开销的自定义转换器,该方法适用于无状态操作,例如预定义 bin 的情况。

        import pandas as pd
        from sklearn.preprocessing import FunctionTransformer
        from sklearn.pipeline import make_pipeline
        
        def ftransformer_cut(X, **kwargs):
            if 'labels' not in kwargs:
                kwargs['labels'] = False
        
            assert isinstance(X, np.ndarray)
            assert kwargs['labels'] == False
        
            for jj in range(X.shape[1]):
                X[:, jj] = pd.cut(x=X[:, jj], **kwargs)
        
            return X
        
        pipeline = make_pipeline(
            FunctionTransformer(ftransformer_cut,
                                kw_args={'bins': np.linspace(0, 1, 5)})
        )
        
        df = pd.DataFrame(data={'rand': np.random.rand(5)})
            rand
        0   0.823234
        1   0.336883
        2   0.713595
        3   0.408184
        4   0.038
        
        pipeline.transform(df)
        array([[3.],
               [1.],
               [2.],
               [1.],
               [0.]])
        

        【讨论】:

          猜你喜欢
          • 2015-03-07
          • 2014-10-27
          • 2019-10-08
          • 1970-01-01
          • 2017-06-30
          • 2012-11-24
          • 1970-01-01
          • 2018-01-27
          • 1970-01-01
          相关资源
          最近更新 更多