Python scikit了解基于用户提供的切点存储数据的转换器

Python scikit了解基于用户提供的切点存储数据的转换器,python,pandas,numpy,scikit-learn,sklearn-pandas,Python,Pandas,Numpy,Scikit Learn,Sklearn Pandas,我试图在scikit学习管道中包含一个转换器,它将根据我自己提供的切点将一个连续数据列存储为4个值。当前的参数to不起作用,主要是因为策略参数只接受{'uniform','quantile','kmeans'} 在pandas中已经有cut()函数,因此我想我需要创建一个自定义转换器来包装cut()函数行为 期望的行为(非实际) 上面的结果假设箱子包括最右边的边缘和最下面的边缘。类似于此,pd.cut()命令将提供: import pandas as pd import numpy as np

我试图在scikit学习管道中包含一个转换器,它将根据我自己提供的切点将一个连续数据列存储为4个值。当前的参数to不起作用,主要是因为
策略
参数只接受
{'uniform','quantile','kmeans'}

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

期望的行为(非实际)

上面的结果假设箱子包括最右边的边缘和最下面的边缘。类似于此,
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])

这是什么似乎为我工作作为一个自定义变压器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

自定义转换器的另一种替代方法是使用
FunctionTransformer()
方法,该方法有助于无状态操作,例如预定义存储箱的情况

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.]])

唯一的问题是,您只是转换传入数据,而不是在fit阶段从培训中学习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.]])