默认情况下,Sklearn 的缩放器按列工作。但我需要按行缩放数据,所以我执行了以下操作:
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
import numpy as np
# %% Generating sample data
x = np.array([[-1, 4, 2], [-0.5, 8, 9], [3, 2, 3]])
y = np.array([1, 2, 3])
#%% Train/Test split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=2)
scaler = MinMaxScaler()
x_train = scaler.fit_transform(x_train.T).T # scaling line-wise
x_test = scaler.transform(x_test) <-------- Error here
但是我收到以下错误:
ValueError: X has 3 features, but MinMaxScaler is expecting 2 features as input.
我不明白这里出了什么问题。为什么它说它期待 2 个特征,而我的所有 X(x、x_train 和 x_test)都有 3 个特征?我该如何解决这个问题?
StandardScaler
是有状态的:当您拟合它时,它会计算并保存列的平均值和标准差;当转换(训练或测试集)时,它使用那些保存的统计数据。您的转置技巧对此不起作用:每个row都保存了统计信息,然后您的测试集没有相同的行,因此转换无法正常工作(如果行数不同,则会抛出错误,或者默默地错误 -如果行数相同则缩放)。
你想要的不是有状态的:测试集应该完全独立于训练集进行转换。事实上,每一行都应该彼此独立地进行转换。所以你可以在分割之前进行这种转换,或者在测试集(转置)上使用
fit_transform
。
对于行的 l2 标准化,有一个内置函数:
Normalizer
(docs)。我不认为有最小-最大归一化的类似物,但我认为你可以写一个 FunctionTransformer
来做到这一点。
这是可以做到的。我可以想到一个场景,这会很有用。通常,
MinMaxScaler
会相对于该特征的其他观测值缩放每个 x
、y
和 z
。这就是“系列”缩放。现在想象一下,您想要映射受 x+y+z = 1
约束的每个点。我认为这就是OP所要求的。我过去曾经这样做过,我将描述我是如何做到的。
您需要将个人观察结果视为列多索引,并将其视为高维特征。然后,您需要构建一个管道,在其中将观察结果从列方式转换为行方式,然后进行最小/最大缩放。这会让您得到 x+y+z=1,但您仍然需要返回到数据的原始形状,为此您需要跟踪每个观察的索引。在管道中,您需要使用类似
DataframeFunctionTransformer
的东西,我在互联网上看到过它,在下面复制它。这样您就可以使用 pandas 函数来调整数据并与索引合并回来。
class DataframeFunctionTransformer():
def __init__(self, func):
self.func = func
def transform(self, input_df, **transform_params):
return self.func(input_df)
def fit(self, X, y=None, **fit_params):
return self
关于
MinMaxScaler
的状态性,我认为在这样的场景中,MinMaxScaler
的状态不会被使用,它纯粹充当变压器,将这些点映射到满足约束的不同空间x
、y
和 z
进行缩放,使其加起来为 1。
@Murilo 希望这能让您开始找到解决方案。一定是一个有趣的问题。
我一直在努力解决同样的问题,所以整理了一个课程:
class StatelessTransformer(TransformerMixin, BaseEstimator):
def __init__(self, transformer_class: TransformerMixin, sample_wise: bool = True):
"""
Create a stateless transformer from a statefull transformer class.
By default, `transform` transposes input and output data to apply feature-wise transformers to samples (rows).
Allows use of feature-wise, stateful transformers in an sklearn `Pipeline`.
Examples
--------
>>> import numpy as np
>>> from sklearn.pipeline import Pipeline
>>> from sklearn.preprocessing import MaxAbsScaler
>>> pipeline = Pipeline([("sample_scaler", StatelessTransformer(MaxAbsScaler))])
>>> X = np.array([[0, 1, 2], [3, 4, 5]])
>>> pipeline.transform(X)
array([[0. , 0.5, 1. ],
[0.6, 0.8, 1. ]])
>>> pipeline = Pipeline([("sample_scaler", StatelessTransformer(MaxAbsScaler, sample_wise=False))])
>>> pipeline.transform(X)
array([[0. , 0.25, 0.4 ],
[1. , 1. , 1. ]])
"""
self.transformer_class = transformer_class
self.sample_wise = sample_wise
def fit(self, X, y=None, **fit_params):
"""Stateless, so no fit operation."""
return self
def transform(self, X):
"""
Calls `.fit_transform` from a new instance of the stateful transformer class, so that no state is held.
Note that default fit parameters are used.
"""
if self.sample_wise:
return self.transformer_class().fit_transform(X.T).T
return self.transformer_class().fit_transform(X)