您好,关于 sklearn.Pipeline 的两个问题,带有用于时间序列的自定义转换器 [关闭]

Posted

技术标签:

【中文标题】您好,关于 sklearn.Pipeline 的两个问题,带有用于时间序列的自定义转换器 [关闭]【英文标题】:Hello, two questions about sklearn.Pipeline with custom transformer for timeseries [closed] 【发布时间】:2020-12-26 23:36:33 【问题描述】:

我应该如何修改下面的代码以使其工作:

目标,预测 = pipe.fit_predict(df)

编辑:

target, predicted = pipe.fit_transform(df, df)

我的代码:

import numpy as np
import pandas as pd
from sklearn.base import BaseEstimator
from sklearn.base import TransformerMixin
from sklearn.pipeline import Pipeline 
np.random.seed(1)

rows,cols = 100,1
data = np.random.randint(100, size = (rows,cols))
tidx = pd.date_range('2019-01-01', periods=rows, freq='20min') 
df = pd.DataFrame(data, columns=['num_orders'], index=tidx)
      


class MakeFeatures(BaseEstimator, TransformerMixin):

def __init__(self, X, y = None, max_lag = None, rolling_mean_day = None, rolling_mean_month = None):
    self.X = X.resample('1H').sum()
    self.max_lag = max_lag
    self.rolling_mean_day = rolling_mean_day
    self.rolling_mean_month = rolling_mean_month
        
def fit(self, X, y = None):
    return self

def transform(self, X, y = None):
    data = pd.DataFrame(index = self.X.index)
    data['num_orders'] = self.X['num_orders']
    data['year'] = self.X.index.year
    data['month'] = self.X.index.month
    data['day'] = self.X.index.day
    data['dayofweek'] = self.X.index.dayofweek
    
    data['detrend'] = self.X.shift() - self.X
    
    if self.max_lag:
        for lag in range(1, self.max_lag + 1):
            data['lag_'.format(lag)] = data['detrend'].shift(lag)
    if self.rolling_mean_day:
        data['rolling_mean_24'] = data.detrend.shift().rolling(self.rolling_mean_day).mean()
    
    if self.rolling_mean_month:
        data['rolling_mean_24'] = data['detrend'].shift().rolling(self.rolling_mean_month).mean()
    
    if data['year'].mean() == data['year'][1]:
        data = data.drop('year', axis = 1)
    
    data = data.dropna()
    
    y = data.num_orders
    data = data.drop('num_orders', 1)
    
    return data, y

pipe = Pipeline([
                ('features', MakeFeatures(df, df, 2 , 24)),
                ('scaler', StandardScaler())  
    ])

target, predicted = pipe.fit_transform(df, df)  # where ‘Target’ is y - the output from the Class

输出:

ValueError: could not broadcast input array from shape (9,7) into shape (9).

Pipeline 中的每个函数都运行良好。

我可以毫无问题地运行 MakeFeatures(df, df)StandardScaler().fit_transform(df, df)

我可以将 MakeFeatures(df,df) 的乘积插入到 StandardScaler 中,没有错误。

【问题讨论】:

您好,您当前的问题很难理解。您能否提供数据的样本/虚拟对象,以便使用您的代码对其进行测试? @Kim Tang,感谢您的评论。至少现在我明白所有的缺点来自哪里。这是我的第一个问题,我还在学习如何提问。 那么欢迎来到 Stack Overflow!看看这里***.com/tour 的导览,然后用您的代码的“最小可重现示例”(***.com/help/minimal-reproducible-example) 更新您的问题以重现您的问题,以便其他人可以更好地帮助您。 让我们看看这是否可行。谢谢指导 【参考方案1】:

你不能用

目标,预测 = pipe.fit_predict(df)

使用您定义的管道,因为只有在估计器也实现了这样的方法时才能使用 fit_predict() 方法。 Reference in documentation

仅当最终估计器实现 fit_predict 时才有效。

另外,它只会返回预测,所以你不能使用target,predicted =,而应该使用predicted =

你得到了错误

ValueError: 使用序列设置数组元素。

因为您提供的是 StandardScaler()pandas.TimeSeries

这是因为通过您的方法调用pipe.fit_predict(df),您只向管道提供了“X”而不是“y”。这对于管道“MakeFeatures”的第一个组件很好,因为它接受“X”并返回“数据”和“y”,但在管道中不会使用“y”,因为“y”必须在 fit_predict() 调用的开头定义。

在此处查看该方法的文档:https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html#sklearn.pipeline.Pipeline.fit_predict

