SkLearn: Feature Union со словарем и текстовыми данными

У меня есть DataFrame, например:

     text_data                worker_dicts                  outcomes

0    "Some string"           {"Sector":"Finance",             0
                              "State: NJ"}                   
1    "Another string"        {"Sector":"Programming",         1
                              "State: NY"}                             

В нем есть как текстовая информация, так и столбец, который является словарем. (Настоящий worker_dicts имеет гораздо больше полей). Меня интересует столбец двоичного результата.

Сначала я попытался объединить как text_data, так и worker_dict, грубо объединив оба столбца, а затем запустив для этого Multinomial NB:

    df['stacked_features']=df['text_data'].astype(str)+'_'+df['worker_dicts']
    stacked_features = np.array(df['stacked_features'])
    outcomes = np.array(df['outcomes'])
    text_clf = Pipeline([('vect', TfidfVectorizer(stop_words='english'), ngram_range = (1,3)), 
   ('clf', MultinomialNB())])
    text_clf = text_clf.fit(stacked_features, outcomes)

Но я получил очень плохую точность, и я думаю, что подгонка двух независимых моделей будет лучшим использованием данных, чем подгонка одной модели для обоих типов функций (как я делаю с наложением).

Как мне использовать Feature Union? worker_dicts немного странный, потому что это словарь, поэтому я очень запутался, как мне его разобрать.


person Community    schedule 19.12.2017    source источник


Ответы (1)


Если ваши словарные записи категоричны, как в вашем примере, я бы создал разные столбцы из словарных статей, прежде чем выполнять дополнительную обработку.

new_features = pd.DataFrame(df['worker_dicts'].values.tolist())

Тогда new_features будет своим собственным фреймом данных со столбцами Sector и State, и вы можете закодировать их по мере необходимости в дополнение к TFIDF или другому извлечению функций для вашего столбца text_data. Чтобы использовать это в конвейере, вам нужно создать новый класс преобразователя, поэтому я мог бы предложить просто применить синтаксический анализ словаря и TFIDF отдельно, затем сложить результаты и добавить OneHotEncoding в конвейер, поскольку это позволяет указать столбцы, к которым нужно применить преобразователь. (Поскольку категории, которые вы хотите закодировать, являются строками, вы можете использовать LabelBinarizer вместо класса OneHotEncoder для преобразования кодирования.)

Если вы хотите просто использовать TFIDF для всех столбцов отдельно с конвейером, вам нужно будет использовать вложенный конвейер и FeatureUnion, настроенные для извлечения столбцов, как описано здесь.

Если у вас есть функции с горячим кодированием в фреймах данных X1 и X2, как описано ниже, и ваши текстовые функции в X3, вы можете сделать что-то вроде следующего, чтобы создать конвейер. (Есть много других вариантов, это только один из способов)

X = pd.concat([X1, X2, X3], axis=1)

def select_text_data(X):
    return X['text_data']

def select_remaining_data(X):
    return X.drop('text_data', axis=1)


# pipeline to get all tfidf and word count for first column
text_pipeline = Pipeline([
    ('column_selection', FunctionTransformer(select_text_data, validate=False)),
    ('tfidf', TfidfVectorizer())
])


final_pipeline = Pipeline([('feature-union', FeatureUnion([('text-features', text_pipeline), 
                               ('other-features', FunctionTransformer(select_remaining_data))
                              ])),
                          ('clf', LogisticRegression())
                          ])

(MultinomialNB не будет работать в конвейере, потому что у него нет методов fit и fit_transform)

person elz    schedule 20.12.2017
comment
Это очень информативный ответ! Тем временем я закончил тем, что использовал Pandas для некоторых вещей: во-первых, я превратил каждый из ключей worker_dicts (Sector, State) в столбцы, а затем использовал однократное кодирование для каждого из этих столбцов. Затем для обоих столбцов я сложил все разреженные матрицы, которые были выходами однократного кодирования. Пусть X1 и X2 обозначают сложенные разреженные массивы, состоящие из однократного кодирования Sector и State соответственно. Пусть X3 обозначает векторизованный столбец text_data. - person ; 21.12.2017
comment
Учитывая изменения в данных, где у нас теперь есть X1, X2, X3, внесете ли вы какие-либо изменения в два предложенных вами метода? - person ; 21.12.2017