BotSharp/BotSharp.NLP/Tag/NGramTagger.cs

113 lines
3.4 KiB
C#
Raw Normal View History

2018-08-16 22:27:50 +00:00
using System;
using System.Collections.Generic;
2018-08-17 20:49:29 +00:00
using System.Linq;
2018-08-16 22:27:50 +00:00
using System.Text;
using BotSharp.NLP.Tokenize;
namespace BotSharp.NLP.Tag
{
/// <summary>
/// N-Gramm taggers are based on a simple statistical algorithm:
/// for each token, assign the tag that is most likely for that particular token.
/// </summary>
public class NGramTagger : ITagger
{
2018-08-17 22:22:05 +00:00
private List<NGramFreq> _contextMapping { get; set; }
2018-08-16 22:27:50 +00:00
public void Tag(Sentence sentence, TagOptions options)
{
2018-08-17 20:49:29 +00:00
// need training to generate model
2018-08-17 22:22:05 +00:00
if(_contextMapping == null)
2018-08-17 20:49:29 +00:00
{
2018-08-17 22:22:05 +00:00
Train(options.Corpus, options);
}
2018-08-18 05:44:18 +00:00
Fill(sentence, options);
for (int pos = options.NGram - 1; pos < sentence.Words.Count; pos++)
{
sentence.Words[pos].Pos = _contextMapping.FirstOrDefault(x => x.Context == GetContext(pos, sentence.Words, options))?.Tag;
// set default tag
if(sentence.Words[pos].Pos == null)
{
sentence.Words[pos].Pos = options.Tag;
}
}
for(int pos = 0; pos < options.NGram - 1; pos++)
{
sentence.Words.RemoveAt(0);
}
2018-08-17 22:22:05 +00:00
}
public void Train(List<Sentence> sentences, TagOptions options)
{
2018-08-18 05:44:18 +00:00
var cache = new List<NGramFreq>();
2018-08-17 20:49:29 +00:00
2018-08-17 22:22:05 +00:00
for (int idx = 0; idx < options.Corpus.Count; idx++)
{
var sent = options.Corpus[idx];
2018-08-17 20:49:29 +00:00
2018-08-18 05:44:18 +00:00
Fill(sent, options);
2018-08-17 20:49:29 +00:00
2018-08-18 05:44:18 +00:00
for (int pos = options.NGram - 1; pos < sent.Words.Count; pos++)
2018-08-17 22:22:05 +00:00
{
var freq = new NGramFreq
2018-08-17 20:49:29 +00:00
{
2018-08-18 05:44:18 +00:00
Context = GetContext(pos, sent.Words, options),
Tag = sent.Words[pos].Pos,
Count = 1
2018-08-17 22:22:05 +00:00
};
2018-08-17 20:49:29 +00:00
2018-08-18 05:44:18 +00:00
cache.Add(freq);
2018-08-17 22:22:05 +00:00
}
2018-08-17 20:49:29 +00:00
}
2018-08-16 22:27:50 +00:00
2018-08-18 05:44:18 +00:00
_contextMapping = (from c in cache
group c by new { c.Context, c.Tag } into g
select new NGramFreq
{
Context = g.Key.Context,
Tag = g.Key.Tag,
Count = g.Count()
}).OrderByDescending(x => x.Count)
.ToList();
}
private string GetContext(int pos, List<Token> words, TagOptions options)
{
string context = words[pos].Text;
for (int ngram = options.NGram - 1; ngram > 0; ngram--)
{
context = words[pos - ngram].Pos + " " + context;
}
return context;
}
private void Fill(Sentence sent, TagOptions options)
{
for (int ngram = 1; ngram < options.NGram; ngram++)
{
sent.Words.Insert(0, new Token { Text = "NIL", Pos = options.Tag, Start = (ngram - 1) * 3 });
}
2018-08-16 22:27:50 +00:00
}
2018-08-17 20:49:29 +00:00
private class NGramFreq
{
2018-08-17 22:22:05 +00:00
/// <summary>
/// Current token tag
/// </summary>
2018-08-18 05:44:18 +00:00
public string Tag { get; set; }
2018-08-17 22:22:05 +00:00
/// <summary>
/// Occurence frequency
/// </summary>
public int Count { get; set; }
2018-08-18 05:44:18 +00:00
public string Context { get; set; }
2018-08-17 20:49:29 +00:00
}
2018-08-16 22:27:50 +00:00
}
}