kon*_*cov 7 python scipy pandas scikit-learn sklearn-pandas
我想以这种方式一致地使用sklearn.compose.ColumnTransformer
(不是并行的,因此,第二个变换器应该仅在第一个变换器之后执行)来相交列列表:
log_transformer = p.FunctionTransformer(lambda x: np.log(x))
df = pd.DataFrame({'a': [1,2, np.NaN, 4], 'b': [1,np.NaN, 3, 4], 'c': [1 ,2, 3, 4]})
compose.ColumnTransformer(n_jobs=1,
transformers=[
('num', impute.SimpleImputer() , ['a', 'b']),
('log', log_transformer, ['b', 'c']),
('scale', p.StandardScaler(), ['a', 'b', 'c'])
]).fit_transform(df)
Run Code Online (Sandbox Code Playgroud)
所以,我想使用SimpleImputer
for 'a'
, 'b'
,然后log
for 'b'
, 'c'
,然后StandardScaler
for 'a'
, 'b'
, 'c'
。
但:
(4, 7)
。Nan
进入a
专栏b
。那么,如何ColumnTransformer
以以下方式用于不同的列Pipeline
?
更新:
pipe_1 = pipeline.Pipeline(steps=[
('imp', impute.SimpleImputer(strategy='constant', fill_value=42)),
])
pipe_2 = pipeline.Pipeline(steps=[
('imp', impute.SimpleImputer(strategy='constant', fill_value=24)),
])
pipe_3 = pipeline.Pipeline(steps=[
('scl', p.StandardScaler()),
])
# in the real situation I don't know exactly what cols these arrays contain, so they are not static:
cols_1 = ['a']
cols_2 = ['b']
cols_3 = ['a', 'b', 'c']
proc = compose.ColumnTransformer(remainder='passthrough', transformers=[
('1', pipe_1, cols_1),
('2', pipe_2, cols_2),
('3', pipe_3, cols_3),
])
proc.fit_transform(df).T
Run Code Online (Sandbox Code Playgroud)
输出:
array([[ 1. , 2. , 42. , 4. ],
[ 1. , 24. , 3. , 4. ],
[-1.06904497, -0.26726124, nan, 1.33630621],
[-1.33630621, nan, 0.26726124, 1.06904497],
[-1.34164079, -0.4472136 , 0.4472136 , 1.34164079]])
Run Code Online (Sandbox Code Playgroud)
我明白为什么我有 cols 重复项,nans
而不是缩放值,但是当 cols 不是静态时,如何以正确的方式解决这个问题?
更新2:
当列更改顺序时可能会出现问题。所以,我想用于FunctionTransformer
列选择:
def select_col(X, cols=None):
return X[cols]
ct1 = compose.make_column_transformer(
(p.OneHotEncoder(), p.FunctionTransformer(select_col, kw_args=dict(cols=['a', 'b']))),
remainder='passthrough'
)
ct1.fit(df)
Run Code Online (Sandbox Code Playgroud)
但得到这个输出:
ValueError:没有有效的列规范。仅允许标量、所有整数或所有字符串的列表或切片、或布尔掩码
我该如何修复它?
的预期用途ColumnTransformer
是并行应用不同的变压器,而不是顺序应用。为了实现您想要的结果,我想到了三种方法:
第一种方法:
pipe_a = Pipeline(steps=[('imp', SimpleImputer()),
('scale', StandardScaler())])
pipe_b = Pipeline(steps=[('imp', SimpleImputer()),
('log', log_transformer),
('scale', StandardScaler())])
pipe_c = Pipeline(steps=[('log', log_transformer),
('scale', StandardScaler())])
proc = ColumnTransformer(transformers=[
('a', pipe_a, ['a']),
('b', pipe_b, ['b']),
('c', pipe_c, ['c'])]
)
Run Code Online (Sandbox Code Playgroud)
第二种方法:
这需要 sklearn>1.2以及引入的 pandas-out 功能。如果没有它,ColumnTransformer
s将重新排列列并忘记名称,这样后面的列就会失败或应用到错误的列。对于早期版本,您可以根据您的特定用例进行调整。
imp_tfm = ColumnTransformer(
transformers=[('num', impute.SimpleImputer() , ['a', 'b'])],
remainder='passthrough'
)
log_tfm = ColumnTransformer(
transformers=[('log', log_transformer, ['b', 'c'])],
remainder='passthrough'
)
scl_tfm = ColumnTransformer(
transformers=[('scale', StandardScaler(), ['a', 'b', 'c'])
)
proc = Pipeline(steps=[
('imp', imp_tfm),
('log', log_tfm),
('scale', scl_tfm)]
).set_output("pandas")
Run Code Online (Sandbox Code Playgroud)
第三,可能有一种方法可以使用Pipeline
切片功能来拥有一个“主”管道,您可以为每个功能削减该管道...这主要像第一种方法一样工作,在管道较大的情况下可能会节省一些编码,但是看起来有点老套。例如,在这里您可以:
pipe_a = clone(pipe_b)[1:]
pipe_c = clone(pipe_b)
pipe_c.steps[1] = ('nolog', 'passthrough')
Run Code Online (Sandbox Code Playgroud)
(如果没有克隆或其他深度复制pipe_b
,最后一行将同时更改pipe_c
和pipe_b
。切片机制返回一个副本,因此pipe_a
并不严格需要克隆,但我将其保留下来是为了感觉更安全。不幸的是,你不能提供不连续的切片,因此pipe_c = pipe_b[0,2]
不起作用,但您可以像我上面所做的那样设置各个切片以"passthrough"
禁用它们。)