非線形データを1次元のデータ配列にした後、データ同士がどれくらい一致しているかを判定するプログラムです。
いわゆるパターンマッチング手法といっていいと思われます。
画像処理で用いる場合はデータを分割して各要素の偏差値を求め、
その偏差値のデータ列を下記プログラムに入れるとデータがどれくらい一致しているか計算できるようになります。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { var collection = new Collection() { new Model(new double[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, 4), new Model(new double[] { 2, 2, 4, 4, 5, 6, 7, 8, 9, 11, 11, 12, 13, 14, 15, 10 }, 4), new Model(new double[] { 1, 12, 3, 14, 5, 26, 57, 18, 9, 40, 11, 22, 13, 14, 15, 11 }, 4), new Model(new double[] { 4, 12, 3, 4, 35, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, 4), new Model(new double[] { 5, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 13, 11 }, 4), new Model(new double[] { 2, 33, 3, 45, 5, 16, 7, 8, 19, 10, 11, 125, 13, 14, 15, 16 }, 4), }; var ret = collection.Filter(2); var testData = new Model(new double[] { 1, 12, 3, 4, 25, 6, 7, 8, 49, 10, 11, 12, 43, 14, 15, 16 }, 4); Console.WriteLine("Matching={0}", collection.Matching(testData)); Console.ReadKey(); } } public class Collection : List<Model> { public Collection Filter(double sigma) { var result = new Collection(); var length = this[0].Patterns.Length; var list = new List<Model>(); list.AddRange(this); for (var stage = 0; stage < length; stage++) { var data = list.Select(_ => _.Patterns[stage]).ToArray(); var ave = data.Average(); var sig = data.Sigma() * sigma; list = list.Where(_ => sig >= Math.Abs(_.Patterns[stage] - ave)).ToList(); } result.AddRange(list); return result; } public double Matching(Model model) { return this.Select(_ => _.Matching(model)).ToArray().Max(); } } public class Model { public double[] Data { get; } public double[] Patterns { get; } public int Count => Patterns.Length; /// <summary> /// /// </summary> /// <param name="data"></param> public Model(double[] data, int split_count) { Data = data; var len = data.Length; var spt = (len / split_count); Patterns = new double[split_count]; for (var idx = 0; idx < split_count; idx++) { Patterns[idx] = data.ToList().GetRange(idx * spt, spt).ToArray().Sigma(); } } /// <summary> /// コサイン類似度 /// </summary> /// <param name="model"></param> /// <returns></returns> public double Matching(Model model) { var sum = 0.0; var v1 = 0.0; var v2 = 0.0; for (var stage = 0; stage < Count; stage++) { var val1 = Patterns[stage]; var val2 = model.Patterns[stage]; sum += val1 * val2; v1 += Math.Pow(val1, 2); v2 += Math.Pow(val2, 2); } v1 = Math.Sqrt(v1); v2 = Math.Sqrt(v2); var result = sum / (v1 * v2); return result; } } public static class DoubleExtensions { public static double Sigma(this double[] self) { var len = self.Length; var ave = self.Average(); var bun = 0.0; foreach (var dat in self) { bun += Math.Pow(dat - ave, 2); } bun = bun / len; return Math.Sqrt(bun); } } }
0 件のコメント:
コメントを投稿