次のクラスは、非常に大きな文字列(テキストの小説全体)を解析し、それをタプルとして格納される連続する4文字の文字列に分割します。次に、計算に基づいて各タプルに確率を割り当てることができます。私はこれをモンテカルロ/遺伝的アルゴリズムの一部として使用して、構文のみに基づいて言語を認識するようにプログラムをトレーニングしています(文字の遷移のみ)。
これを行うより速い方法があるかどうか疑問に思います。任意の4文字のタプルの確率を調べるのに約400msかかります。関連するメソッド_Probablity()は、クラスの最後にあります。
これは、私の別の投稿に関連する計算集約型の問題です。関数の妥当性を計算するためのアルゴリズム/モンテカルロ法
最終的には、これらの値を4Dマトリックスに保存したいと思います。しかし、アルファベットに26文字あることを考えると、これは非常に大きな作業になります。(26x26x26x26)。小説の最初の15000文字だけを取ると、パフォーマンスは1トン向上しますが、私のデータはそれほど有用ではありません。
テキスト'source'を解析するメソッドは次のとおりです。
private List<Tuple<char, char, char, char>> _Parse(string src)
{
var _map = new List<Tuple<char, char, char, char>>();
for (int i = 0; i < src.Length - 3; i++)
{
int j = i + 1;
int k = i + 2;
int l = i + 3;
_map.Add
(new Tuple<char, char, char, char>(src[i], src[j], src[k], src[l]));
}
return _map;
}
そして、これが_Probabilityメソッドです。
private double _Probability(char x0, char x1, char x2, char x3)
{
var subset_x0 = map.Where(x => x.Item1 == x0);
var subset_x0_x1_following = subset_x0.Where(x => x.Item2 == x1);
var subset_x0_x2_following = subset_x0_x1_following.Where(x => x.Item3 == x2);
var subset_x0_x3_following = subset_x0_x2_following.Where(x => x.Item4 == x3);
int count_of_x0 = subset_x0.Count();
int count_of_x1_following = subset_x0_x1_following.Count();
int count_of_x2_following = subset_x0_x2_following.Count();
int count_of_x3_following = subset_x0_x3_following.Count();
decimal p1;
decimal p2;
decimal p3;
if (count_of_x0 <= 0 || count_of_x1_following <= 0 || count_of_x2_following <= 0 || count_of_x3_following <= 0)
{
p1 = e;
p2 = e;
p3 = e;
}
else
{
p1 = (decimal)count_of_x1_following / (decimal)count_of_x0;
p2 = (decimal)count_of_x2_following / (decimal)count_of_x1_following;
p3 = (decimal)count_of_x3_following / (decimal)count_of_x2_following;
p1 = (p1 * 100) + e;
p2 = (p2 * 100) + e;
p3 = (p3 * 100) + e;
}
//more calculations omitted
return _final;
}
}
編集-私は物事を片付けるためにもっと詳細を提供しています、
1)厳密に言えば、私はこれまで英語しか扱っていませんが、異なるアルファベットを考慮する必要があるのは事実です。現在、このペーパーで説明されているものと同様に、プログラムで英語のみを認識したいと考えています。http ://www-stat.stanford.edu/~cgates/PERSI/papers/MCMCRev.pdf
2)n <= 4の文字のnタプルの確率を計算しています。たとえば、文字列「that」の合計確率を計算する場合、これらの独立したタプルに分解して、それぞれの確率を計算します。個別に最初に:
[t] [h]
[t] [h] [a]
[それ]
[t] [h]が最も重みが与えられ、次に[t] [h] [a]、次に[t] [h][a][t]が与えられます。私は4文字のタプルを単一のユニットとして見ているだけではないので、テキスト内の[t] [h][a][t]のインスタンスを合計数で割ることはできません。次の4タプルの。
各4タプルに割り当てられた値は、テキストに適合しすぎることはありません。これは、偶然にも多くの実際の英語の単語がテキストに表示されない可能性があり、不釣り合いに低いスコアを取得するべきではないためです。1次の文字遷移(2タプル)を強調すると、この問題が改善されます。3タプルに移動してから、4タプルで計算を調整します。
私は、メモリの浪費である同一のタプルを繰り返すのではなく、テキスト内でタプルが発生する頻度のカウントを単純に集計する辞書を思いつきました(Vilxが提案したものと同様)。これにより、ルックアップあたり約400ミリ秒から約40ミリ秒になりました。これは、かなり大きな改善です。しかし、私はまだ他の提案のいくつかを調べる必要があります。