public void Check(string line) { // Морфологический разбор using (SolarixGrammarEngineNET.AnalysisResults tokens = gren.AnalyzeMorphology(line, LanguageID, SolarixGrammarEngineNET.GrammarEngine.MorphologyFlags.SOL_GREN_COMPLETE_ONLY)) { // Токенизация без использования синтаксических правил using (SolarixGrammarEngineNET.AnalysisResults projs = gren.AnalyzeMorphology(line, LanguageID, SolarixGrammarEngineNET.GrammarEngine.MorphologyFlags.SOL_GREN_TOKENIZE_ONLY)) { List <List <int> > word2tags = new List <List <int> >(); if (projs.Count != tokens.Count) { return; } total_word_count += projs.Count - 2; // Для каждого слова получим списки альтернативных лемматизаций. List <List <string> > word2lemmas = new List <List <string> >(); List <List <int> > word2lemma_id = new List <List <int> >(); List <string> lemmas = new List <string>(); int last_word_index = projs.Count - 1; List <List <double> > viterbi_P = new List <List <double> >(); List <List <int> > viterbi_backpointer = new List <List <int> >(); for (int iword = 0; iword < projs.Count; ++iword) { if (iword == 0 || iword == last_word_index) { List <string> w2l = new List <string>(); w2l.Add(string.Empty); word2lemmas.Add(w2l); List <int> w2li = new List <int>(); w2li.Add(MatchSuffix(GetTokenSuffix(0, last_word_index, projs[iword]), false)); word2lemma_id.Add(w2li); } else { List <string> word_lemmas = new List <string>(); List <int> word_lemma_ids = new List <int>(); for (int iproj = 0; iproj < projs[iword].VersionCount(); ++iproj) { string lemma = string.Empty; int ekey = projs[iword].GetVersionEntryID(iproj); string ename = gren.GetEntryName(ekey); if (IsUnknownLexem(ename)) { lemma = projs[iword].GetWord().ToLower(); } else { lemma = ename.ToLower(); } if (!word_lemmas.Contains(lemma)) { word_lemmas.Add(lemma); int id_lemma = MatchSuffix(GetSuffix(lemma), false); if (id_lemma == -1) { throw new System.ApplicationException(); } word_lemma_ids.Add(id_lemma); } } word2lemmas.Add(word_lemmas); word2lemma_id.Add(word_lemma_ids); } lemmas.Add(word2lemmas[iword][0]); List <double> px = new List <double>(); List <int> bx = new List <int>(); for (int i = 0; i < word2lemmas[iword].Count; ++i) { if (iword == 0) { px.Add(1.0); // состояние START } else { px.Add(0.0); // для остальных столбцов пока не знаем } bx.Add(-1); } viterbi_P.Add(px); viterbi_backpointer.Add(bx); } // Для каждого слова получим id_suffix List <int> word_suffices = new List <int>(); for (int iword = 0; iword < projs.Count; ++iword) { string word = projs[iword].GetWord().ToLower(); string suffix = GetTokenSuffix(iword, last_word_index, projs[iword]); int id_suffix = MatchSuffix(suffix, false); if (id_suffix == -1) { continue; } word_suffices.Add(id_suffix); } // расчет по решетке for (int iword = 1; iword < projs.Count - 1; ++iword) { // в этом столбце столько разных состояний int n_states = word2lemmas[iword].Count; // сразу получим теги для контекста int id_suffix1 = word_suffices[iword - 1]; int id_suffix2 = word_suffices[iword]; int id_suffix3 = word_suffices[iword + 1]; string label1 = TagLabel(-1, id_suffix1); string label2 = TagLabel(0, id_suffix2); string label3 = TagLabel(1, id_suffix3); for (int istate = 0; istate < n_states; ++istate) { // для состояния istate получим целевую метку для леммы int id_result_lemma = word2lemma_id[iword][istate]; string result_label = ResultLabel(id_result_lemma); if (!result_label2id.ContainsKey(result_label)) { // переходов в такое состояние не было вообще, будет нулевая верояность continue; } int res_label_index = result_label2id[result_label]; // просматриваем переходы из состояний предыдущего шага int n_prev_states = word2lemmas[iword - 1].Count; double best_p = -1.0; int best_prev_state_index = -1; for (int i_prev_state = 0; i_prev_state < n_prev_states; ++i_prev_state) { int id_prev_lemma = word2lemma_id[iword - 1][i_prev_state]; string prev_lemma_label = LemmaLabel(-1, id_prev_lemma); double P_prev = viterbi_P[iword - 1][i_prev_state]; // запускаем модель для получения достоверности нового состояния System.Collections.ArrayList context = new System.Collections.ArrayList(); context.Add(prev_lemma_label); context.Add(label1); context.Add(label2); context.Add(label3); try { double[] probabilities = mModel.Evaluate((string[])context.ToArray(typeof(string))); double p = probabilities[res_label_index]; double P12 = p * P_prev; // вероятность данного перехода if (P12 > best_p) { best_p = P12; best_prev_state_index = i_prev_state; } } catch (System.Exception ex) { // ... обычно это означает, что встретился ключ, которые не был включен в обучающий набор. // будем считать, что у таких переходов нулевая вероятность.s } } if (n_states == 1) { // если на данном шаге всего 1 состояние, то можем принудительно присвоить ему накопленную достоверность=1 и таким образом // улучшить поведение модели при появлении неизвестных слов, приводящих к обнулению вероятностей. viterbi_P[iword][istate] = 1.0; } else { viterbi_P[iword][istate] = best_p; } viterbi_backpointer[iword][istate] = best_prev_state_index; } } // Для последнего состояния END просто найдем самое достоверное на пред. шаге double best_P1 = 0; int best_state1 = 0; for (int i = 0; i < word2lemmas[last_word_index - 1].Count; ++i) { double p = viterbi_P[last_word_index - 1][i]; if (p > best_P1) { best_P1 = p; best_state1 = i; } } viterbi_P[last_word_index][0] = best_P1; viterbi_backpointer[last_word_index][0] = best_state1; // теперь обратный проход по решетке, через записи в backpointer'ах восстанавливаем самую достоверную цепочку лемм // для последнего шага - всего одно состояние END. int cur_backpointer = viterbi_backpointer[projs.Count - 1][0]; int j = projs.Count - 2; List <string> best_lemmas = new List <string>(); for (int k = 0; k < projs.Count; ++k) { best_lemmas.Add(string.Empty); } while (j > 0) { // для этого шага - такая лучшая лемма string best_lemma = word2lemmas[j][cur_backpointer]; best_lemmas[j] = best_lemma; // определяем лучшее состояние для предыдущего шага int prev_backpointer = viterbi_backpointer[j][cur_backpointer]; cur_backpointer = prev_backpointer; j--; } // Теперь сравниваем леммы c правильными значениями. for (int iword = 1; iword < tokens.Count - 1; ++iword) { string mustbe = string.Empty; int ekey = tokens[iword].GetEntryID(); string ename = gren.GetEntryName(ekey); if (IsUnknownLexem(ename)) // не будем учитывать ошибки лемматизации для не-словарных лексем. { continue; } mustbe = ename.ToLower(); if (mustbe != best_lemmas[iword]) { error_count_with_ngram++; } string lemma0 = string.Empty; int ekey0 = projs[iword].GetEntryID(); string ename0 = gren.GetEntryName(ekey0); if (IsUnknownLexem(ename0)) { continue; } lemma0 = ename0.ToLower(); if (mustbe != lemma0) { error_count_no_filter++; } } } } return; }
/* * public void Check( string line ) * { * // Морфологический разбор * using( SolarixGrammarEngineNET.AnalysisResults tokens = gren.AnalyzeMorphology( line, LanguageID, SolarixGrammarEngineNET.GrammarEngine.SOL_GREN_COMPLETE_ONLY ) ) * { * // Токенизация без использования синтаксических правил * using( SolarixGrammarEngineNET.AnalysisResults projs = gren.AnalyzeMorphology( line, LanguageID, SolarixGrammarEngineNET.GrammarEngine.SOL_GREN_TOKENIZE_ONLY ) ) * { * List<List<int>> word2tags = new List<List<int>>(); * * if( projs.Count != tokens.Count ) * return; * * total_word_count += projs.Count - 2; * * // Для каждого слова получим списки альтернативных лемматизаций. * List<List<string>> word2lemmas = new List<List<string>>(); * * List<string> lemmas = new List<string>(); * * int last_word_index = projs.Count - 1; * * for( int iword = 0; iword < projs.Count; ++iword ) * { * if( iword == 0 || iword == last_word_index ) * { * List<string> w2l = new List<string>(); * w2l.Add( string.Empty ); * word2lemmas.Add( w2l ); * } * else * { * List<string> word_lemmas = new List<string>(); * for( int iproj = 0; iproj < projs[iword].VersionCount(); ++iproj ) * { * string lemma = string.Empty; * int ekey = projs[iword].GetVersionEntryID( iproj ); * string ename = gren.GetEntryName( ekey ); * if( IsUnknownLexem( ename ) ) * lemma = projs[iword].GetWord().ToLower(); * else * lemma = ename.ToLower(); * * if( !word_lemmas.Contains( lemma ) ) * word_lemmas.Add( lemma ); * } * * word2lemmas.Add( word_lemmas ); * } * * lemmas.Add( word2lemmas[iword][0] ); * } * * * for( int iword = 1; iword < projs.Count - 1; ++iword ) * { * string suffix1 = GetTokenSuffix( iword - 1, last_word_index, projs[iword - 1] ); * int id_suffix1 = MatchSuffix( suffix1, false ); * if( id_suffix1 == -1 ) * continue; * * string suffix2 = GetTokenSuffix( iword, last_word_index, projs[iword] ); * int id_suffix2 = MatchSuffix( suffix2, false ); * if( id_suffix2 == -1 ) * continue; * * string suffix3 = GetTokenSuffix( iword + 1, last_word_index, projs[iword + 1] ); * int id_suffix3 = MatchSuffix( suffix3, false ); * if( id_suffix3 == -1 ) * continue; * * string label1 = TagLabel( -1, id_suffix1 ); * string label2 = TagLabel( 0, id_suffix2 ); * string label3 = TagLabel( 1, id_suffix3 ); * * * System.Collections.ArrayList context = new System.Collections.ArrayList(); * context.Add( label1 ); * context.Add( label2 ); * context.Add( label3 ); * * double[] probabilities = mModel.Evaluate( (string[])context.ToArray( typeof( string ) ) ); * * // теперь надо выбрать самый достоверный вариант. * double best_score = 0; * * // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс. * for( int iproj = 0; iproj < word2lemmas[iword].Count; ++iproj ) * { * string ename = word2lemmas[iword][iproj]; * string proj_suffix = GetSuffix( ename.ToLower() ); * int id_suffix = MatchSuffix( proj_suffix, false ); * if( id_suffix == -1 ) * continue; * * string res_label = ResultLabel( id_suffix ); * * if( !result_label2id.ContainsKey( res_label ) ) * continue; * * int res_label_index = result_label2id[res_label]; * * double p = probabilities[res_label_index]; * * if( p > best_score ) * { * best_score = p; * lemmas[iword] = ename.ToLower(); * } * } * } * * * // Теперь сравниваем леммы c правильными значениями. * for( int iword = 1; iword < tokens.Count - 1; ++iword ) * { * string mustbe = string.Empty; * * int ekey = tokens[iword].GetEntryID(); * string ename = gren.GetEntryName( ekey ); * * if( IsUnknownLexem( ename ) ) // не будем учитывать ошибки лемматизации для не-словарных лексем. * continue; * * mustbe = ename.ToLower(); * * if( mustbe != lemmas[iword] ) * error_count_with_ngram++; * * string lemma0 = string.Empty; * int ekey0 = projs[iword].GetEntryID(); * string ename0 = gren.GetEntryName( ekey0 ); * if( IsUnknownLexem( ename0 ) ) * continue; * * lemma0 = ename0.ToLower(); * * if( mustbe != lemma0 ) * error_count_no_filter++; * } * } * } * * return; * } */ public void Check(string line) { // Морфологический разбор using (SolarixGrammarEngineNET.AnalysisResults tokens = gren.AnalyzeMorphology(line, LanguageID, SolarixGrammarEngineNET.GrammarEngine.MorphologyFlags.SOL_GREN_COMPLETE_ONLY)) { total_word_count += tokens.Count - 2; System.Text.StringBuilder b = new System.Text.StringBuilder(); b.Capacity = 100; // Для каждого слова получим списки альтернативных лемматизаций. List <List <string> > word2lemmas = new List <List <string> >(); List <string> lemmas = new List <string>(); List <int> model_lemma_id = new List <int>(); int last_word_index = tokens.Count - 1; for (int iword = 0; iword < tokens.Count; ++iword) { if (iword == 0 || iword == last_word_index) { List <string> w2l = new List <string>(); w2l.Add(string.Empty); word2lemmas.Add(w2l); } else { List <string> word_lemmas = new List <string>(); string word = tokens[iword].GetWord(); System.IntPtr hLemmas = SolarixLemmatizatorEngineNET.LemmatizatorEngine.sol_GetLemmasW(lemm_engine, word); if (hLemmas == System.IntPtr.Zero) { throw new System.ApplicationException(); } int nlemma = SolarixLemmatizatorEngineNET.LemmatizatorEngine.sol_CountLemmas(hLemmas); for (int i = 0; i < nlemma; ++i) { b.Length = 0; SolarixLemmatizatorEngineNET.LemmatizatorEngine.sol_GetLemmaStringW(hLemmas, i, b, b.Capacity); string lemma = b.ToString().ToLower(); if (!word_lemmas.Contains(lemma)) { word_lemmas.Add(lemma); } } SolarixLemmatizatorEngineNET.LemmatizatorEngine.sol_DeleteLemmas(hLemmas); word2lemmas.Add(word_lemmas); } lemmas.Add(word2lemmas[iword][0]); model_lemma_id.Add(0); } for (int iword = 1; iword < tokens.Count - 1; ++iword) { string suffix1 = GetTokenSuffix(iword - 1, last_word_index, tokens[iword - 1]); int id_suffix1 = MatchSuffix(suffix1, false); if (id_suffix1 == -1) { continue; } string suffix2 = GetTokenSuffix(iword, last_word_index, tokens[iword]); int id_suffix2 = MatchSuffix(suffix2, false); if (id_suffix2 == -1) { continue; } string suffix3 = GetTokenSuffix(iword + 1, last_word_index, tokens[iword + 1]); int id_suffix3 = MatchSuffix(suffix3, false); if (id_suffix3 == -1) { continue; } string label1 = TagLabel(-1, id_suffix1); string label2 = TagLabel(0, id_suffix2); string label3 = TagLabel(1, id_suffix3); System.Collections.ArrayList context = new System.Collections.ArrayList(); context.Add(label1); context.Add(label2); context.Add(label3); double[] probabilities = mModel.Evaluate((string[])context.ToArray(typeof(string))); // теперь надо выбрать самый достоверный вариант. double best_score = 0; // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс. for (int iproj = 0; iproj < word2lemmas[iword].Count; ++iproj) { string ename = word2lemmas[iword][iproj]; string proj_suffix = GetSuffix(ename.ToLower()); int id_suffix = MatchSuffix(proj_suffix, false); if (id_suffix == -1) { continue; } string res_label = ResultLabel(id_suffix); if (!result_label2id.ContainsKey(res_label)) { continue; } int res_label_index = result_label2id[res_label]; double p = probabilities[res_label_index]; if (p > best_score) { best_score = p; model_lemma_id[iword] = id_suffix; lemmas[iword] = ename.ToLower(); } } } // Теперь сравниваем леммы c правильными значениями. for (int iword = 1; iword < tokens.Count - 1; ++iword) { string mustbe = string.Empty; int ekey = tokens[iword].GetEntryID(); string ename = gren.GetEntryName(ekey); if (IsUnknownLexem(ename)) // не будем учитывать ошибки лемматизации для не-словарных лексем. { continue; } mustbe = ename.ToLower(); // отдельно считаем все ошибки модели, так как часть из них могут быть // скрыты при выборе леммы в случаях, когда есть только один правильный вариант леммы, и он не совпадает с выбором модели. string mustbe_suffix = GetSuffix(mustbe); int mustbe_id_suffix = MatchSuffix(mustbe_suffix, false); if (mustbe_id_suffix != model_lemma_id[iword]) { raw_model_error_count++; } if (mustbe != lemmas[iword]) { error_count_with_ngram++; } string lemma0 = word2lemmas[iword][0].ToLower(); if (mustbe != lemma0) { error_count_no_filter++; } } } return; }