Created
March 4, 2014 16:26
-
-
Save adrianseeley/9349785 to your computer and use it in GitHub Desktop.
GATO.WEIGHTED GENETIC FOLDER (C#) - IRIS -> 0 ERRORS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.IO; | |
namespace GATO.WGF | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
List<TrainingCase> TrainingCases = new List<TrainingCase>(); | |
using (FileStream FS = File.OpenRead("iris.data")) | |
{ | |
using (StreamReader SR = new StreamReader(FS)) | |
{ | |
while (!SR.EndOfStream) | |
{ | |
String Line = SR.ReadLine(); | |
String[] Parts = Line.Split(','); | |
List<double> Inputs = new List<double>(); | |
for (int p = 0; p < Parts.Length - 1; p++) | |
{ | |
Inputs.Add(Double.Parse(Parts[p])); | |
} | |
TrainingCases.Add(new TrainingCase(Inputs.ToArray(), Parts[Parts.Length - 1])); | |
} | |
} | |
} | |
WeightedGeneticFolder WGF = new WeightedGeneticFolder(NumberOfInputs: 4); | |
WGF.Train( | |
TrainingCases, | |
ErrorThreshold: 0, | |
FitnessThreshold: 2, // class count - 1 | |
IterationThreshold: 100000, | |
MaximumHalfPopulation: 10, | |
AddGeneticFoldRate: 0.50 | |
); | |
Console.WriteLine("Final Fitness: " + WGF.OptimalConfiguration.Fitness); | |
Console.WriteLine("Total Errors: " + WGF.OptimalConfiguration.Test(TrainingCases)); | |
Console.ReadLine(); | |
} | |
} | |
class WeightedGeneticFolder | |
{ | |
public int NumberOfNearestNeighbours; | |
public WeightedGeneticFolderConfiguration OptimalConfiguration; | |
public WeightedGeneticFolder(int NumberOfInputs) | |
{ | |
OptimalConfiguration = new WeightedGeneticFolderConfiguration(NumberOfInputs); | |
} | |
public void Train (List<TrainingCase> TrainingCases, double ErrorThreshold, double FitnessThreshold, int IterationThreshold, int MaximumHalfPopulation, double NerfRate = 1.01, double WeightPointMutationRate = 0.05, double WeightPointMutationAmount = 0.05, double AddGeneticFoldRate = 0.10, double RemovePointGeneticFoldRate = 0.05, double GeneticFoldPointMutationRate = 0.05, double GeneticFoldPointMutationAmount = 0.05) | |
{ | |
OptimalConfiguration.BuildNeighbourhood(TrainingCases); | |
OptimalConfiguration.AssesFitness(TrainingCases); | |
OptimalConfiguration.Nerf = 1.0; | |
List<WeightedGeneticFolderConfiguration> Population = new List<WeightedGeneticFolderConfiguration>() { OptimalConfiguration }; | |
for (int Iteration = 0; Iteration < IterationThreshold && Population[0].Errors > ErrorThreshold && Population[0].Fitness > FitnessThreshold; Iteration++) | |
{ | |
StringBuilder sb = new StringBuilder(); | |
sb.Append("Iteration: " + Iteration + " Errors: " + Population[0].Errors + " Fit: " + Population[0].Fitness + " Nerf: " + Population[0].Nerf.ToString("N4") + " G: " + Population[0].GeneticFolds.Count + " W: "); | |
for (int w = 0; w < Population[0].Weights.Length; w++) | |
{ | |
sb.Append(Population[0].Weights[w].ToString("N4") + (w != Population[0].Weights.Length - 1 ? ", " : "")); | |
} | |
/*for (int g = 0; g < Population[0].GeneticFolds.Count; g++) | |
{ | |
sb.Append(Population[0].GeneticFolds[g] + (g != Population[0].GeneticFolds.Count - 1 ? ", " : "")); | |
}*/ | |
Console.WriteLine(sb); | |
for (int PopulationIterator = Population.Count - 1; PopulationIterator >= 0; PopulationIterator--) | |
{ | |
WeightedGeneticFolderConfiguration Mutant = Population[PopulationIterator].Clone().Mutate(WeightPointMutationRate, WeightPointMutationAmount, AddGeneticFoldRate, RemovePointGeneticFoldRate, GeneticFoldPointMutationRate, GeneticFoldPointMutationAmount); | |
Mutant.BuildNeighbourhood(TrainingCases); | |
Mutant.AssesFitness(TrainingCases); | |
Mutant.Nerf = 1.0; | |
if (Mutant.Errors >= Population[PopulationIterator].Errors || Mutant.Fitness >= Population[PopulationIterator].Fitness) | |
{ | |
Population[PopulationIterator].Nerf *= NerfRate; | |
} | |
Population.Add(Mutant); | |
} | |
Population.Sort((a, b) => | |
{ | |
int ret; | |
ret = a.Errors.CompareTo(b.Errors); | |
if (ret != 0) return ret; | |
ret = (a.Fitness * a.Nerf).CompareTo(b.Fitness * b.Nerf); | |
if (ret != 0) return ret; | |
return a.GeneticFolds.Count.CompareTo(b.GeneticFolds.Count); | |
}); | |
if (Population.Count > MaximumHalfPopulation) | |
{ | |
Population.RemoveRange(MaximumHalfPopulation, Population.Count - MaximumHalfPopulation); | |
} | |
} | |
Population.Sort((a, b) => | |
{ | |
int ret; | |
ret = a.Errors.CompareTo(b.Errors); | |
if (ret != 0) return ret; | |
ret = (a.Fitness).CompareTo(b.Fitness); | |
if (ret != 0) return ret; | |
return a.GeneticFolds.Count.CompareTo(b.GeneticFolds.Count); | |
}); | |
OptimalConfiguration = Population[0]; | |
} | |
} | |
class WeightedGeneticFolderConfiguration | |
{ | |
public static Random R = new Random(); | |
public double[] Weights; | |
public List<double> GeneticFolds; | |
public List<KeyValuePair<String, double>> Neighbourhood; | |
public int Errors; | |
public double Fitness; | |
public double Nerf; | |
public WeightedGeneticFolderConfiguration(int NumberOfInputs) | |
{ | |
Weights = new double[NumberOfInputs]; | |
for (int w = 0; w < Weights.Length; w++) | |
{ | |
Weights[w] = 1; | |
} | |
GeneticFolds = new List<double>(); | |
Neighbourhood = new List<KeyValuePair<string, double>>(); | |
} | |
public WeightedGeneticFolderConfiguration Clone() | |
{ | |
WeightedGeneticFolderConfiguration WGFC = new WeightedGeneticFolderConfiguration(Weights.Length); | |
Weights.CopyTo(WGFC.Weights, 0); | |
WGFC.GeneticFolds.AddRange(GeneticFolds.GetRange(0, GeneticFolds.Count)); | |
WGFC.Neighbourhood.AddRange(Neighbourhood.GetRange(0, Neighbourhood.Count)); | |
WGFC.Fitness = Fitness; | |
WGFC.Nerf = Nerf; | |
return WGFC; | |
} | |
public WeightedGeneticFolderConfiguration Mutate(double WeightPointMutationRate, double WeightPointMutationAmount, double AddGeneticFoldRate, double RemovePointGeneticFoldRate, double GeneticFoldPointMutationRate, double GeneticFoldPointMutationAmount) | |
{ | |
for (int w = 0; w < Weights.Length; w++) | |
{ | |
if (R.NextDouble() < WeightPointMutationRate) | |
{ | |
Weights[w] += R.NextDouble() * ((Weights[w] * WeightPointMutationAmount) - (Weights[w] * -WeightPointMutationAmount)) + (Weights[w] * -WeightPointMutationAmount); | |
} | |
} | |
while (R.NextDouble() < AddGeneticFoldRate) | |
{ | |
GeneticFolds.Add(Neighbourhood[R.Next(0, Neighbourhood.Count)].Value); | |
} | |
for (int g = GeneticFolds.Count - 1; g >= 0; g--) | |
{ | |
if (R.NextDouble() < RemovePointGeneticFoldRate) | |
{ | |
GeneticFolds.RemoveAt(g); | |
continue; | |
} | |
if (R.NextDouble() < GeneticFoldPointMutationRate) | |
{ | |
GeneticFolds[g] += R.NextDouble() * ((GeneticFolds[g] * GeneticFoldPointMutationAmount) - (GeneticFolds[g] * -GeneticFoldPointMutationAmount)) + (GeneticFolds[g] * -GeneticFoldPointMutationAmount); | |
} | |
} | |
return this; | |
} | |
public void BuildNeighbourhood (List<TrainingCase> TrainingCases) | |
{ | |
Neighbourhood = new List<KeyValuePair<string, double>>(); | |
for (int t = 0; t < TrainingCases.Count; t++) | |
{ | |
Neighbourhood.Add(new KeyValuePair<String, double>(TrainingCases[t].Class, Express(TrainingCases[t].Inputs))); | |
} | |
} | |
public double Express(double[] Inputs) | |
{ | |
double OutputSum = 0; | |
for (int i = 0; i < Inputs.Length; i++) | |
{ | |
OutputSum += Inputs[i] * Weights[i]; | |
} | |
for (int g = 0; g < GeneticFolds.Count; g++) | |
{ | |
OutputSum = Fold(GeneticFolds[g], OutputSum); | |
} | |
return OutputSum; | |
} | |
private double Fold(double GeneticFold, double OutputSum) | |
{ | |
if (OutputSum > GeneticFold) return GeneticFold - (OutputSum - GeneticFold); | |
else return OutputSum; | |
} | |
public void AssesFitness(List<TrainingCase> TrainingCases) | |
{ | |
Neighbourhood.Sort((a, b) => | |
{ | |
return a.Value.CompareTo(b.Value); | |
}); | |
int Faults = 0; | |
String LastClass = Neighbourhood[0].Key; | |
for (int n = 1; n < Neighbourhood.Count; n++) | |
{ | |
if (Neighbourhood[n].Key != LastClass) | |
{ | |
LastClass = Neighbourhood[n].Key; | |
Faults++; | |
} | |
} | |
Fitness = Faults; | |
Errors = Test(TrainingCases); | |
} | |
public String Classify (double[] Inputs, int KNearestNeighbours) | |
{ | |
return KNearestNeighbour(Express(Inputs), KNearestNeighbours); | |
} | |
public String KNearestNeighbour(double OutputSum, int KNearestNeighbours) | |
{ | |
List<KeyValuePair<String, double>> NeighbourDistances = new List<KeyValuePair<string, double>>(); | |
for (int n = 0; n < Neighbourhood.Count; n++) | |
{ | |
NeighbourDistances.Add(new KeyValuePair<String, double> (Neighbourhood[n].Key, Math.Abs(Neighbourhood[n].Value - OutputSum))); | |
} | |
NeighbourDistances.Sort((a, b) => | |
{ | |
return a.Value.CompareTo(b.Value); | |
}); | |
Dictionary<String, int> NearestNeighbours = new Dictionary<string, int>(); | |
for (int n = 0; n < NeighbourDistances.Count && n < KNearestNeighbours; n++) | |
{ | |
if (!NearestNeighbours.ContainsKey(NeighbourDistances[n].Key)) | |
{ | |
NearestNeighbours.Add(NeighbourDistances[n].Key, 0); | |
} | |
NearestNeighbours[NeighbourDistances[n].Key]++; | |
} | |
List<KeyValuePair<String, int>> NearestNeighboursList = NearestNeighbours.ToList(); | |
NearestNeighboursList.Sort((a, b) => | |
{ | |
return a.Value.CompareTo(b.Value); | |
}); | |
return NearestNeighboursList[0].Key; | |
} | |
public int Test(List<TrainingCase> TrainingCases) | |
{ | |
int Errors = 0; | |
for (int t = 0; t < TrainingCases.Count; t++) | |
{ | |
if (TrainingCases[t].Class != Classify(TrainingCases[t].Inputs, 3)) | |
{ | |
Errors++; | |
} | |
} | |
return Errors; | |
} | |
} | |
class TrainingCase | |
{ | |
public double[] Inputs; | |
public String Class; | |
public TrainingCase(double[] Inputs, String Class) | |
{ | |
this.Inputs = Inputs; | |
this.Class = Class; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment