0

Ich habe einen Pandas Datenrahmen, der Informationen über Nachrichten enthält, die vom Benutzer gesendet werden. Für mein Modell bin ich daran interessiert, fehlende Empfänger einer Nachricht zu prognostizieren i, e gegeben Empfänger A, B, C einer Nachricht Ich möchte vorhersagen, wer noch Teil der Empfänger sein sollte.Wie transformiert man mehrere Features in einer PipeLine mit FeatureUnion?

Ich mache Multi-Label-Klassifizierung mit OneVsRestClassifier und LinearSVC. Für Funktionen möchte ich die Empfänger der Nachricht verwenden. Thema und Körper.

Da Empfänger eine Liste von Benutzern ist, möchte ich diese Spalte mit MultiLabelBinarizer transformieren. Für Betreff und Text mag ich TFIDF

Mein Eingang Beize Dateidaten verwenden, haben wie folgt: Alle Werte sind Strings außer Empfänger die ein Satz()

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

Ich bin mit benutzerdefinierter Funktion Vereinigung mit Transformatoren in der Pipeline, um dies wie folgt zu erreichen.

Ich bin mir nicht sicher, ob ich die featurization der CoRecipients Spalte richtig mache. Da die Ergebnisse nicht richtig aussehen. Irgendeine Ahnung?

UPDATE 1

den Code des MLB Transformators wie folgt verändert:

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

und fixiert den Test zu verwenden, setzen 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']) 

die unten sehend 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

Arbeits Code

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) 

Antwort

1

Sie die transformierende falsch für MultiLabelBinarizer tun. Sie sind sowohl für Trainings- als auch für Testdaten geeignet. Das ist nicht richtig.

Sie sollten nur immer auf Trainingsdaten passen und Transform auf Testdaten verwenden.

Sie diesen Fehler zweimal gemacht haben:

  • In MultiLabelTransformer, wo Sie die "Co-Empfänger
  • Während die Umwandlung der test_y verwandeln, wo Sie die
'TopRecipients' verwandeln

Das Problem ist, wenn Testdaten unterschiedliche (oder neue) Werte in 'Co-Empfänger' oder 'TopRecipients' haben, hat das zurückgegebene Array eine andere Form als während der Trainingszeit. Das wird zu falschen Ergebnissen führen.

Code wie folgt ändern:

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

Und

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

Und in der Pipeline:

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

Obwohl die letzte Änderung in test_y das zurückgegebene Array nicht beeinflussen, weil Sie haben die Klassen mit top_recips während angegeben mlb = MultiLabelBinarizer(classes=top_recips), aber es ist immer noch besser, nur die Testdaten zu transformieren (und nie passen oder fit_transform).

+0

Ich habe den Code für MultiLabelTrasnformer wie Sie vorgeschlagen geändert und ich erhalte jetzt einen KeyError beim Versuch, auf test_x vorherzusagen Aktualisieren Sie den Code in der Q mit Änderungen vorgeschlagen. Ich glaube, dass der Fehler passiert, weil es einige Empfänger gibt, die nur in den Testdaten auftauchen, die nicht in den Zugdaten vorhanden sind, wie Sie angespielt haben. Wie kann ich das beheben, so dass der Multi-Label-Binarizer über alle möglichen Empfänger in Zug- und Test-Sets informiert? – user330612

+0

@ user330612 Verwenden Sie das Attribut classes im 'MultiLabelTrasnformer' für alle bekannten Beschriftungen in der Spalte CoRecipients. So wie du es für y_train und y_test gemacht hast. –

+0

Bekam das. Aber wie gebe ich diese Liste der einzigartigen CoRecipients an den MultiLabelTransformer weiter? co_recips = Liste (set ([a für b in df.CoRecipients.tolist() für a in b])) – user330612

Verwandte Themen