Я пытаюсь использовать CountVectorizer()
с Pipeline
и ColumnTransformer
. Поскольку CountVectorizer()
создает разреженную матрицу, я использовал FunctionTransformer
, чтобы убедиться, что ColumnTransformer
может hstack
правильно составить результирующую матрицу.
import pandas as pd
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, FunctionTransformer
from sklearn.compose import ColumnTransformer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.pipeline import Pipeline
from typing import Callable
# Dataset
df = pd.DataFrame([['a', 'Hi Tom', 'It is hot', 1],
['b', 'How you been Tom', 'hot coffee', 2],
['c', 'Hi you', 'I want some coffee', 3]],
columns=['col_for_ohe', 'col_for_countvectorizer_1', 'col_for_countvectorizer_2', 'num_col'])
# Use FunctionTransformer to ensure dense matrix
def tf_text(X, vectorizer_tf: Callable):
X_vect_ = vectorizer_tf.fit_transform(X)
return X_vect_.toarray()
tf_transformer = FunctionTransformer(tf_text, kw_args={'vectorizer_tf': CountVectorizer()})
# Transformation Pipelines
tf_transformer_pipe = Pipeline(
steps = [('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
('tf', tf_transformer)])
ohe_transformer_pipe = Pipeline(
steps = [('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
('ohe', OneHotEncoder(handle_unknown='ignore', sparse=False))])
transformer = ColumnTransformer(transformers=[
('cat_ohe', ohe_transformer_pipe, ['col_for_ohe']),
('cat_tf', tf_transformer_pipe, ['col_for_countvectorizer_1', 'col_for_countvectorizer_2'])
], remainder='passthrough')
transformed_df = transformer.fit_transform(df)
Я получаю AttributeError: объект 'numpy.ndarray' не имеет атрибута 'ниже'. Я видел этот вопрос и подозреваю, что CountVectorizer()
является виновником, но не знаю, как его решить (в предыдущем вопросе ColumnTransformer
не используется). Я наткнулся на DenseTransformer
, который хотел бы использовать вместо FunctionTransformer
, но, к сожалению, он не поддерживается в моей компании.
Я думаю, вам действительно стоит еще раз оглянуться на свои основы. Ваш вопрос говорит мне о том, что вы недостаточно хорошо понимаете функцию, чтобы реализовать ее эффективно. Спросите еще раз, когда вы проведете достаточно исследований самостоятельно, чтобы не смущаться.
Да, я новичок. Но я стараюсь изо всех сил и надеюсь, что со временем мне станет лучше, если я получу помощь от тех, кто готов помочь. Я набрался смелости, чтобы опубликовать вопрос, несмотря на свое невежество, пожалуйста, не обескураживайте людей, которые пытаются стать лучше и еще только начинают свой путь.
Ваш ответ может быть улучшен с помощью дополнительной вспомогательной информации. Пожалуйста, редактировать добавьте дополнительную информацию, например цитаты или документацию, чтобы другие могли подтвердить правильность вашего ответа. Дополнительную информацию о том, как писать хорошие ответы, можно найти в справочном центре.
В CountVectorizer передайте lower_case=False.
Я думаю, что подчеркивания нет, так как в нижнем регистре = False. Когда я пытаюсь это сделать, я получаю другую ошибку: «Ошибка типа: ожидаемая строка или объект, подобный байтам».
Имо, первое, что нужно сделать, это то, что CountVectorizer()
требует ввода 1D; ваш пример не работает, потому что вменение возвращает массив 2D numpy, что означает, что вам нужно добавить индивидуальную обработку, чтобы заставить его работать.
Затем вы также должны учитывать, что при использовании экземпляра CountVectorizer()
(который, опять же, требует ввода 1D) в качестве преобразователя в ColumnTransformer()
, вы должны передать колонны трансформаторов:
columns: str, array-like of str, int, array-like of int, array-like of bool, slice or callable
Indexes the data on its second axis. Integers are interpreted as positional columns, while strings can reference DataFrame columns by name. A scalar string or int should be used where transformer expects X to be a 1d array-like (vector), otherwise a 2d array will be passed to the transformer. [...]
Это было бы полезно при интерпретации фрагмента, который я опубликую как возможное решение.
import pandas as pd
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, FunctionTransformer
from sklearn.compose import ColumnTransformer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.pipeline import Pipeline
from typing import Callable
from sklearn.base import BaseEstimator, TransformerMixin
# Dataset
df = pd.DataFrame([['a', 'Hi Tom', 'It is hot', 1],
['b', 'How you been Tom', 'hot coffee', 2],
['c', 'Hi you', 'I want some coffee', 3]],
columns=['col_for_ohe', 'col_for_countvectorizer_1', 'col_for_countvectorizer_2', 'num_col'])
class DimTransformer(BaseEstimator, TransformerMixin):
def __init__(self):
pass
def fit(self, *_):
return self
def transform(self, X, *_):
return pd.DataFrame(X)
# Use FunctionTransformer to ensure dense matrix
def tf_text(X, vectorizer_tf: Callable):
X_vect_ = vectorizer_tf.fit_transform(X)
return X_vect_.toarray()
tf_transformer = FunctionTransformer(tf_text, kw_args={'vectorizer_tf': CountVectorizer()})
# Transformation Pipelines
tf_transformer_pipe = Pipeline(
steps = [('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
('dt', DimTransformer()),
('ct', ColumnTransformer([
('tf1', tf_transformer, 0),
('tf2', tf_transformer, 1)
]))
])
ohe_transformer_pipe = Pipeline(
steps = [('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
('ohe', OneHotEncoder(handle_unknown='ignore', sparse=False))])
transformer = ColumnTransformer(transformers=[
('cat_ohe', ohe_transformer_pipe, ['col_for_ohe']),
('cat_tf', tf_transformer_pipe, ['col_for_countvectorizer_1', 'col_for_countvectorizer_2'])
], remainder='passthrough')
transformed_df = transformer.fit_transform(df)
А именно, я добавляю преобразователь, который просто преобразует массив, возвращаемый экземпляром SimpleImputer
, в DataFrame. Затем - и самое главное - поскольку кажется невозможным применить векторизацию к 2D-входу, полученному в результате двух предыдущих шагов ('imputer'
и 'dt'
), я добавляю еще один ColumnTransformer
, который разделяет векторизацию на два параллельных шага (векторизация на столбец). Обратите внимание, что в этот момент ссылки на столбцы позиционируются, поскольку имена столбцов, возможно, изменились. Конечно, это индивидуальное решение, но, по крайней мере, может дать некоторые подсказки.
Учитывая, что на самом деле у вас нет пропущенных значений, вы можете увидеть, что это действительно работает, сравнив его с выводом:
dt = DimTransformer().fit_transform(df)
ct = ColumnTransformer([
('tf1', tf_transformer, 1),
('tf2', tf_transformer, 2)
])
ct.fit_transform(dt)
print(ct.named_transformers_['tf1'].kw_args['vectorizer_tf'].vocabulary_) print(ct.named_transformers_['tf2'].kw_args['vectorizer_tf'].vocabulary_)
и заметив, что столбцы с четвертого до предпоследнего предыдущего вывода (а именно те, на которые повлияло применение 'cat_tf'
) совпадают с столбцами чуть ниже.
Вот пара постов, посвященных использованию CountVectorizer
в экземпляре ColumnTransformer
, хотя они не рассматривали предварительную подстановку набора данных.
lower
— это метод строк Python. панды также могут использовать его. Массив numpy не работает. Вам нужно выяснить, почему рассматриваемый объект является массивом. Вы должны изучить трассировку.