n-gramデータの保存


12

nグラムのデータを保存することについて少しブレインストーミングしたいと思っていました。私のプロジェクトでは、すべての(n -1)データ項目を知っており、適用可能なすべてのnグラムに対する線形補間を使用して統計的にnを推測したい言語の問題を解決しようとしています。(はい、用語集に従ってタグを既知の単語に割り当てるタガーと、未知の単語の単語の種類を推測するサフィックスツリーがあります。ここで説明するnグラムコンポーネントは、曖昧さの解決を担当します。)

私の最初のアプローチは、観測されたすべてのnグラム(n = 1..3、つまりモノグラム、バイグラム、トライグラム)のデータをそれぞれのSQLデータベースに単純に格納し、それを1日と呼ぶことです。しかし、私のプロジェクトの要件は、他のベクトルの長さ(n)を含むように変更される可能性があり、多くの作業(スキーマの更新、アプリケーションコードの更新など)なしにアプリケーションを4グラムに適応させたいです。理想的には、コードを大幅に(またはまったく)変更せずに、4グラムで動作するようにアプリケーションに指示し、特定のデータソースからのデータをトレーニングするだけです。

すべての要件をまとめるには:

  • nグラムのデータを保存する機能(最初はn = {1、2、3}の場合
  • 使用するnグラムの種類を変更する機能(アプリケーションの実行間)
  • nグラムデータを(再)トレーニングする機能(アプリケーションの実行間)
  • データストアを照会する機能(たとえば、A、B、Cを観察した場合、トレーニング済みの4、3、2、1グラムのデータセットを使用して、最も頻繁に観察されるアイテムを知りたい)

    ほとんどの場合、アプリケーションは読み込みが重くなり、データセットはほとんどの場合再トレーニングされません

  • このソリューションは、.NET Framework(最大4.0)を採用しています

では、そのようなタスクに適した設計は何でしょうか?

  • nの SQLサーバー(MSSQL、MySQLなど)によって管理される固定テーブル(たとえば、2グラム、3グラムなどの専用テーブル)
  • または、ドキュメントのキーとして最初のn -1 を保存し、ドキュメント自体にn番目の値と観測頻度が含まれるNoSQLドキュメントデータベースソリューションですか?
  • または何か違う?

3
これは、スタックオーバーフローに適していると思います。
コンラッドルドルフ

1
おそらく、トライ(プレフィックスツリー)データ構造が要件に合うでしょうか?
シュドラー


わかった、ありがとう。質問をあちらこちらで取得しようとします。
マニー

4
この質問は、programmers.stackexchange.comに最適であり、stackoverflow、IMOに移行すべきではありません。ここで尋ねる必要があるのは、まさに「ホワイトボード状況」の質問です。詳細については、メタを確認してください。
user281377

回答:


8

Nの最適範囲がわからない場合は、絶対に変更できるようにする必要があります。たとえば、アプリケーションが特定のテキストが英語である可能性を予測する場合、おそらくN 3..5に文字N-gramを使用する必要があります。(これは実験的に発見したものです。)

アプリケーションに関する詳細を共有していませんが、問題は十分に明確です。リレーショナルデータベース(またはNoSQLドキュメントベースのソリューション)でN-gramデータを表現したい。私自身の解決策を提案する前に、次のアプローチを検討してください。

  1. Google ngramsをデータベースに最適に保存する方法は?
  2. nグラム未満のテーブルのデータベースにn-gramを保存する
  3. リレーショナルデータベースを使用したGoogle Web 1T 5-gramの管理

さて、上記のリンクをまったく読んでいないので、N-gramのサイズごとに1つずつ、複数のテーブルを使用する単純なリレーショナルデータベースアプローチをお勧めします。すべてのデータを必要な最大列を持つ単一のテーブルに入れることができます(つまり、ngram_4にバイグラムとトライグラムを格納し、最終列をnullのままにします)が、データをパーティション分割することをお勧めします。データベースエンジンによっては、多数の行を持つ単一のテーブルがパフォーマンスに悪影響を与える可能性があります。

  create table ngram_1 (
      word1 nvarchar(50),
      frequency FLOAT,
   primary key (word1));

  create table ngram_2 (
      word1 nvarchar(50),
      word2 nvarchar(50),
      frequency FLOAT,
   primary key (word1, word2));

  create table ngram_3 (
      word1 nvarchar(50),
      word2 nvarchar(50),
      word3 nvarchar(50),
      frequency FLOAT,
   primary key (word1, word2, word3));

  create table ngram_4 (
      word1 nvarchar(50),
      word2 nvarchar(50),
      word3 nvarchar(50),
      word4 nvarchar(50),
      frequency FLOAT,
   primary key (word1, word2, word3, word4));

次に、すべてのngramテーブルから最も可能性の高い次の単語を返すクエリを提供します。ただし、最初に、上記の表に挿入する必要があるサンプルデータをいくつか示します。

  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'building', N'with', 0.5)
  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'hit', N'the', 0.1)
  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'man', N'hit', 0.2)
  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'the', N'bat', 0.7)
  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'the', N'building', 0.3)
  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'the', N'man', 0.4)
  INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'with', N'the', 0.6)
  INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'building', N'with', N'the', 0.5)
  INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'hit', N'the', N'building', 0.3)
  INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'man', N'hit', N'the', 0.2)
  INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'the', N'building', N'with', 0.4)
  INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'the', N'man', N'hit', 0.1)
  INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'with', N'the', N'bat', 0.6)
  INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'building', N'with', N'the', N'bat', 0.5)
  INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'hit', N'the', N'building', N'with', 0.3)
  INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'man', N'hit', N'the', N'building', 0.2)
  INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'the', N'building', N'with', N'the', 0.4)
  INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'the', N'man', N'hit', N'the', 0.1)

