Трубопровод Scikit-Learn: решена малая матрица, но требуются плотные данные
Мне трудно понять, как исправить созданный мной конвейер (читайте: в основном вставляемый из учебника). Это python 3.4.2:
df = pd.DataFrame
df = DataFrame.from_records(train)
test = [blah1, blah2, blah3]
pipeline = Pipeline([('vectorizer', CountVectorizer()), ('classifier', RandomForestClassifier())])
pipeline.fit(numpy.asarray(df[0]), numpy.asarray(df[1]))
predicted = pipeline.predict(test)
Когда я запустил его, я получаю:
TypeError: A sparse matrix was passed, but dense data is required. Use X.toarray() to convert to a dense numpy array.
Это для строки pipeline.fit(numpy.asarray(df[0]), numpy.asarray(df[1]))
.
Я много экспериментировал с решениями с помощью numpy, scipy и т.д., но я до сих пор не знаю, как это исправить. И да, подобные вопросы возникли раньше, но не внутри конвейера.
Где я должен применить toarray
или todense
?
Ответы
Ответ 1
К сожалению, эти два несовместимы. CountVectorizer
создает разреженную матрицу, а для RandomForestClassifier требуется плотная матрица. Можно конвертировать с помощью X.todense()
. Это существенно увеличит объем памяти.
Ниже приведен пример кода для этого на основе http://zacstewart.com/2014/08/05/pipelines-of-featureunions-of-pipelines.html, который позволяет вам вызывать .todense()
на этапе конвейера.
class DenseTransformer(TransformerMixin):
def fit(self, X, y=None, **fit_params):
return self
def transform(self, X, y=None, **fit_params):
return X.todense()
Получив DenseTransformer
, вы можете добавить его в качестве шага конвейера.
pipeline = Pipeline([
('vectorizer', CountVectorizer()),
('to_dense', DenseTransformer()),
('classifier', RandomForestClassifier())
])
Другой вариант - использовать классификатор, предназначенный для разреженных данных, например LinearSVC
.
from sklearn.svm import LinearSVC
pipeline = Pipeline([('vectorizer', CountVectorizer()), ('classifier', LinearSVC())])
Ответ 2
Случайные леса в 0.16-dev теперь принимают разреженные данные.
Ответ 3
Наиболее кратким решением было бы использование FunctionTransformer
для преобразования в плотный: это будет автоматически реализовывать методы fit
, transform
и fit_transform
как в ответе Дэвида. Кроме того, если мне не нужны специальные имена для моих шагов конвейера, я бы хотел использовать удобную функцию sklearn.pipeline.make_pipeline
чтобы включить более минималистский язык для описания модели:
from sklearn.preprocessing import FunctionTransformer
pipeline = make_pipeline(
CountVectorizer(),
FunctionTransformer(lambda x: x.todense(), accept_sparse=True),
RandomForestClassifier()
)
Ответ 4
вы можете изменить pandas Series
на массивы с помощью метода .values
.
pipeline.fit(df[0].values, df[1].values)
Однако я думаю, что проблема здесь возникает, потому что CountVectorizer()
возвращает разреженную матрицу по умолчанию и не может быть передана в RF классификатор. CountVectorizer()
имеет параметр dtype
для указания типа возвращаемого массива. Тем не менее, как правило, вам нужно сделать какое-то уменьшение размерности, чтобы использовать случайные леса для классификации текста, потому что в мешке слов есть векторы очень долго
Ответ 5
с этим конвейером добавим TfidTransformer plus
pipelinex = Pipeline([('bow',vectorizer),
('tfidf',TfidfTransformer()),
('to_dense', DenseTransformer()),
('classifier',classifier)])