2017-10-04 2 views
3

파이프 라인의 데이터를 정리하기 위해 일련의 사용자 지정 변환을 sklearn에 작성했습니다. 각 사용자 정의 변환은 fittransform의 매개 변수로 두 개의 팬더 DataFrame을 사용하므로 transform은 두 개의 DataFrames도 반환합니다 (아래 예 참조). DataFrames in과 DataFrames out : 파이프 라인에 단 하나의 Transformer가있는 경우이 방법이 유용합니다. 이런 두 Rransformers가 파이프 라인에서 조합 그러나 sklearn 변환은 어떤 데이터에서 작동합니까?

, : 신비 입력으로 튜플을 수신 RemoveMissingRowsBasedOnTarget

pipeline = Pipeline ([ 
     ('remove_missing_columns', RemoveAllMissing (['mailing_address_str_number'])), 
     ('remove_rows_based_on_target', RemoveMissingRowsBasedOnTarget()), 
     ]) 

X, y = pipeline.fit_transform (X, y) 

==>TypeError: tuple indices must be integers or slices, not Series 

클래스. 나는이

pipeline = Pipeline ([ 
     ('remove_rows_based_on_target', RemoveMissingRowsBasedOnTarget()), 
     ('remove_missing_columns', RemoveAllMissing (['mailing_address_str_number'])), 
     ]) 

==> AttributeError: 'tuple' object has no attribute 'apply' 

같은 변압기의 위치를 ​​전환 할 때이 오류는 클래스 RemoveAllMissing 발생합니다. 두 경우 모두 오류 메시지는 오류가 발생한 행 위에 ==> 표시됩니다. 정확하게 무슨 일이 벌어 질 수 있는지 정확히 읽은 것 같지만이 주제에 대해서는 아무 것도 찾을 수 없습니다. 누군가 내가 뭘 잘못하고 있는지 말해 줄 수 있니? 아래에서 격리 된 문제에 대한 코드를 찾을 수 있습니다.

import numpy as np 
import pandas as pd 
import random 
from sklearn.base import BaseEstimator, TransformerMixin 
from sklearn.pipeline import Pipeline 

def create_data (rows, cols, frac_nan, random_state=42): 
    random.seed (random_state) 
    X = pd.DataFrame (np.zeros ((rows, cols)), 
         columns=['col' + str(i) for i in range (cols)], 
         index=None) 
    # Create dataframe of (rows * cols) with random floating points 
    y = pd.DataFrame (np.zeros ((rows,))) 
    for row in range(rows): 
     for col in range(cols): 
      X.iloc [row,col] = random.random() 
     X.iloc [row,1] = np.nan # column 1 exists colely of NaN's 
     y.iloc [row] = random.randint (0, 1) 
    # Assign NaN's to a fraction of X 
    n = int(frac_nan * rows * cols) 
    for i in range (n): 
     row = random.randint (0, rows-1) 
     col = random.randint (0, cols-1) 
     X.iloc [row, col] = np.nan 
    # Same applies to y 
    n = int(frac_nan * rows) 
    for i in range (n): 
     row = random.randint (0, rows-1) 
     y.iloc [row,] = np.nan 

    return X, y  

class RemoveAllMissing (BaseEstimator, TransformerMixin): 
    # remove columns containg NaN only 
    def __init__ (self, requested_cols=[]): 
     self.all_missing_data = requested_cols 

    def fit (self, X, y=None): 
     # find empty columns == columns with all missing data 
     missing_cols = X.apply (lambda x: x.count(), axis=0) 
     for idx in missing_cols.index: 
      if missing_cols [idx] == 0: 
       self.all_missing_data.append (idx) 

     return self 

    def transform (self, X, y=None): 
     print (">RemoveAllMissing - X shape: " + str (X.shape), " y shape: " + str (y.shape), 'type (X):', type(X)) 
     for all_missing_predictor in self.all_missing_data: 
      del X [all_missing_predictor] 

     print ("<RemoveAllMissing - X shape: " + str (X.shape), " y shape: " + str (y.shape), 'type (X):', type(X)) 
     return X, y 

    def fit_transform (self, X, y=None): 
     return self.fit (X, y).transform (X, y) 

class RemoveMissingRowsBasedOnTarget (BaseEstimator, TransformerMixin): 
    # remove each row where target contains one or more NaN's 
    def __init__ (self): 
     self.missing_rows = [] 

    def fit (self, X, y = None): 
     # remove all rows where the target value is missing data 
     print (type (X)) 
     if y is None: 
      print ('RemoveMissingRowsBasedOnTarget: target (y) cannot be None') 
      return self 

     self.missing_rows = np.array (y.notnull()) # false = missing data 

     return self 

    def transform (self, X, y=None): 
     print (">RemoveMissingRowsBasedOnTarget - X shape: " + str (X.shape), " y shape: " + str (y.shape), 'type (X):', type(X)) 
     if y is None: 
      print ('RemoveMissingRowsBasedOnTarget: target (y) cannot be None') 
      return X, y 

     X = X [self.missing_rows].reset_index() 
     del X ['index'] 
     y = y [self.missing_rows].reset_index() 
     del y ['index'] 

     print ("<RemoveMissingRowsBasedOnTarget - X shape: " + str (X.shape), " y shape: " + str (y.shape), 'type (X):', type(X)) 
     return X, y 

    def fit_transform (self, X, y=None): 
     return self.fit (X, y).transform (X, y) 

pipeline = Pipeline ([ 
     ('RemoveAllMissing', RemoveAllMissing()), 
     ('RemoveMissingRowsBasedOnTarget', RemoveMissingRowsBasedOnTarget()), 
     ]) 

X, y = create_data (25, 10, 0.1) 
print ("X shape: " + str (X.shape), " y shape: " + str (y.shape), 'type (X):', type(X)) 
X, y = pipeline.fit_transform (X, y) 
#X, y = RemoveAllMissing().fit_transform (X, y) 
#X, y = RemoveMissingRowsBasedOnTarget().fit_transform (X, y) 

@Vivek으로 편집 내가 문제가 격리되어 실행이 독립적 코드에 의해 원래의 코드를 교체 한 요청했다. 튜플이 DataFrame 대신 매개 변수로 전송되기 때문에 코드가 어딘가에 충돌합니다. 파이프 라인은 데이터 유형을 변경하므로 문서에서 찾을 수 없습니다. 하나는 파이프 라인에 대한 호출을 코멘트와 같이, 잘 작동 everyting 변압기의 개별 호출하기 전에 주석을 제거 할 때 :

#X, y = pipeline.fit_transform (X, y) 
X, y = RemoveAllMissing().fit_transform (X, y) 
X, y = RemoveMissingRowsBasedOnTarget().fit_transform (X, y) 
+0

: 또한, 나는 당신이 한 번 봐 가질 수있는 파이프 라인 내부의 목표 변수를 y 변환하기위한 몇 가지 관련 문제가있는 것을 발견 print (type (X))'그 시점에 인쇄합니까?(클래스'RemoveMissingRowsBasedOnTarget', 처음 호출했을 때) 'X '는 다음 클래스 ('RemoveAllMissing')를 호출하기위한 DataFrame이되어야하지만 그 시점에서 튜플이 된 것 같습니다 ... – Eskapp

+0

이것은에 따라 달라집니다 호출 순서 : RemoveMissingRowsBasedOnTarget이 먼저 호출되면 DataFrame이 인쇄되고 두 번째 호출되면 터플이 인쇄됩니다. 또한 오류 메시지는 rfeferred 메소드가없는 튜플에 대해 불평합니다. – Arnold

+0

샘플 데이터와 함께 코드를 복사하기 쉽도록 추가해야합니다. –

답변

2

좋아, 지금은 수업과 것으로 보인다 오류를 가지고있다 파이프 라인이 y의 입력을 받아 들일 수 있고 (내부 변압기를 따라 전달하는) X, y를 모두 반환하는 경우, y는 전체에서 일정하며 모든 transform() 메서드에서 반환되지 않는다고 가정합니다. 귀하의 코드에는 해당되지 않습니다. 그 부분을 다른 곳에서 분리 할 수 ​​있다면 작동 할 수 있습니다.

this line in the source code of pipeline를 참조하십시오

if hasattr(transformer, 'fit_transform'): 
     res = transformer.fit_transform(X, y, **fit_params) 
    else: 
     res = transformer.fit(X, y, **fit_params).transform(X) 

당신은 두 개의 값 (X, Y) 만 반환하는 유일한 하나의 변수 res에 포함 따라서는 튜플이된다. 다음 변압기에서 실패합니다.

당신은 X로 튜플의 압축을 해제하여 이러한 데이터를 처리 할 수있는, Y는이 같은 :

class RemoveMissingRowsBasedOnTarget (BaseEstimator, TransformerMixin): 
    ... 
    ... 

    def fit (self, X, y = None): 
     # remove all rows where the target value is missing data 
     print (type (X)) 
     if isinstance(X, tuple): 
      y=X[1] 
      X=X[0] 

     ... 
     ... 

     return self 

    def transform (self, X, y=None): 
     if isinstance(X, tuple): 
      y=X[1] 
      X=X[0] 

     ... 
     ... 

     return X, y 

    def fit_transform(self, X, y=None): 
     self.fit(X, y).transform(X, y) 

당신이 파이프 라인의 모든 후속 변압기에 대해이 작업을 수행해야합니다. 하지만 X와 Y 처리를 분리하는 것이 좋습니다. `무엇을

+0

이 코드는 실제로 작동합니다. 감사합니다. 코드에서 문제가있는 것 같습니다 .X와 X가 아닌 X 만 전송한다는 결정이 나타납니다. 조금 의심 스러워요. 특히 행 단위 작업을 수행 할 때 X와 Y 모두에서 수행하는 것이 좋을 것입니다. 어쨌든, 이것은 그대로이며 솔루션을 제공해 주셔서 감사합니다. – Arnold