它说明了“y”参数

训练目标。必须满足所有步骤的标签要求 管道。

因此“y”将用作管道所有部分的“y”,但您的未定义,所以None

因此,您当前的管道基本上会发生以下情况:

makeF = MakeFeatures(df, 2 , 24)
transformed_df = makeF.fit_transform(df)

sc = StandardScaler()
sc.fit(transformed_df)

并导致ValueError: setting an array element with a sequence.

所以我建议你像这样更新你的代码:

import numpy as np
import pandas as pd
from sklearn.base import BaseEstimator
from sklearn.base import TransformerMixin
from sklearn.pipeline import Pipeline 
from sklearn.preprocessing import StandardScaler 
from sklearn.linear_model import LinearRegression

np.random.seed(1)

rows,cols = 100,1
data = np.random.randint(100, size = (rows,cols))
tidx = pd.date_range('2019-01-01', periods=rows, freq='20min') 
df = pd.DataFrame(data, columns=['num_orders'], index=tidx)
      
class MakeFeatures(BaseEstimator, TransformerMixin):

  def __init__(self, X, max_lag = None, rolling_mean_day = None, rolling_mean_month = None):
      self.X = X.resample('1H').sum()
      self.max_lag = max_lag
      self.rolling_mean_day = rolling_mean_day
      self.rolling_mean_month = rolling_mean_month
          
  def fit(self, X):
      return self

  def transform(self, X):
      data = pd.DataFrame(index = self.X.index)
      data['num_orders'] = self.X['num_orders']
      data['year'] = self.X.index.year
      data['month'] = self.X.index.month
      data['day'] = self.X.index.day
      data['dayofweek'] = self.X.index.dayofweek
      
      data['detrend'] = self.X.shift() - self.X
      
      if self.max_lag:
          for lag in range(1, self.max_lag + 1):
              data['lag_'.format(lag)] = data['detrend'].shift(lag)
      if self.rolling_mean_day:
          data['rolling_mean_24'] = data.detrend.shift().rolling(self.rolling_mean_day).mean()
      
      if self.rolling_mean_month:
          data['rolling_mean_24'] = data['detrend'].shift().rolling(self.rolling_mean_month).mean()
      
      if data['year'].mean() == data['year'][1]:
          data = data.drop('year', axis = 1)
      
      data = data.dropna()
      
      y = data.num_orders
      data = data.drop('num_orders', 1)
      
      return data, list(y)

pipe = Pipeline([
                 ('scaler', StandardScaler()),
                ('Model' , LinearRegression())
      ])

makeF = MakeFeatures(df, 2 , 24)
makeF.fit(df)
data,y = makeF.transform(df)
pipe.fit(data,y)  # where ‘Target’ is y - the output from the Class

然后您可以使用管道来预测数据并评估性能,例如使用 r2_score:

from sklearn.metrics import r2_score

predictions = pipe.predict(data)
r2_score(y,predictions)

【讨论】:

Kim Tang,谢谢你的回答,但 StandardScaler 和 Pipeline 都接受 label 参数,所以如果我将我的 Class 修改为 MakeFeature(self, X , y,..) 然后调用 pipe.fit_transform(df,df) (其中 pipe = Pipeline([ ('features', MakeFeatures(df,df), (')缩放器', StandardScaler())]) ? 我在这里看不到你完整的更新代码,但是通过查看这个,我认为错误是 StandardScaler 将使用'df'作为'y'参数来调用,因为你调用 pipe.fit_transform(df,df)。但 StandardScaler 不能将 'df' 用作 'y'。 首先-感谢您的患者,不确定政策,但我的问题与您已经回答的主要问题不同。 StandardScaler().fit_transform(df,df) 可以正常工作,MakeFeatures(df,df) 也可以。但一起: pipe = Pipeline([ ('features', MakeFeatures(df,df), ('scaler', StandardScaler())]), pipe.fit_transform(df,df) 它没有'不工作 好的,就你的问题提出一个新问题,包括代码和一些数据来重现和理解你的问题。这样其他人也可以帮助你。

以上是关于您好,关于 sklearn.Pipeline 的两个问题,带有用于时间序列的自定义转换器 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

sklearn.pipeline.Pileline

如何使用 sklearn.pipeline 转换新数据

使用 sklearn Pipeline 和 MultiOutputRegressor 访问属性

sklearn Pipeline 和 DataFrameMapper 有啥区别?

sklearn Pipeline 正确使用

sklearn Pipeline 和Ploynomial