/// <summary> /// This is similar logic as standard deviation, but this returns the max distance from the average /// NOTE: Spread is probably the wrong word, since this only returns the max distance (radius instead of diameter) /// </summary> public static double GetTotalSpread(IEnumerable <VectorND> values) { VectorND mean = MathND.GetCenter(values); double distancesSquared = values. Select(o => (o - mean).LengthSquared). OrderByDescending(). First(); return(Math.Sqrt(distancesSquared)); }
/// <summary> /// This version starts with a SOM, then potentially splits the largest node and/or gathers the smallest nodes into a single /// </summary> /// <returns></returns> public static SOMResult Train(ISOMInput[] inputs, SOMRules rules, bool isDisplay2D) { SOMResult result = SelfOrganizingMaps.TrainSOM(inputs, rules, isDisplay2D); if (result.Nodes.Length == 0) { return(result); } else if (result.Nodes.Length == 1) { #region kmeans single node if (inputs.Length < 20) { return(result); } return(SelfOrganizingMaps.TrainKMeans(inputs, 5, true)); #endregion } var categorized = GetSOM_SplitMerge_Categorize(result); List <SOMNode> nodes = new List <SOMNode>(); List <ISOMInput[]> newInputs = new List <ISOMInput[]>(); foreach (NodeCombo set in UtilityCore.Iterate(categorized.kmeans, categorized.keep)) // UtilityCore.Iterate gracefully skips nulls { nodes.Add(set.Node); newInputs.Add(set.Inputs); } if (categorized.remaining != null) { nodes.Add(new SOMNode() { Position = MathND.GetCenter(categorized.remaining.Select(o => o.Node.Position)), Weights = MathND.GetCenter(categorized.remaining.Select(o => o.Node.Weights)), }); newInputs.Add(categorized.remaining. SelectMany(o => o.Inputs). ToArray()); } return(new SOMResult(nodes.ToArray(), newInputs.ToArray(), false)); }
private static void AdjustKMeansCenters(SOMNode[] nodes, ISOMInput[][] inputsByNode) { if (nodes.Length != inputsByNode.Length) { throw new ArgumentException("Arrays must be the same size"); } for (int cntr = 0; cntr < nodes.Length; cntr++) { if (inputsByNode[cntr].Length == 0) { // This happened when there were a bunch of identical images. Otherwise, it should never happen //throw new ArgumentException("Must have inputs for every node"); continue; } nodes[cntr].Weights = MathND.GetCenter(inputsByNode[cntr].Select(o => o.Weights)); } }