0

私は、ユーザーが送信したメッセージに関する情報を含むpandasデータフレームを持っています。 私のモデルでは、メッセージの受信者の欠落を予測することに興味があります。受信者A、B、Cがメッセージを受け取った場合、他の誰が受信者の一部であったかを予測したいと考えています。FeatureUnionを使用してPipeLineで複数のフィーチャを変換する方法は?

私はOneVsRestClassifierとLinearSVCを使用して複数ラベルの分類を行っています。 機能については、メッセージの受信者を使用したいと思います。被験者および身体。

受信者はユーザーのリストなので、MultiLabelBinarizerを使用してその列を変換する必要があります。すべての値は、私はカスタムと機能の組合を使用していますセット()

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

ある受信者を除く文字列です:件名と本文については、私は次のように私の入力漬物ファイルはデータを持っているTFIDF

を使用したいですこれを達成するためにパイプラインのトランスを以下のように使用します。

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列の機能を正しく実行しているかどうかはわかりません。結果は正しく見えません。どんな手掛かり?

UPDATE 1

は、次のようにMLB変圧器のコードを変更:

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]) 

を、以下に見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']) 

を使用するようにテストセットを固定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]' 

> UPDATE 2

の作業コード

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

あなたは間違ってMultiLabelBinarizerのための変換を行っています。トレーニングデータとテストデータの両方に適しています。それは正しい方法ではありません。

トレーニングデータには常に適合し、テストデータの変換を使用する必要があります。

あなたがこの間違いを2回行っている

:あなたは「共同受信者の

  • トランスフォーム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']) 
    

    、パイプラインの内側:test_yでの最後の変更は、返される配列には影響を与えませんが

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

    理由あなたはtop_recipsを使ってクラスを指定しましたmlb = MultiLabelBinarizer(classes=top_recips)ですが、テストデータにtransform(とfitまたはtransform_transformはしません)だけを行う方が良いです。

  • +0

    私が提案したようにMultiLabelTrasnformerのコードを変更しましたが、今はtest_xで予測しようとするとKeyErrorが発生します 変更点があるQのコードを更新してください。あなたが示唆したように列車データには存在しないテストデータにしか現れない受信者がいるので、エラーが起こっていると私は信じています。 マルチラベル二値化装置が列車とテストセットのすべての可能な受信者について知っているように、これをどのように修正できますか? – user330612

    +0

    @ user330612 CoRecipientsカラムのすべての既知のラベルに対して、 'MultiLabelTrasnformer'のclasses属性を使用します。あなたがy_trainとy_testのためにやったように。 –

    +0

    それを得ました。しかし、このユニークなCoRecipientsのリストをMultiLabelTransformerに渡すにはどうすればよいですか? co_recips = list(set([in b]の場合はdf.CoRecipients.tolist()内のa)) – user330612

    関連する問題