ネット上であまり見かけないので投稿。
非線形データを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);
}
}
}