web-dev-qa-db-ja.com

ドキュメントをカテゴリに分類する

Postgresデータベースにトピックカテゴリでタグ付けされた約300kのドキュメントが保存されています(合計で約150のカテゴリがあります)。まだカテゴリがない別の15万のドキュメントがあります。プログラムでそれらを分類するための最良の方法を見つけようとしています。

私は [〜#〜] nltk [〜#〜] とその単純ベイズ分類器を探索してきました。良い出発点のようです(このタスクのためのより良い分類アルゴリズムを提案できれば、私はすべての耳です)。

私の問題は、150のカテゴリすべて/ 300kのドキュメントでNaiveBayesClassifierを一度にトレーニングするのに十分なRAMがないことです(5つのカテゴリでトレーニングは8GBを使用)。さらに、分類器の精度はより多くのカテゴリでトレーニングすると低下します(2つのカテゴリで90%の精度、5で81%、10で61%)。

一度に5つのカテゴリで分類子をトレーニングし、15万のドキュメントすべてを分類子に通して、一致するものがあるかどうかを確認する必要がありますか?これはうまくいくようですが、どのカテゴリにも実際には一致しないドキュメントが、利用可能な最良の一致であるという理由だけで分類子に突き刺さる誤検知がたくさんあることを除けば...ありますかドキュメントがどのカテゴリにも当てはまらない場合に備えて、分類子に「上記のいずれでもない」オプションを設定する方法はありますか?

これが私のテストクラスです http://Gist.github.com/45188

33
erikcw

ドキュメントを TF-log(1 + IDF)vectors に変換することから始める必要があります:用語の頻度はまばらなので、python dict with term as key and count値として入力し、合計数で割ってグローバル頻度を取得します。

別の解決策は、たとえばabs(hash(term))を正の整数キーとして使用することです。次に、python dictよりも線形代数演算を実行するのに便利で効率的なscipy.sparseベクトルを使用します。

また、同じカテゴリに属する​​すべてのラベル付きドキュメントの頻度を平均して、150の頻度ベクトルを作成します。次に、ラベルを付ける新しいドキュメントについて、ドキュメントベクトルと各カテゴリベクトルの間の コサイン類似度 を計算し、ドキュメントのラベルとして最も類似したカテゴリを選択できます。

これが十分でない場合は、 この例 of scikit-learn (これはのラッパーです)で説明されているように、L1ペナルティを使用してロジスティック回帰モデルをトレーニングする必要があります。 @ephesで説明されているliblinear)。ロジスティック回帰モデルのトレーニングに使用されるベクトルは、良好なパフォーマンス(適合率と再現率)を得るために、以前に導入されたTD-log(1 + IDF)ベクトルである必要があります。 scikit learn libは、特定のモデルと特定のデータセットのスコアを計算するルーチンを備えたsklearn.metricsモジュールを提供します。

大規模なデータセットの場合: vowpal wabbit を試してみてください。これは、大規模なドキュメント分類の問題に対しておそらく地球上で最速のウサギです(ただし、使用は簡単ではありませんpythonラッパーAFAIK) 。

32
ogrisel

あなたの文書はどれくらいの大きさ(単語数)ですか? 150Kのtrainingdocsでのメモリ消費は問題になりません。

ナイーブベイズは、トレーニング例が少ない、またはトレーニングデータが非常にノイズの多いカテゴリが多い場合に特に適しています。しかし、一般的に、線形サポートベクターマシンははるかに優れたパフォーマンスを発揮します。

問題はマルチクラス(ドキュメントが1つのカテゴリにのみ属している)またはマルチラベル(ドキュメントが1つ以上のカテゴリに属している)ですか?

精度は、分類器のパフォーマンスを判断するための適切な選択ではありません。適合率vs再現率、適合率再現率ブレークイーブンポイント(prbp)、f1、aucを使用し、信頼度しきい値の値に基づいて適合率(x)が適合率(y)に対してプロットされている適合率vs再現率曲線を確認する必要があります。 (ドキュメントがカテゴリに属しているかどうか)。通常、カテゴリごとに1つのバイナリ分類子を作成します(1つのカテゴリのポジティブトレーニング例と、現在のカテゴリに属していない他のすべてのトレーニング例)。カテゴリごとに最適な信頼度のしきい値を選択する必要があります。カテゴリごとのこれらの単一のメジャーをグローバルパフォーマンスメジャーに結合する場合は、マイクロ(すべての真陽性、偽陽性、偽陰性、真陰性を合計し、結合されたスコアを計算する)またはマクロ(カテゴリごとの計算スコアと次に、これらのスコアをすべてのカテゴリで平均します)平均。

数千万のドキュメント、数百万のトレーニング例、数千のカテゴリ(マルチラベル)のコーパスがあります。トレーニング時間の深刻な問題に直面しているため(1日あたりのドキュメントの新規、更新、削除の数が非常に多い)、 liblinear の修正バージョンを使用します。ただし、python liblinear( liblinear2scipy または scikit-learn )のラッパーのいずれかを使用する小さな問題の場合は正常に機能するはずです。

11
ephes

ドキュメントがどのカテゴリにも当てはまらない場合に備えて、分類子に「上記のどれでもない」オプションを設定する方法はありますか?

この効果は、「上記のどれでもない」疑似カテゴリを毎回トレーニングするだけで得られる可能性があります。トレーニングできる最大数が5つのカテゴリである場合(RAMを大量に消費する理由はわかりませんが)、実際の2Kドキュメントからそれぞれ4つの実際のカテゴリをトレーニングし、2Kドキュメントで「上記のどれでもない」カテゴリをトレーニングします。他のすべての146カテゴリからランダムに取得されます(「層化サンプリング」アプローチが必要な場合は、それぞれから約13〜14で、より健全な場合があります)。

それでも少し厄介な感じがするので、まったく異なるアプローチを使用したほうがよい場合があります。300Kの事前タグ付きドキュメントを150の合理的に分離可能なクラスターに定義する多次元ドキュメントメジャーを見つけて、それぞれを割り当てます。 -このように決定された適切なクラスターへのタグなしドキュメント。 NLTKには、この種のことをサポートするために直接利用できるものはないと思いますが、ねえ、NLTKは非常に急速に成長しているので、何かを見逃している可能性があります... ;-)

2
Alex Martelli