最も可能性の高い次の単語をクエリするには、次のようなクエリを使用します。

  DECLARE @word1 NVARCHAR(50) = 'the'
  DECLARE @word2 NVARCHAR(50) = 'man'
  DECLARE @word3 NVARCHAR(50) = 'hit'
  DECLARE @bigramWeight FLOAT = 0.2;
  DECLARE @trigramWeight FLOAT = 0.3
  DECLARE @fourgramWeight FLOAT = 0.5

  SELECT next_word, SUM(frequency) AS frequency
  FROM (
    SELECT word2 AS next_word, frequency * @bigramWeight AS frequency
    FROM ngram_2
    WHERE word1 = @word3
    UNION
    SELECT word3 AS next_word, frequency * @trigramWeight AS frequency
    FROM ngram_3
    WHERE word1 = @word2
      AND word2 = @word3
    UNION
    SELECT word4 AS next_word, frequency * @fourgramWeight AS frequency
    FROM ngram_4
    WHERE word1 = @word1
      AND word2 = @word2
      AND word3 = @word3
    ) next_words
  GROUP BY next_word
  ORDER BY SUM(frequency) DESC

さらにngramテーブルを追加する場合は、上記のクエリに別のUNION句を追加する必要があります。最初のクエリでword1 = @ word3を使用したことに気付くかもしれません。2番目のクエリでは、word1 = @ word2 AND word2 = @ word3です。これは、ngramデータのクエリで3つの単語を揃える必要があるためです。3つの単語のシーケンスで最も可能性の高い次の単語が必要な場合は、シーケンス内の単語の最後の単語に対してバイグラムデータの最初の単語をチェックする必要があります。

必要に応じて、重量パラメーターを調整できます。この例では、序数の「n」グラムが高いほど信頼性が高いと想定しました。

PS構成を介して任意の数のngram_Nテーブルを処理するプログラムコードを構築します。ngram_5およびngram_6テーブルを作成した後、N-gram範囲N(1..6)を使用するようにプログラムを宣言的に変更できます。


このクエリでは、ここにある頻度スコアのみが表示されます。次の予測単語を選択するにはどうすればよいですか。文に最も関連するのはどれですか?
TomSawyer

良い点は@TomSawyerです。サンプルデータを回答に追加し、最も可能性の高い次の単語を返すサンプルクエリを提供しました。
マシューロダトゥス

更新のTks。しかし、ここで頻度を計算するにはどうすればよいですか?つまり、in ngram_2では、フレーズのbuilding with周波数は0.5です。と同じ質問、それ@bigramWeightは何ですか。freqは、データベースを更新するたびに更新されるフィールドです。つまり、ユーザーがさらに文字列を入力すると、この文字列の頻度が再計算されますか?0.5は各フレーズの合計使用時間または出現率の0.5%ですか?
TomSawyer

bigramWeightとtrigramWeight(など)は、全体的な計算で異なるn-gramに重み付けする方法です。これは、長いn-gramのエントロピーが高く、短いn-gramよりも「カウント」したいという単純な言い方です。
マシューロダタス

データベースの更新に関しては、明らかにすべての詳細をカバーしておらず、改善の余地がたくさんあります。たとえば、nvarcharsをngramテーブルに保存するのではなく、wordsテーブル(word_id INT、word NVARCHAR)にトークン化してから、ngramテーブルのword_idsを参照することをお勧めします。再トレーニングでテーブルを更新するには、そうです。頻度フィールドを更新するだけです。
マシューロダトゥス

3

他の人が提案していることとは反対に、ハッシュマップやキーバリューストアよりも複雑なデータ構造を避けることをお勧めします。

データアクセス要件に留意してください:a)99%のリクエスト-ngram "aaa-bbb-ccc"をクエリし、値(または0)を取得しますb)1%のリクエスト-特定のngramのカウントを挿入/更新しますc)なし(c)。

最も効果的な方法は、1回の検索で取得することです。範囲外(またはエスケープ)セパレーターを使用して、1つの文字列に完全なn-gram(たとえば、3gramの場合は "alpha | beta | gamma"、unigramの場合は "alpha"など)を組み合わせて、そのハッシュによって)。それは、NLPソフトウェアの多くがそれを行う方法です。

ngramデータが小さく(たとえば<1 gb)メモリに収まる場合、オーバーヘッドを避けるために効率的なプログラム内メモリ構造(ハッシュマップ、ツリー、試行など)を使用することをお勧めします。そして、単にフラットファイルにシリアライズ/デシリアライズします。ngramデータがテラバイト以上の場合、複数のノードに分割されたNoSQLキーバリューストアを選択できます。

パフォーマンスを向上させるために、すべての単語を整数IDに置き換えて、コアアルゴリズムが(遅い)文字列をまったく表示しないようにすることができます。同じアイデアを実装することはわずかに異なります。


1

最も効率的ではありませんが、シンプルで、あなたが望むようにデータベースに組み込まれています:

Table: word
Colums:
word (int, primary key) - a unique identifier for each word
text (varchar) - the actual word

Table: wordpos
Columns:
document (int) - a unique identified for the document of this word
word (int, foreign key to word.word) - the word in this position
pos (int) - the position of this word (e.g., first word is 1, next is 2, ...)

wordposには、ドキュメントとposのインデックスが必要です。

バイグラムは:

select word1.text as word1, word2.text as word2
from wordpos as pos1, wordpos as pos2, word as word1, word as word2
where pos1.document = pos2.document
      and pos1.pos = pos2.pos - 1
      and word1.word = pos1.word
      and word2.word = pos2.word

それからcount()して、頻度やものへの道をグループ化できます。

トライグラムに変更するには、この文字列を生成してword3を含めるのは簡単です。

実際にこれを行ったことがあります(SQLが少し錆びているかもしれませんが)。簡単にシークでき、ディスクからストリーミングできるフラットファイルのセットに決めました。Kindaは、ハードウェアによって、それをより良くする方法に依存しています。


1

私のアプリケーションのユニグラムからバイグラムとトライグラムへの単純な検索を改善しようとしている間、本質的に、あなたの質問を見ました。

要件の1つが分散ファイルシステムまたはデータベースを照会する能力である場合、これもあなたにとって興味深いかもしれません。ランタイムとスペースの条件。彼らはhttps://github.com/jermp/tongramsで実装を提供しました

n-gramの各「n」は、非常に高速な選択およびクエリ機能を備えた最小完全ハッシュ関数によってアクセスされる個別のテーブルに保持されます。テーブルは静的で、Google n-gramsテキストファイル形式の入力を使用してメインコードによって構築されます。

まだコードを使用していませんが、クエリの出所に関するオープンな要件については、さまざまな方法があります。

1つの方法:サーブレットに相当する.NETをデータベースまたはデータストアで使用し、ストレージスペースを節約する必要がある場合、各ngramテーブルをバイナリ形式でデータベース/データストアにテーブルとして格納するのは1つのオプションです(1つのデータベース/ datastoreテーブルは、すべての1グラムの効率的なngramコードの結果の静的ファイル、すべての2グラムの別のファイルなどに対応しています。クエリは、効率的なn-gramコードを呼び出すことで実行されます(サーブレットからアクセスできるようにラップされます)。これは、効率的なn-gramコードを使用して分散ファイルシステム上のファイルにアクセスする分散データベースを作成するための回避策です。バイナリデータベース/データストアテーブルにはそれぞれ、基礎となるファイルシステムのファイルサイズ制限があることに注意してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.