Skip to content

Instantly share code, notes, and snippets.

@jameshenegan
Created September 27, 2019 20:05
Show Gist options
  • Save jameshenegan/c8ee4fc0e4b58e21ca86f1315028661a to your computer and use it in GitHub Desktop.
Save jameshenegan/c8ee4fc0e4b58e21ca86f1315028661a to your computer and use it in GitHub Desktop.
Sampling from a Binomial Distribution

Sampling from a Binomial Distribution

Let X denote a random variable with a Binomial(n=8, p=0.5) distribution. Step One: Plot the probability mass function of X. Step Two: Draw 100 observations from X and make a histogram of the results. Step Three: Repeat Steps Two and Three.

class Binom {
constructor(n, p) {
this.n = n,
this.p = p
this.pmf = this.makePMF()
this.cdf = this.makeCDF()
}
binomialSumArg(n, i, p) {
return choose(n, i) * Math.pow(p, i) * Math.pow(1 - p, n - i)
}
makePMF() {
const myLinSpace = linSpaceInclude(0, this.n, this.n)
myLinSpace.forEach((val, index) => {
myLinSpace[index] = this.binomialSumArg(this.n, index, this.p)
})
return myLinSpace
}
makeCDF() {
var runningSum = 0;
const newArray = [...this.pmf]
newArray.forEach((val, index) => {
newArray[index] = newArray[index] + runningSum
runningSum = newArray[index]
})
return newArray
}
}
function factorial(k) {
if (k == 0) {
return 1
} else {
return (k == 1) ? k : (k * factorial(k - 1))
}
}
function choose(n, k) {
return factorial(n) / (factorial(n - k) * factorial(k))
}
const sum = arr => arr.reduce((a, b) => a + b, 0)
function roundEight(n) {
return Math.round(Math.pow(10, 8) * n) / Math.pow(10, 8)
}
function linSpaceInclude(start, stop, n) {
var arr = [];
const step = (stop - start) / n
for (var loc = start; loc <= stop; loc = loc + step) {
arr.push(loc)
}
return arr;
}
function binomialSumArg(n, i, p) {
return choose(n, i) * Math.pow(p, i) * Math.pow(1 - p, n - i)
}
function roundFour(n) {
return Math.round(Math.pow(10, 4) * n) / Math.pow(10, 4)
}
var myResults = []
for(var j = 0; j < numSamples; j++){
var randomUniformVariate = Math.random()
var comparisons = rng.cdf.map( d=> randomUniformVariate < d ? true : false)
var result = comparisons.findIndex( d => d == true)
myResults.push(result)
}
var x = d3.scaleLinear()
.domain([-1, rng.n + 1])
.range([0, width]);
// set the parameters for the histogram
var histogram = d3.histogram()
.value(function (d) { return d }) // I need to give the vector of value
.domain(x.domain()) // then the domain of the graphic
.thresholds(x.ticks(rng.n + 1)); // then the numbers of bins
// And apply this function to data to get the bins
var bins = histogram(myResults);
// Y axis: scale and draw:
var y = d3.scaleLinear()
.range([height, 0]);
y.domain([0, d3.max(bins, function (d) { return d.length; })]);
// append the bar rectangles to the svg element
svg.selectAll("rect")
.data(bins)
.enter()
.append("rect")
.attr("x", 1)
.attr("transform", function (d) { return `translate(${x(d.x0-0.5)}, ${y(d.length)})`; })
.attr("width", function(d) {
if(x(d.x1) - x(d.x0) > 1){
return x(d.x1) - x(d.x0) -1
} else{
return 0
}
})
.attr("height", function (d) { return height - y(d.length); })
.style("fill", "#69b3a2")
.style("opacity", 0.75)
//"translate(" + x(d.x0) + "," + y(d.length) + ")";
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<script>
const binomialN = 8
const binomialP = 0.5
const numSamples = 100;
</script>
<script src="helpers.js"></script>
<script src="binom.js"></script>
<script src="lollipop.js"></script>
<script src="histo.js"></script>
<script src="interval.js"></script>
</body>
</html>
d3.interval(() => {
myResults = []
for (var j = 0; j < numSamples; j++) {
var randomUniformVariate = Math.random()
var comparisons = rng.cdf.map(d => randomUniformVariate < d ? true : false)
var result = comparisons.findIndex(d => d == true)
myResults.push(result)
}
// And apply this function to data to get the bins
bins = histogram(myResults);
y.domain([0, d3.max(bins, function (d) { return d.length; })]);
svg.selectAll("rect")
.data(bins)
.transition()
.duration(1000)
.attr("transform", function (d) { return `translate(${x(d.x0 - 0.5)}, ${y(d.length)})`; })
.attr("width", function (d) {
if (x(d.x1) - x(d.x0) > 1) {
return x(d.x1) - x(d.x0) - 1
} else {
return 0
}
})
.attr("height", function (d) { return height - y(d.length); })
}, 1000)
var rng = new Binom(binomialN, binomialP)
console.log(rng)
// set the dimensions and margins of the graph
var margin = { top: 10, right: 30, bottom: 90, left: 40 },
width = 460 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// append the svg object to the body of the page
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 myData = rng.pmf
// X axis
var x = d3.scaleBand()
.range([0, width])
.domain(myData.map((d, i) => i))
.padding(1)
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end");
// Add Y axis
var y = d3.scaleLinear()
.domain([0, d3.max(myData)])
.range([height, 0]);
svg.append("g")
.call(d3.axisLeft(y));
// Lines
svg.selectAll("myline")
.data(myData)
.enter()
.append("line")
.attr("x1", (d, i) => x(i))
.attr("x2", (d, i) => x(i))
.attr("y1", d => y(d))
.attr("y2", y(0))
.attr("stroke", "grey")
svg.selectAll("mycircle")
.data(myData)
.enter()
.append("circle")
.attr("cx", (d, i) => x(i))
.attr("cy", d => y(d))
.attr("r", "4")
.style("fill", "#69b3a2")
.attr("stroke", "black")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment