web-dev-qa-db-ja.com

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を適用する必要があるのはどこですか?

26
Ada Stra

残念ながら、これら2つには互換性がありません。 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())])
47
David Maust

0.16-devのランダムフォレストは、スパースデータを受け入れるようになりました。

16
Gilles Louppe

最も簡潔な解決策は、FunctionTransformerを使用してデンスに変換することです。これは、Davidの答えのように、fittransform、およびfit_transformメソッドを自動的に実装します。さらに、パイプラインステップに特別な名前が必要ない場合は、sklearn.pipeline.make_pipeline便利な関数を使用して、モデルを記述するためのよりシンプルな言語を有効にします。

from sklearn.preprocessing import FunctionTransformer

pipeline = make_pipeline(
     CountVectorizer(), 
     FunctionTransformer(lambda x: x.todense(), accept_sparse=True), 
     RandomForestClassifier()
)
16
maxymoo

_.values_メソッドを使用して、pandas Seriesを配列に変更できます。

_pipeline.fit(df[0].values, df[1].values)
_

ただし、CountVectorizer()はデフォルトでスパース行列を返し、RF分類子にパイプすることはできません。CountVectorizer()には返される配列のタイプを指定するdtypeパラメーター単語の特徴ベクトルは非常に長いため、通常、テキストの分類にランダムフォレストを使用するには、何らかの次元削減を行う必要があります

3
JAB