我想创建自己的变换器以与sklearn Pipeline一起使用。因此,我正在创建一个实现fit和transform方法的类。变换器的目的是从矩阵中删除具有超过指定数量的NaN的行。所以我面临的问题是如何更改传递给变压器的X和y矩阵?我相信这必须在fit方法中完成,因为它可以同时访问X和y。因为一旦我将X重新分配给具有较少行的新矩阵,python就会通过赋值传递参数,因此对原始X的引用将丢失(当然对于y也是如此)。是否可以保留此参考?
我正在使用pandas DataFrame轻松删除具有太多NaN的行,这可能不适合我的用例。当前代码如下所示:
class Dropna():
# thresh is max number of NaNs allowed in a row
def __init__(self, thresh=0):
self.thresh = thresh
def fit(self, X, y):
total = X.shape[1]
# +1 to account for 'y' being added to the dframe
new_thresh = total + 1 - self.thresh
df = pd.DataFrame(X)
df['y'] = y
df.dropna(thresh=new_thresh, inplace=True)
X = df.drop('y', axis=1).values
y = df['y'].values
return self
def transform(self, X):
return X
答案 0 :(得分:7)
修改样本轴,例如删除样本,(但是?)是否符合scikit-learn变换器API。因此,如果您需要这样做,您应该在任何调用scikit学习之外的时候进行预处理。
现在,变换器API用于将给定样本的特征转换为新的特征。这可以隐含地包含来自其他样本的信息,但样本永远不会被删除。
另一个选择是尝试估算缺失的值。但同样,如果您需要删除样本,请在使用scikit learn之前将其视为预处理。
答案 1 :(得分:0)
您可以使用sklearn.preprocessing.FunctionTransformer方法(http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.FunctionTransformer.html)轻松解决此问题
您只需要在功能
中将替换放到X.def drop_nans(X, y=None):
total = X.shape[1]
new_thresh = total - thresh
df = pd.DataFrame(X)
df.dropna(thresh=new_thresh, inplace=True)
return df.values
然后通过调用
获得变压器transformer = FunctionTransformer(drop_nans, validate=False)
您可以在管道中使用。可以在drop_nans函数之外设置阈值。
答案 2 :(得分:0)
@eickenberg 是正确而干净的答案。尽管如此,我喜欢把所有东西都放在一个流水线中,所以如果你有兴趣,我创建了一个库(尚未部署在 pypi 上)允许在 Y 上应用转换:
https://gitlab.com/thibaultB/transformers/
用法如下:
df = pd.DataFrame([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
df.columns = ["a", "b", "target"]
spliter = SplitXY("target") # Create a new step and give it name of column target
pipe = Pipeline([
("imputer", SklearnPandasWrapper(KNNImputer())),
("spliter", spliter),
("scaler", StandardScaler()),
("rf",
EstimatorWithoutYWrapper(RandomForestRegressor(random_state=45),
spliter)) # EstimatorWithoutYWrapper overwrite RandomForestRegressor to get y from spliter just before calling fit or transform
])
pipe.fit(df)
res = pipe.predict(df)
使用此代码,如果将所有修改行数的转换器放在“SplitXY”转换器之前,则可以更改行数。在 SplitXY 转换器之前的转换器应该保留列名,这就是为什么我还添加了一个 SklearnPandasWrapper 来包装 sklearn 转换器(通常返回 numpy 数组)以保留列名。
答案 3 :(得分:-1)
在管道下方进一步使用“深层副本”, X
, y
仍然受到保护
.fit()
可以先为每次调用深层复制分配新的类变量
self.X_without_NaNs = X.copy()
self.y_without_NaNs = y.copy()
然后缩小/转换它们,使NaN
- s比self.treshold