Skip to content

Instantly share code, notes, and snippets.

@jonahwilliams
Last active August 29, 2015 14:21
Show Gist options
  • Save jonahwilliams/60eecef5e9f721348c20 to your computer and use it in GitHub Desktop.
Save jonahwilliams/60eecef5e9f721348c20 to your computer and use it in GitHub Desktop.
Perceptron Learning I

Implementation of a perceptron classifier on a linearly separable dataset. The decision boundary of the classifier Sign(wx + b) is given at wx + b = 0, where w is a vector of weights, x is a vector of points, and b is the bias (intercept) term. Each step is 20 iterations of the simpliest perceptron learning algorithm; misclassified points have black outlines and correctly classified points no longer contribute to gradient adjustment. This means that the decision boundary will no longer move once all points are classified correctly, and many different decision boundaries are possible.

<!DOCTYPE html>
<meta charset="utf-8">
<head>
<script src="http://d3js.org/d3.v3.min.js"></script>
<style>
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<div align="center">
<button type="button" onclick="UpdatePerceptron()">Iterate</button>
</div>
<script>
var m = {'x': 0.001, 'y': 0.001},
b = 0,
alpha = 0.01;
var margin = {top: 80, right: 180, bottom: 80, left: 180},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var y = d3.scale.linear()
.domain([0, 10])
.range([height, 0]);
var x = d3.scale.linear()
.domain([0, 10])
.range([0, width])
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
decision = svg.append("line")
.attr("class", "line")
.attr("x1", function(d){
return x(0);
})
.attr("x2", function(d){
return x(10);
})
.attr("y1", function(d){
return y(-b / m.y);
})
.attr("y2", function(d){
return y(((-m.x / m.y) * 10) - (b / m.y));
})
.style("stroke", "black")
.style("stroke-width", 1);
d3.json("PerceptronClassifier.json", function(error, data){
dots = svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 5.5)
.attr("cx", function(d){
return x(+d.x);
})
.attr("cy", function(d){
return y(+d.y)
})
.style("fill", function(d){
if (d.c == 1){
return "#377eb8";
}
else {
return "#e41a1c";
}
})
.style("stroke", function(d){
var u = d.c * ((m.x * d.x) + (m.y * d.y) + b);
if (u >= 0){
return "white";
}
else{
return "black";
console.log(d.x, d.y, d.c);
}
})
.style("stroke-width", 2);
});
function OfflineLearning(data, alpha){
//Takes dataset and setpsize alpha
var delta = [0, 0, 0];
for (var i = 0; i < data.length; i++){
var d = data[i];
var u = d.c * ((m.x * d.x) + (m.y * d.y) + b);
if ( u <= 0){
delta[0] += (d.c - f) * d.x;
delta[1] += (d.c - f) * d.y;
delta[2] += (d.c - f);
}
}
for (var i = 0; i < delta; i ++){
delta[i] /= data.length
}
m.x = m.x + alpha * delta[0];
m.y = m.y + alpha * delta[1];
b = b + alpha * delta[2];
return [m, b];
}
function OnlineLearning(data, alpha, n){
//Takes a dataset, a setpsize alpha, and a number of iterations to performs,
//Otherwise far too slow to see effect
for (var i = 0; i < n; i++){
var d = data[Math.floor(Math.random() * data.length)];
var u = (m.x * d.x) + (m.y * d.y) + b;
if (d.c * u <= 0){
m.x = m.x + alpha * d.c * d.x;
m.y = m.y + alpha * d.c * d.y;
b = b + alpha * d.c;
}
}
return [m, b];
}
function UpdatePerceptron(){
d3.json("PerceptronClassifier.json", function(error, data){
ret = OnlineLearning(data, alpha, 10);
m = ret[0];
b = ret[1];
decision.transition()
.ease("linear")
.attr("y1", function(d){
return y(-b / m.y);
})
.attr("y2", function(d){
return y(((-m.x / m.y) * 10) - (b / m.y));
});
dots.transition()
.ease("linear")
.style("stroke", function(d){
var u = d.c * ((m.x * d.x) + (m.y * d.y) + b);
if (u >= 0){
return "white";
}
else{
return "black";
console.log(d.x, d.y, d.c);
}
});
});
}
</script>
</body>
[{"x":1.3918159586,"y":2.3137462987,"c":-1},{"x":2.7553492977,"y":3.8358933062,"c":-1},{"x":1.3068825052,"y":1.562141254,"c":-1},{"x":2.8944226465,"y":2.5841533943,"c":-1},{"x":3.7024428812,"y":2.7501198675,"c":-1},{"x":3.5026863304,"y":4.1441852379,"c":-1},{"x":1.2875267989,"y":1.6449839313,"c":-1},{"x":1.5512224368,"y":3.479681808,"c":-1},{"x":2.4134867529,"y":4.2236237896,"c":-1},{"x":3.6559341255,"y":1.9783436371,"c":-1},{"x":6.9659900849,"y":5.3009901301,"c":1.0},{"x":9.0119210614,"y":7.702946096,"c":1.0},{"x":5.950966712,"y":7.2311001543,"c":1.0},{"x":5.979236673,"y":7.7339372771,"c":1.0},{"x":5.955605886,"y":6.8574976596,"c":1.0},{"x":7.8664572356,"y":6.3242365141,"c":1.0},{"x":5.2714950518,"y":6.744864841,"c":1.0},{"x":7.0457948624,"y":8.2216029477,"c":1.0},{"x":8.3580121873,"y":7.1820232618,"c":1.0},{"x":9.6273291291,"y":7.0579781464,"c":1.0}]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment