0

사용자가 보낸 메시지에 대한 정보가 포함 된 팬더 데이터 프레임이 있습니다. 내 모델의 경우, 수신자 A, B, C가 수신자에게 속해야 하는지를 예기하고자하는 메시지의 수신자 누락을 예측하는 데 관심이 있습니다.FeatureUnion을 사용하여 PipeLine에서 여러 피쳐를 변환하는 방법은 무엇입니까?

OneVsRestClassifier 및 LinearSVC를 사용하여 다중 레이블 분류를 수행하고 있습니다. 기능의 경우 메시지의 수신자를 사용하고 싶습니다. 제목과 본문.

수신자가 사용자 목록이므로 MultiLabelBinarizer를 사용하여 해당 열을 변환하려고합니다. 제목과 본문, 나는 다음과 같이

내 입력 피클 파일에 데이터가 TFIDF를 사용하려면 : 모든 값은받는 사람을 제외하고 문자열 내가 정의와 기능의 조합을 사용하고 세트()

[[message_id,sent_time,subject,body,set(recipients),message_type, is_sender]] 

가되어 있습니다 파이프 라인의 변압기는 다음과 같이이를 달성합니다.

from sklearn.preprocessing import MultiLabelBinarizer 
from sklearn.base import TransformerMixin, BaseEstimator 
from sklearn.pipeline import Pipeline, FeatureUnion 
from sklearn.feature_extraction.text import TfidfVectorizer 
from sklearn.multiclass import OneVsRestClassifier 
from sklearn.model_selection import GridSearchCV 
from sklearn.multiclass import OneVsRestClassifier 
from sklearn.linear_model import SGDClassifier 
from sklearn.svm import SVC, LinearSVC 
import pickle 
import pandas as pd 
import numpy as np 

if __name__ == "__main__": 
class ColumnSelector(BaseEstimator, TransformerMixin): 
    def __init__(self, column): 
     self.column = column 

    def fit(self, X, y=None, **fit_params): 
     return self 

    def transform(self, X, y=None, **fit_params): 
     return X[self.column] 

class MultiLabelTransformer(BaseEstimator, TransformerMixin): 

    def __init__(self, column): 
     self.column = column 

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

    def transform(self, X): 
     mlb = MultiLabelBinarizer() 
     return mlb.fit_transform(X[self.column]) 

pipeline = Pipeline([ 
    ('features', FeatureUnion([ 
     ('subject_tfidf', Pipeline([ 
        ('selector', ColumnSelector(column='Subject')), 
        ('tfidf', TfidfVectorizer(min_df=0.0025, ngram_range=(1, 4))) 
        ])), 
     ('body_tfidf', Pipeline([ 
      ('selector', ColumnSelector(column='Body')), 
      ('tfidf', TfidfVectorizer(min_df=0.0025, ngram_range=(1, 4))) 
     ])), 
     ('recipients_binarizer', Pipeline([ 
      ('multi_label', MultiLabelTransformer(column='CoRecipients')) 
     ])), 
    ])), 
    ('classifier', OneVsRestClassifier(LinearSVC(), n_jobs=-1)) 
]) 

top_recips = ['A', 'B', 'C, 'D] 
corpus_data = pickle.load(
    open("E:\\Data\\messages_items.pkl", "rb")) 
df = pd.DataFrame(corpus_data, columns=[ 
    'MessageId', 'SentTime', 'Subject', 'Body', 'Recipients', 'MessageType', 'IsSender']) 

df = df.dropna() 

# add co recipients and top recipients columns 
df['CoRecipients'] = df['Recipients'].apply(
    lambda r: [x for x in r if x not in top_recips]) 
df['TopRecipients'] = df['Recipients'].apply(
    lambda r: [x for x in top_recips if x in r]) 

# drop rows where top recipients = 0 
df = df.loc[df['TopRecipients'].str.len() > 0] 
df_train = df.loc[df['SentTime'] <= '2017-10-15'] 
df_test = df.loc[(df['SentTime'] > '2017-10-15') & (df['MessageType'] == 'Meeting')] 

mlb = MultiLabelBinarizer(classes=top_recips) 

train_x = df_train[['Subject', 'Body', 'CoRecipients']] 
train_y = mlb.fit_transform(df_train['TopRecipients']) 

test_x = df_train[['Subject', 'Body', 'CoRecipients']] 
test_y = mlb.fit_transform(df_train['TopRecipients']) 

print "train" 
pipeline.fit(train_x, train_y) 

print "predict" 
predictions = pipeline.predict(test_x) 

print "done" 

CoRecipients 열의 기능을 올바르게 수행하고 있는지 확실하지 않습니다. 결과가 올바르게 보이지 않기 때문에. 어떤 단서? df_test

mlb = MultiLabelBinarizer(classes=top_recips) 

train_x = df_train[['Subject', 'Body', 'CoRecipients']] 
train_y = mlb.fit_transform(df_train['TopRecipients']) 

test_x = df_test[['Subject', 'Body', 'CoRecipients']] 
test_y = mlb.transform(df_test['TopRecipients']) 

는 아래 보는 사용하도록 설정 시험

class MultiLabelTransformer(BaseEstimator, TransformerMixin): 
     def __init__(self, column): 
      self.column = column 

     def fit(self, X, y=None): 
      self.mlb = MultiLabelBinarizer() 
      self.mlb.fit(X[self.column]) 
      return self 

     def transform(self, X): 
      return self.mlb.transform(X[self.column]) 

를 고정 :

는 UPDATE 1

다음과 같이 MLB 변압기의 코드 변경 KeyError

Traceback (most recent call last): 
    File "E:\Projects\NLP\FeatureUnion.py", line 99, in <module> 
    predictions = pipeline.predict(test_x) 
    File "C:\Python27\lib\site-packages\sklearn\utils\metaestimators.py", line 115, in <lambda> 
    out = lambda *args, **kwargs: self.fn(obj, *args, **kwargs) 
    File "C:\Python27\lib\site-packages\sklearn\pipeline.py", line 306, in predict 
    Xt = transform.transform(Xt) 
    File "C:\Python27\lib\site-packages\sklearn\pipeline.py", line 768, in transform 
    for name, trans, weight in self._iter()) 
    File "C:\Python27\lib\site-packages\sklearn\externals\joblib\parallel.py", line 779, in __call__ 
    while self.dispatch_one_batch(iterator): 
    File "C:\Python27\lib\site-packages\sklearn\externals\joblib\parallel.py", line 625, in dispatch_one_batch 
    self._dispatch(tasks) 
    File "C:\Python27\lib\site-packages\sklearn\externals\joblib\parallel.py", line 588, in _dispatch 
    job = self._backend.apply_async(batch, callback=cb) 
    File "C:\Python27\lib\site-packages\sklearn\externals\joblib\_parallel_backends.py", line 111, in apply_async 
    result = ImmediateResult(func) 
    File "C:\Python27\lib\site-packages\sklearn\externals\joblib\_parallel_backends.py", line 332, in __init__ 
    self.results = batch() 
    File "C:\Python27\lib\site-packages\sklearn\externals\joblib\parallel.py", line 131, in __call__ 
    return [func(*args, **kwargs) for func, args, kwargs in self.items] 
    File "C:\Python27\lib\site-packages\sklearn\pipeline.py", line 571, in _transform_one 
    res = transformer.transform(X) 
    File "C:\Python27\lib\site-packages\sklearn\pipeline.py", line 426, in _transform 
    Xt = transform.transform(Xt) 
    File "E:\Projects\NLP\FeatureUnion.py", line 37, in transform 
    return self.mlb.transform(X[self.column]) 
    File "C:\Python27\lib\site-packages\sklearn\preprocessing\label.py", line 765, in transform 
    yt = self._transform(y, class_to_index) 
    File "C:\Python27\lib\site-packages\sklearn\preprocessing\label.py", line 789, in _transform 
    indices.extend(set(class_mapping[label] for label in labels)) 
    File "C:\Python27\lib\site-packages\sklearn\preprocessing\label.py", line 789, in <genexpr> 
    indices.extend(set(class_mapping[label] for label in labels)) 
KeyError: u'[email protected]' 

> 업데이트 2

근무 당신이 잘못 MultiLabelBinarizer의 변형을하고있다

class MultiLabelTransformer(BaseEstimator, TransformerMixin): 
     def __init__(self, column, classes): 
      self.column = column 
      self.classes = classes 
    def fit(self, X, y=None): 
     self.mlb = MultiLabelBinarizer(classes=self.classes) 
     self.mlb.fit(X[self.column]) 
     return self 

    def transform(self, X): 
     return self.mlb.transform(X[self.column]) 

# drop rows where top recipients = 0 
df = df.loc[df['TopRecipients'].str.len() > 0] 
df_train = df.loc[df['SentTime'] <= '2017-10-15'] 
df_test = df.loc[(df['SentTime'] > '2017-10-15') & 
       (df['MessageType'] == 'Meeting')] 

mlb = MultiLabelBinarizer(classes=top_recips) 

train_x = df_train[['Subject', 'Body', 'CoRecipients']] 
train_y = mlb.fit_transform(df_train['TopRecipients']) 

test_x = df_test[['Subject', 'Body', 'CoRecipients']] 
test_y = mlb.transform(df_test['TopRecipients']) 

# get all unique co-recipients 
co_recips = list(set([a for b in df.CoRecipients.tolist() for a in b])) 

# create pipeline 
pipeline = Pipeline([ 
    ('features', FeatureUnion(
     # list of features 
     transformer_list=[ 
      ('subject_tfidf', Pipeline([ 
        ('selector', ColumnSelector(column='Subject')), 
        ('tfidf', TfidfVectorizer(min_df=0.0025, ngram_range=(1, 4))) 
        ])), 
      ('body_tfidf', Pipeline([ 
       ('selector', ColumnSelector(column='Body')), 
       ('tfidf', TfidfVectorizer(min_df=0.0025, ngram_range=(1, 4))) 
      ])), 
      ('recipients_binarizer', Pipeline([ 
       ('multi_label', MultiLabelTransformer(column='CoRecipients', classes=co_recips)) 
      ])) 
     ], 
     # weight components in FeatureUnion 
     transformer_weights={ 
      'subject_tfidf': 3.0, 
      'body_tfidf': 1.0, 
      'recipients_binarizer': 1.0, 
     } 
    )), 
    ('classifier', OneVsRestClassifier(LinearSVC(), n_jobs=-1)) 
]) 

print "train" 
pipeline.fit(train_x, train_y) 

print "predict" 
predictions = pipeline.predict(test_x) 

답변

1

코드입니다. 교육 및 테스트 데이터 모두에 적합합니다. 그게 전부가 아니야.

항상 훈련 데이터에 적합하고 테스트 데이터에 대한 변형을 사용해야합니다.

당신이 실수를 두 번 수행 한

: 당신은 '공동받는 사람의

  • 당신이 변환 test_y을 변환하는 동안 변환 MultiLabelTransformer에서는

    • 을'TopRecipients '

    문제는 테스트 데이터가 'Co-recipients'또는 'TopRecipients'에서 서로 다른 (또는 새) 값을 가지면 반환 된 배열의 모양이 교육 시간과 다른 것입니다. 결과가 잘못 될 수 있습니다.

    class MultiLabelTransformer(BaseEstimator, TransformerMixin): 
    
        #Updated 
        def __init__(self, column, classes): 
         self.column = column 
         self.classes = classes 
    
        def fit(self, X, y=None): 
         # Updated 
         self.mlb = MultiLabelBinarizer(classes = self.classes) 
         self.mlb.fit(X[self.column]) 
         return self 
    
        def transform(self, X): 
         return self.mlb.transform(X[self.column]) 
    

    그리고

    test_y = mlb.transform(df_train['TopRecipients']) 
    

    을 그리고 파이프 라인 내부 :

    은 다음과 같이 코드를 변경

    .... 
    .... 
    ('multi_label', MultiLabelTransformer(column='CoRecipients', 
                 classes=set([a for b in df.CoRecipients.tolist() for a in b])) 
    .... 
    .... 
    

    test_y의 마지막 변화는 반환 된 배열로 인해 영향을 미치지 않습니다 있지만 다음 중 top_recips을 사용하여 클래스를 지정했습니다. mlb = MultiLabelBinarizer(classes=top_recips)하지만 테스트 데이터에 transform (및 fit_transform 또는 never_transform) 만 수행하는 것이 더 좋습니다.

  • +0

    제안한대로 MultiLabelTrasnformer의 코드가 변경되었으며 test_x에서 예측하려고 할 때 KeyError가 발생했습니다. 변경 사항이 제안 된 Q 코드를 업데이트하십시오. 나는 당신이 암시하는 것처럼 열차 데이터에없는 테스트 데이터에만 나타나는 일부 수신자가 있기 때문에 오류가 발생했다고 생각합니다. 멀티 라벨 이진 장치가 기차 및 테스트 세트의 모든 가능한 수신자에 대해 알 수 있도록 어떻게 수정해야합니까? – user330612

    +0

    @ user330612 CoRecipients 열의 알려진 모든 레이블에 대해 'MultiLabelTrasnformer'의 classes 속성을 사용하십시오. y_train과 y_test에 대해했던 것처럼. –

    +0

    알았어. 그러나이 고유 CoRecipients 목록을 MultiLabelTransformer에 전달하려면 어떻게해야합니까? co_recips = list (set ([a b에 대한 df.CoRecipients.tolist()의 b에 대한 a)) – user330612