using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; namespace BotSharp.MachineLearning.CRFsuite { public class Crfutils { /// /// Generate features for an item sequence by applying feature templates. /// A feature template consists of a tuple of (name, offset) pairs, /// where name and offset specify a field name and offset from which /// the template extracts a feature valreaditerue. Generated features are stored /// in the 'F' field of each item in the sequence. /// /// Token features for a sentence /// the template which contains what feature to extract public void ApplyTemplates (List> X, Template templates) { foreach (List template in templates.Features) { List list = new List(); template.ForEach(t => list.Add($"{t.Field}[{t.Offset}]")); string name = string.Join("|", list); for (int t = 0 ; t < X.Count() ; t++) { List values = new List(); foreach (CRFFeature crffeature in template) { string field = crffeature.Field; int offset = crffeature.Offset; int p = t + offset; if (p < 0 || p >= X.Count) { values.Clear(); break; } values.Add(X[p][field].ToString()); } if (values != null && values.Count > 0) { string value = string.Join("|", values); ((List)X[t]["F"]).Add($"{name}={value}"); } } } } /// /// Return an iterator for item sequences read from a file object. /// This function reads a sequence from a file object L{fi}, and /// yields the sequence as a list of mapping objects. Each line /// (item) from the file object is split by the separator character /// L{sep}. Separated values of the item are named by L{names}, /// and stored in a mapping object. Every item has a field 'F' that /// is reserved for storing features. /// /// source file which contains crf style training data /// each attribute name in fields /// seperate by public List>> Readiter (string fiPath, List names, string sep = " ") { List>> Xs = new List>>(); List> X = new List>(); using (StreamReader sr = new StreamReader(fiPath, Encoding.Default)) { string line; while ((line = sr.ReadLine()) != null) { line = line.Replace("\n", ""); if (line == null || line.Length == 0) { Xs.Add(new List>(X)); X.Clear(); } else { String[] fields = line.Split(sep); if (fields.Count() < names.Count) { // Error Exception } Dictionary item = new Dictionary(); item.Add("F", new List()); for (int i = 0; i < names.Count; i++) { item.Add(names[i], fields[i]); } X.Add(item); } } } return Xs; } /// /// Escape colon characters from feature names. /// /// a feature name public string Escape(string src) { return src.Replace(":", "__COLON__"); } /// /// Output features (and reference labels) of a sequence in CRFSuite /// format. For each item in the sequence, this function writes a /// reference label (if L{field} is a non-empty string) and features. /// /// destination file stream writer /// Token features for a sentence /// one attribute name in fields public void OutputFeatures (StreamWriter sw, List> X, string field = "") { for (int t = 0; t < X.Count; t++) { if (field.Length != 0) { sw.Write(X[t][field]); } foreach (string a in (List)X[t]["F"]) { sw.Write($"\t{Escape(a)}"); } sw.Write("\n"); } sw.Write("\n"); } /// /// CRFFileGenerator /// /// an extractor which to do the feature extracting work /// attributes name seperated by space /// string whihch seperated by public void CRFFileGenerator(System.Action>> FeatureExtractor, string fields, string rawFile, string parsedName, string sep = " ") { using (FileStream fs = new FileStream(parsedName, FileMode.Create)) { using (StreamWriter sw = new StreamWriter(fs)) { List F = fields.Split(" ").ToList(); List>> Xs = Readiter(rawFile, F, " "); foreach (List> X in Xs) { if (X.Any(x => x["w"].ToString() == "")) { } FeatureExtractor(X); OutputFeatures(sw, X, "y"); } sw.Flush(); } } } } }