Skip to content

Instantly share code, notes, and snippets.

@adrianseeley
Last active August 29, 2015 13:56
Show Gist options
  • Save adrianseeley/9332610 to your computer and use it in GitHub Desktop.
Save adrianseeley/9332610 to your computer and use it in GitHub Desktop.
GATO - WEIGHTED GENETIC FOLDER
//<html><script>
function weighted_genetic_folder (number_of_inputs, number_of_nearest_neighbours) {
var identity_weights = [];
for (var i = 0; i < number_of_inputs; i++)
identity_weights.push(1);
var ret = {
number_of_nearest_neighbours: number_of_nearest_neighbours,
weights: identity_weights,
genetic_folds: [],
neighbourhood: [],
fitness: null,
fitness: function (training_list, weights, genetic_folds, neighbourhood) {
var errors = 0;
for (var t = 0; t < training_list.length; t++)
if (ret.classify(training_list[t].inputs, weights, genetic_folds, neighbourhood) != training_list[t].class)
errors++;
return errors;
},
clone: function (populus) {
return JSON.parse(JSON.stringify(populus));
},
mutate: function (populus, weight_point_mutation_rate, weight_point_mutation_amount, add_genetic_fold_rate, remove_point_genetic_fold_rate, genetic_fold_point_mutation_rate, genetic_fold_point_mutation_amount) {
for (var w = 0; w < populus.weights.length; w++)
if (Math.random() < weight_point_mutation_rate)
populus.weights[w] += Math.random() * ((populus.weights[w] * weight_point_mutation_amount) - (populus.weights[w] * -weight_point_mutation_amount)) + (populus.weights[w] * -weight_point_mutation_amount);
if (Math.random() < add_genetic_fold_rate)
populus.genetic_folds.push(populus.neighbourhood[Math.floor(Math.random() * populus.neighbourhood.length)].value);
for (var g = populus.genetic_folds.length - 1; g >= 0; g--) {
if (Math.random() < remove_point_genetic_fold_rate) {
populus.genetic_folds.splice(g, 1);
continue;
}
if (Math.random() < genetic_fold_point_mutation_rate)
populus.genetic_folds[g].fold_point += Math.random() * ((populus.genetic_folds[g].fold_point * genetic_fold_point_mutation_amount) - (populus.genetic_folds[g].fold_point * -genetic_fold_point_mutation_amount)) + (populus.genetic_folds[g].fold_point * -genetic_fold_point_mutation_amount);
}
return populus;
},
fold: function (fold_point, output_sum) {
if (output_sum > fold_point) return fold_point - (output_sum - fold_point);
return output_sum;
},
train: function (training_list, training_list_error_threshold, iteration_threshold, maximum_population, nerf_rate, weight_point_mutation_rate, weight_point_mutation_amount, add_genetic_fold_rate, remove_point_genetic_fold_rate, genetic_fold_point_mutation_rate, genetic_fold_point_mutation_amount) {
var population = [{weights: ret.weights, genetic_folds: ret.genetic_folds, neighbourhood: ret.build_neighbourhood(training_list, ret.weights, ret.genetic_folds)}];
population[0].fitness = ret.fitness(training_list, population[0].weights, population[0].genetic_folds, population[0].neighbourhood);
population[0].nerf = 1.0;
for (var i = 0; i < iteration_threshold && population[0].fitness > training_list_error_threshold; i++) {
//trace
for (var p = 0; p < population.length && p < 20; p++)
console.log('iter: ' + i, 'fit: ' + population[p].fitness, 'nerf: ' + population[p].nerf, 'folds: ' + population[p].genetic_folds.length, 'weights: ' + population[p].weights.join(', '));
console.log();
//trace
for (var p = population.length - 1; p >= 0; p--) {
population.push(ret.mutate(ret.clone(population[p]), weight_point_mutation_rate, weight_point_mutation_amount, add_genetic_fold_rate, remove_point_genetic_fold_rate, genetic_fold_point_mutation_rate, genetic_fold_point_mutation_amount));
population[population.length - 1].neighbourhood = ret.build_neighbourhood(training_list, population[population.length - 1].weights, population[population.length - 1].genetic_folds);
population[population.length - 1].fitness = ret.fitness(training_list, population[p].weights, population[p].genetic_folds, population[p].neighbourhood);
population[population.length - 1].nerf = 1.0;
if (population[p].fitness <= population[population.length - 1].fitness)
population[p].nerf *= nerf_rate;
}
population.sort(function (a, b) { return (a.fitness * a.nerf) - (b.fitness * b.nerf) || a.genetic_folds.length - b.genetic_folds.length; });
while (population.length > maximum_population)
population.pop();
}
ret.weights = population[0].weights;
ret.genetic_folds = population[0].genetic_folds;
ret.neighbourhood = population[0].neighbourhood;
ret.fitness = population[0].fitness;
},
build_neighbourhood: function (training_list, weights, genetic_folds) {
var neighbourhood = [];
for (var t = 0; t < training_list.length; t++)
neighbourhood.push({class: training_list[t].class, value: ret.express(training_list[t].inputs, weights, genetic_folds)});
return neighbourhood;
},
express: function (inputs, weights, genetic_folds) {
if (!weights) weights = ret.weights;
if (!genetic_folds) genetic_folds = ret.genetic_folds;
var weighted_inputs = [];
for (var i = 0; i < inputs.length; i++)
weighted_inputs.push(inputs[i] * weights[i]);
var output_sum = 0;
for (var w = 0; w < weighted_inputs.length; w++)
output_sum += weighted_inputs[w];
for (var g = 0; g < genetic_folds.length; g++)
output_sum = ret.fold(genetic_folds[g], output_sum);
return output_sum;
},
knearestneighbour: function (output_sum, neighbourhood) {
if (!neighbourhood) neighbourhood = ret.neighbourhood;
var neighbour_distances = [];
for (var n = 0; n < neighbourhood.length; n++)
neighbour_distances.push({class: neighbourhood[n].class, distance: Math.abs(neighbourhood[n].value - output_sum)});
neighbour_distances.sort(function (a, b) { return a.distance - b.distance; });
var nearest_neighbours = {};
for (var n = 0; n < neighbour_distances.length && n < ret.number_of_nearest_neighbours; n++) {
if (!nearest_neighbours.hasOwnProperty(neighbour_distances[n].class))
nearest_neighbours[neighbour_distances[n].class] = 0;
nearest_neighbours[neighbour_distances[n].class]++;
}
var most_voted_class = null;
var most_votes = null;
for (var n in nearest_neighbours)
if (most_votes == null || nearest_neighbours[n] > most_votes) {
most_voted_class = n;
most_votes = nearest_neighbours[n];
}
return most_voted_class;
},
classify: function (inputs, weights, genetic_folds, neighbourhood) {
return ret.knearestneighbour(ret.express(inputs, weights, genetic_folds), neighbourhood);
}
};
return ret;
};
var test_list = [{inputs: [5.1,3.5,1.4,0.2], class: 'Iris-setosa'},
{inputs: [4.9,3.0,1.4,0.2], class: 'Iris-setosa'},
{inputs: [4.7,3.2,1.3,0.2], class: 'Iris-setosa'},
{inputs: [4.6,3.1,1.5,0.2], class: 'Iris-setosa'},
{inputs: [5.0,3.6,1.4,0.2], class: 'Iris-setosa'},
{inputs: [5.4,3.9,1.7,0.4], class: 'Iris-setosa'},
{inputs: [4.6,3.4,1.4,0.3], class: 'Iris-setosa'},
{inputs: [5.0,3.4,1.5,0.2], class: 'Iris-setosa'},
{inputs: [4.4,2.9,1.4,0.2], class: 'Iris-setosa'},
{inputs: [4.9,3.1,1.5,0.1], class: 'Iris-setosa'},
{inputs: [5.4,3.7,1.5,0.2], class: 'Iris-setosa'},
{inputs: [4.8,3.4,1.6,0.2], class: 'Iris-setosa'},
{inputs: [4.8,3.0,1.4,0.1], class: 'Iris-setosa'},
{inputs: [4.3,3.0,1.1,0.1], class: 'Iris-setosa'},
{inputs: [5.8,4.0,1.2,0.2], class: 'Iris-setosa'},
{inputs: [5.7,4.4,1.5,0.4], class: 'Iris-setosa'},
{inputs: [5.4,3.9,1.3,0.4], class: 'Iris-setosa'},
{inputs: [5.1,3.5,1.4,0.3], class: 'Iris-setosa'},
{inputs: [5.7,3.8,1.7,0.3], class: 'Iris-setosa'},
{inputs: [5.1,3.8,1.5,0.3], class: 'Iris-setosa'},
{inputs: [5.4,3.4,1.7,0.2], class: 'Iris-setosa'},
{inputs: [5.1,3.7,1.5,0.4], class: 'Iris-setosa'},
{inputs: [4.6,3.6,1.0,0.2], class: 'Iris-setosa'},
{inputs: [5.1,3.3,1.7,0.5], class: 'Iris-setosa'},
{inputs: [4.8,3.4,1.9,0.2], class: 'Iris-setosa'},
{inputs: [5.0,3.0,1.6,0.2], class: 'Iris-setosa'},
{inputs: [5.0,3.4,1.6,0.4], class: 'Iris-setosa'},
{inputs: [5.2,3.5,1.5,0.2], class: 'Iris-setosa'},
{inputs: [5.2,3.4,1.4,0.2], class: 'Iris-setosa'},
{inputs: [4.7,3.2,1.6,0.2], class: 'Iris-setosa'},
{inputs: [4.8,3.1,1.6,0.2], class: 'Iris-setosa'},
{inputs: [5.4,3.4,1.5,0.4], class: 'Iris-setosa'},
{inputs: [5.2,4.1,1.5,0.1], class: 'Iris-setosa'},
{inputs: [5.5,4.2,1.4,0.2], class: 'Iris-setosa'},
{inputs: [4.9,3.1,1.5,0.1], class: 'Iris-setosa'},
{inputs: [5.0,3.2,1.2,0.2], class: 'Iris-setosa'},
{inputs: [5.5,3.5,1.3,0.2], class: 'Iris-setosa'},
{inputs: [4.9,3.1,1.5,0.1], class: 'Iris-setosa'},
{inputs: [4.4,3.0,1.3,0.2], class: 'Iris-setosa'},
{inputs: [5.1,3.4,1.5,0.2], class: 'Iris-setosa'},
{inputs: [5.0,3.5,1.3,0.3], class: 'Iris-setosa'},
{inputs: [4.5,2.3,1.3,0.3], class: 'Iris-setosa'},
{inputs: [4.4,3.2,1.3,0.2], class: 'Iris-setosa'},
{inputs: [5.0,3.5,1.6,0.6], class: 'Iris-setosa'},
{inputs: [5.1,3.8,1.9,0.4], class: 'Iris-setosa'},
{inputs: [4.8,3.0,1.4,0.3], class: 'Iris-setosa'},
{inputs: [5.1,3.8,1.6,0.2], class: 'Iris-setosa'},
{inputs: [4.6,3.2,1.4,0.2], class: 'Iris-setosa'},
{inputs: [5.3,3.7,1.5,0.2], class: 'Iris-setosa'},
{inputs: [5.0,3.3,1.4,0.2], class: 'Iris-setosa'},
{inputs: [7.0,3.2,4.7,1.4], class: 'Iris-versicolor'},
{inputs: [6.4,3.2,4.5,1.5], class: 'Iris-versicolor'},
{inputs: [6.9,3.1,4.9,1.5], class: 'Iris-versicolor'},
{inputs: [5.5,2.3,4.0,1.3], class: 'Iris-versicolor'},
{inputs: [6.5,2.8,4.6,1.5], class: 'Iris-versicolor'},
{inputs: [5.7,2.8,4.5,1.3], class: 'Iris-versicolor'},
{inputs: [6.3,3.3,4.7,1.6], class: 'Iris-versicolor'},
{inputs: [4.9,2.4,3.3,1.0], class: 'Iris-versicolor'},
{inputs: [6.6,2.9,4.6,1.3], class: 'Iris-versicolor'},
{inputs: [5.2,2.7,3.9,1.4], class: 'Iris-versicolor'},
{inputs: [5.0,2.0,3.5,1.0], class: 'Iris-versicolor'},
{inputs: [5.9,3.0,4.2,1.5], class: 'Iris-versicolor'},
{inputs: [6.0,2.2,4.0,1.0], class: 'Iris-versicolor'},
{inputs: [6.1,2.9,4.7,1.4], class: 'Iris-versicolor'},
{inputs: [5.6,2.9,3.6,1.3], class: 'Iris-versicolor'},
{inputs: [6.7,3.1,4.4,1.4], class: 'Iris-versicolor'},
{inputs: [5.6,3.0,4.5,1.5], class: 'Iris-versicolor'},
{inputs: [5.8,2.7,4.1,1.0], class: 'Iris-versicolor'},
{inputs: [6.2,2.2,4.5,1.5], class: 'Iris-versicolor'},
{inputs: [5.6,2.5,3.9,1.1], class: 'Iris-versicolor'},
{inputs: [5.9,3.2,4.8,1.8], class: 'Iris-versicolor'},
{inputs: [6.1,2.8,4.0,1.3], class: 'Iris-versicolor'},
{inputs: [6.3,2.5,4.9,1.5], class: 'Iris-versicolor'},
{inputs: [6.1,2.8,4.7,1.2], class: 'Iris-versicolor'},
{inputs: [6.4,2.9,4.3,1.3], class: 'Iris-versicolor'},
{inputs: [6.6,3.0,4.4,1.4], class: 'Iris-versicolor'},
{inputs: [6.8,2.8,4.8,1.4], class: 'Iris-versicolor'},
{inputs: [6.7,3.0,5.0,1.7], class: 'Iris-versicolor'},
{inputs: [6.0,2.9,4.5,1.5], class: 'Iris-versicolor'},
{inputs: [5.7,2.6,3.5,1.0], class: 'Iris-versicolor'},
{inputs: [5.5,2.4,3.8,1.1], class: 'Iris-versicolor'},
{inputs: [5.5,2.4,3.7,1.0], class: 'Iris-versicolor'},
{inputs: [5.8,2.7,3.9,1.2], class: 'Iris-versicolor'},
{inputs: [6.0,2.7,5.1,1.6], class: 'Iris-versicolor'},
{inputs: [5.4,3.0,4.5,1.5], class: 'Iris-versicolor'},
{inputs: [6.0,3.4,4.5,1.6], class: 'Iris-versicolor'},
{inputs: [6.7,3.1,4.7,1.5], class: 'Iris-versicolor'},
{inputs: [6.3,2.3,4.4,1.3], class: 'Iris-versicolor'},
{inputs: [5.6,3.0,4.1,1.3], class: 'Iris-versicolor'},
{inputs: [5.5,2.5,4.0,1.3], class: 'Iris-versicolor'},
{inputs: [5.5,2.6,4.4,1.2], class: 'Iris-versicolor'},
{inputs: [6.1,3.0,4.6,1.4], class: 'Iris-versicolor'},
{inputs: [5.8,2.6,4.0,1.2], class: 'Iris-versicolor'},
{inputs: [5.0,2.3,3.3,1.0], class: 'Iris-versicolor'},
{inputs: [5.6,2.7,4.2,1.3], class: 'Iris-versicolor'},
{inputs: [5.7,3.0,4.2,1.2], class: 'Iris-versicolor'},
{inputs: [5.7,2.9,4.2,1.3], class: 'Iris-versicolor'},
{inputs: [6.2,2.9,4.3,1.3], class: 'Iris-versicolor'},
{inputs: [5.1,2.5,3.0,1.1], class: 'Iris-versicolor'},
{inputs: [5.7,2.8,4.1,1.3], class: 'Iris-versicolor'},
{inputs: [6.3,3.3,6.0,2.5], class: 'Iris-virginica'},
{inputs: [5.8,2.7,5.1,1.9], class: 'Iris-virginica'},
{inputs: [7.1,3.0,5.9,2.1], class: 'Iris-virginica'},
{inputs: [6.3,2.9,5.6,1.8], class: 'Iris-virginica'},
{inputs: [6.5,3.0,5.8,2.2], class: 'Iris-virginica'},
{inputs: [7.6,3.0,6.6,2.1], class: 'Iris-virginica'},
{inputs: [4.9,2.5,4.5,1.7], class: 'Iris-virginica'},
{inputs: [7.3,2.9,6.3,1.8], class: 'Iris-virginica'},
{inputs: [6.7,2.5,5.8,1.8], class: 'Iris-virginica'},
{inputs: [7.2,3.6,6.1,2.5], class: 'Iris-virginica'},
{inputs: [6.5,3.2,5.1,2.0], class: 'Iris-virginica'},
{inputs: [6.4,2.7,5.3,1.9], class: 'Iris-virginica'},
{inputs: [6.8,3.0,5.5,2.1], class: 'Iris-virginica'},
{inputs: [5.7,2.5,5.0,2.0], class: 'Iris-virginica'},
{inputs: [5.8,2.8,5.1,2.4], class: 'Iris-virginica'},
{inputs: [6.4,3.2,5.3,2.3], class: 'Iris-virginica'},
{inputs: [6.5,3.0,5.5,1.8], class: 'Iris-virginica'},
{inputs: [7.7,3.8,6.7,2.2], class: 'Iris-virginica'},
{inputs: [7.7,2.6,6.9,2.3], class: 'Iris-virginica'},
{inputs: [6.0,2.2,5.0,1.5], class: 'Iris-virginica'},
{inputs: [6.9,3.2,5.7,2.3], class: 'Iris-virginica'},
{inputs: [5.6,2.8,4.9,2.0], class: 'Iris-virginica'},
{inputs: [7.7,2.8,6.7,2.0], class: 'Iris-virginica'},
{inputs: [6.3,2.7,4.9,1.8], class: 'Iris-virginica'},
{inputs: [6.7,3.3,5.7,2.1], class: 'Iris-virginica'},
{inputs: [7.2,3.2,6.0,1.8], class: 'Iris-virginica'},
{inputs: [6.2,2.8,4.8,1.8], class: 'Iris-virginica'},
{inputs: [6.1,3.0,4.9,1.8], class: 'Iris-virginica'},
{inputs: [6.4,2.8,5.6,2.1], class: 'Iris-virginica'},
{inputs: [7.2,3.0,5.8,1.6], class: 'Iris-virginica'},
{inputs: [7.4,2.8,6.1,1.9], class: 'Iris-virginica'},
{inputs: [7.9,3.8,6.4,2.0], class: 'Iris-virginica'},
{inputs: [6.4,2.8,5.6,2.2], class: 'Iris-virginica'},
{inputs: [6.3,2.8,5.1,1.5], class: 'Iris-virginica'},
{inputs: [6.1,2.6,5.6,1.4], class: 'Iris-virginica'},
{inputs: [7.7,3.0,6.1,2.3], class: 'Iris-virginica'},
{inputs: [6.3,3.4,5.6,2.4], class: 'Iris-virginica'},
{inputs: [6.4,3.1,5.5,1.8], class: 'Iris-virginica'},
{inputs: [6.0,3.0,4.8,1.8], class: 'Iris-virginica'},
{inputs: [6.9,3.1,5.4,2.1], class: 'Iris-virginica'},
{inputs: [6.7,3.1,5.6,2.4], class: 'Iris-virginica'},
{inputs: [6.9,3.1,5.1,2.3], class: 'Iris-virginica'},
{inputs: [5.8,2.7,5.1,1.9], class: 'Iris-virginica'},
{inputs: [6.8,3.2,5.9,2.3], class: 'Iris-virginica'},
{inputs: [6.7,3.3,5.7,2.5], class: 'Iris-virginica'},
{inputs: [6.7,3.0,5.2,2.3], class: 'Iris-virginica'},
{inputs: [6.3,2.5,5.0,1.9], class: 'Iris-virginica'},
{inputs: [6.5,3.0,5.2,2.0], class: 'Iris-virginica'},
{inputs: [6.2,3.4,5.4,2.3], class: 'Iris-virginica'},
{inputs: [5.9,3.0,5.1,1.8], class: 'Iris-virginica'}];
var wgf = weighted_genetic_folder(test_list[0].inputs.length, 10);
wgf.train(test_list,
0, // training_list_error_threshold
1000, // iteration_threshold
100, // maximum_population
1.01, // nerf_rate
0.05, // weight_point_mutation_rate
0.05, // weight_point_mutation_amount
0.05, // add_genetic_fold_rate
0.05, // remove_point_genetic_fold_rate
0.05, // genetic_fold_point_mutation_rate
0.05 // genetic_fold_point_mutation_amount
);
for (var t = 0; t < test_list.length; t++)
console.log(JSON.stringify(test_list[t]) + '->' + wgf.classify(test_list[t].inputs));
//</script></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment