A random walk is a mathematical exercise of taking 100 random steps, each moves the line higher or lower on the y-axis. It will look something like this:
random.walk <- cumsum(rnorm(100))
plot( random.walk, type="l", col="darkred", axes=F, xlab="", ylab="", main="Random Walk" )
abline( h=0, lty=2, col="gray" )
Now how can we animate the process to make the concept easier to visualize?
What happens if we take a random walk along the x-axis and y-axis at the same time - if we are allowed to wander along a two-dimensional space. It will look something like a particle bouncing around inside a jar.
How would we create this animation? Here is some code to get you started:
x <- cumsum( rnorm(100) )
y <- cumsum( rnorm(100) )
max.x <- max(x)
min.x <- min(x)
max.y <- max(y)
min.y <- min(y)
par( ask=T )
par( mar=c(2,2,3,1) )
for( i in 5:100 )
{
plot( x[i], y[i], pch=19, cex=2, xlim=c(min.x,max.x), ylim=c(min.y,max.y) )
}
Now how do you make your animation look like this?
You will need to install the animation package in R to create gifs. You also need to install Image Magick, free software that turns images into animations.
If you install the program on a Windows machine, be sure to click the option “Install legacy components (convert.exe etc)” when it appears as a check box! Otherwise your animation package in R will not work.
The function you will use to create gif animations is called saveGIF()
.
# create a directory for your images
dir.create("gifs")
setwd("gifs")
library( animation )
saveGIF({
# the loop that creates your image files here
},
movie.name = "movie_name.gif", # name of your gif
interval = 0.3, # controls the animation speed
ani.width = 800, # size of the gif in pixels
ani.height = 800 ) # size of the git in pixels
From Wikipedia:
Conway was interested in a problem presented in the 1940s by mathematician John von Neumann, who attempted to find a hypothetical machine that could build copies of itself and succeeded when he found a mathematical model for such a machine with very complicated rules on a rectangular grid. The Game of Life emerged as Conway’s successful attempt to drastically simplify von Neumann’s ideas.
Ever since its publication, Conway’s Game of Life has attracted much interest, because of the surprising ways in which the patterns can evolve. Life provides an example of emergence and self-organization. Scholars in various fields, such as computer science, physics, biology, biochemistry, economics, mathematics, philosophy, and generative sciences have made use of the way that complex patterns can emerge from the implementation of the game’s simple rules[citation needed]. The game can also serve as a didactic analogy, used to convey the somewhat counterintuitive notion that “design” and “organization” can spontaneously emerge in the absence of a designer. For example, philosopher and cognitive scientist Daniel Dennett has used the analogue of Conway’s Life “universe” extensively to illustrate the possible evolution of complex philosophical constructs, such as consciousness and free will, from the relatively simple set of deterministic physical laws, which might govern our universe.
The universe of the Game of Life is an infinite two-dimensional orthogonal grid of square cells, each of which is in one of two possible states, alive or dead, or “populated” or “unpopulated” (the difference may seem minor, except when viewing it as an early model of human/urban behaviour simulation or how one views a blank space on a grid). Every cell interacts with its eight neighbours, which are the cells that are horizontally, vertically, or diagonally adjacent. At each step in time, the following transitions occur:
The initial pattern constitutes the seed of the system. The first generation is created by applying the above rules simultaneously to every cell in the seedâbirths and deaths occur simultaneously, and the discrete moment at which this happens is sometimes called a tick (in other words, each generation is a pure function of the preceding one). The rules continue to be applied repeatedly to create further generations.
It was generously translated into a compact R program by Petrkeil.
## GAME SETUP
game.of.life <- function(side, steps, filename){
# the sideXside matrix, filled up with binomially
# distributed individuals
X <- matrix(nrow=side, ncol=side)
X[] <- rbinom(side^2,1,0.4)
# array that stores all of the simulation steps
# (so that it can be exported as a gif)
storage <- array(0, c(side, side, steps))
# the simulation
for (i in 1:steps)
{
# make the shifted copies of the original array
allW = cbind( rep(0,side) , X[,-side] )
allNW = rbind(rep(0,side),cbind(rep(0,side-1),X[-side,-side]))
allN = rbind(rep(0,side),X[-side,])
allNE = rbind(rep(0,side),cbind(X[-side,-1],rep(0,side-1)))
allE = cbind(X[,-1],rep(0,side))
allSE = rbind(cbind(X[-1,-1],rep(0,side-1)),rep(0,side))
allS = rbind(X[-1,],rep(0,side))
allSW = rbind(cbind(rep(0,side-1),X[-1,-side]),rep(0,side))
# summation of the matrices
X2 <- allW + allNW + allN + allNE + allE + allSE + allS + allSW
# the rules of GoL are applied using logical subscripting
X3 <- X
X3[X==0 & X2==3] <- 1
X3[X==1 & X2<2] <- 0
X3[X==1 & X2>3] <- 0
X <- X3
image( X, col=c("white","steelblue") )
# each simulation step is stored
storage[,,i] <- X2
# note that I am storing the array of Ni values -
# - this is in order to make the animation prettier
}
storage <- storage/max(storage) # scaling the results
# to a 0-1 scale
# writing the results into an animated gif
# write.gif(storage, filename, col="jet", delay=5)
}
## SAVE ANIMATION
library( animation )
# dir.create("gifs")
setwd("gifs")
saveGIF({
par( mar=c(0,0,0,0) )
game.of.life(side=50, steps=300 )
},
movie.name = "game_of_life.gif", # name of your gif
interval = 0.1, # controls the animation speed
ani.width = 800, # size of the gif in pixels
ani.height = 800 ) # size of the git in pixels
library( animation )
setwd("gifs")
createSample <- function( samp.size=10 )
{
par( mar=c(5.1,5.1,4.1,1) )
# CREATE A DATASET WITH 100 POINTS
#
# z = b0 + b1*x where b0=800, b1=-2
x <- seq( 20, 40, length.out=100 )
z <- 800 - 10*x + rnorm(100, 0, 100)
# DRAW A SAMPLE
samp.id <- sample( 1:100, samp.size )
x2 <- x[samp.id]
z2 <- z[samp.id]
plot( x, z, xlim= c(40,20), ylim=c(200,800),
bty="n", pch=19, col=gray(0.5,0.5), cex=1.2,
main="Sampling Process",
xlab="Class Size", ylab="Test Performance",
cex.main=2, cex.lab=2 )
text( 40, 780, paste("SAMPLE SIZE OF", samp.size), pos=4, col="darkorange2", cex=1.5 )
Sys.sleep( 3 )
for( i in 1:samp.size )
{
for( j in 10:2 )
{
plot( x, z, xlim= c(40,20), ylim=c(200,800),
bty="n", pch=19, col=gray(0.5,0.5), cex=1.2,
main="Sampling Process", cex.main=2, cex.lab=2,
xlab="Class Size", ylab="Test Performance" )
text( 40, 780, paste("SAMPLE SIZE OF", samp.size),
pos=4, col="darkorange2", cex=1.5 )
if( i > 1 )
{ points( x2[1:(i-1)], z2[1:(i-1)], pch=8, cex=2, col="darkorange2", lwd=2 ) }
points( x2[i], z2[i], pch=8, cex=j, col="darkorange2", lwd=2 )
}
}
for( m in 1:30 )
{
plot( x, z, xlim= c(40,20), ylim=c(200,800),
bty="n", pch=19, col=gray(0.5,0.5), cex=1.2,
main="Sampling Process", cex.main=2, cex.lab=2,
xlab="Class Size", ylab="Test Performance" )
points( x2, z2, pch=8, cex=j, col="darkorange2", lwd=2 )
abline( a=800, b=-10, lwd=2 )
text( 28, 300, "True Slope", cex=2, pos=4 )
}
for( m in 1:50 )
{
plot( x, z, xlim= c(40,20), ylim=c(200,800),
bty="n", pch=19, col=gray(0.5,0.5), cex=1.2,
main="Sampling Process", cex.main=2, cex.lab=2,
xlab="Class Size", ylab="Test Performance" )
points( x2, z2, pch=8, cex=j, col="darkorange2", lwd=2 )
abline( a=800, b=-10, lwd=2 )
text( 28, 300, "True Slope", cex=2, pos=4 )
r1 <- lm( z2 ~ x2 )
abline( a= r1$coefficients[1], b= r1$coefficients[2], col="darkorange2", lwd=2 )
text( 28, 250, "Best Guess", col="darkorange2", cex=2, pos=4 )
}
}
# TEST
createSample( samp.size=10 )
# Generate a bunch of image files
png( "sample%03d.png", width=600, height=400 )
createSample( samp.size=10 )
createSample( samp.size=10 )
createSample( samp.size=10 )
dev.off()
## set conversion options
ani.options( interval=0, nmax = 2000 )
## matches all files with a wildcard *
im.convert( "sample*.png", output = "reg_sample_orange.gif" )
# Delete all temporary PNG files
dir()
unlink( "sample*.png")
sampDistOfSlope <- function( num.trials=1000, samp.size=10, slowSim=F )
{
slopes1 <- NULL
x <- 1:100
z <- 400 + x + rnorm(100, 0, 100)
for( i in 1:num.trials )
{
samp.id <-sample( x, samp.size )
x2 <- x[samp.id]
z2 <- z[samp.id]
r1 <- lm( z2 ~ x2 )
slopes1[i] <- r1$coefficients[2]
par( mfrow=c(1,2) )
if( slowSim==T ) { par(ask=TRUE) } # HAVE TO CLICK ON GRAPH FOR NEXT ONE
if( slowSim==F ) { par(ask=FALSE) }
plot( x, z, xlim= c(0,100), ylim=c(200, 750 ), xaxt="n", bty="n", pch=19, col=gray(0.5,0.5),
main="Repeated Samples", xlab="", ylab="Test Performance" )
title( xlab="Class Size", line=2 )
points( x2, z2, pch=8, cex=2, lwd=2, col="darkorange3" )
abline( a=400, b=1 )
abline( a= r1$coefficients[1], b= r1$coefficients[2], col="darkorange3", lwd=2 )
hist( slopes1, col="darkorange3", border="lightgray",
xlim=c(-5, 6), ylim=c(0,num.trials/5), breaks=seq(-10,10,0.5),
xlab="True Slope = 1", main="Sampling Distribution", yaxt="n", ylab="" )
}
return( slopes1 )
}
# USE:
sampDistOfSlope( num.trials=1000, samp.size=10, slowSim=F )
png( "samp_dist%03d.png", width=600, height=400 )
sampDistOfSlope( num.trials=1000, samp.size=10, slowSim=F )
dev.off()
ani.options( interval=0, nmax = 2000 )
## matches all files with a wildcard *
im.convert( "samp_dist*.png", output = "sampling_dist_slope.gif" )
# Delete all temporary PNG files
unlink( "samp_dist*.png")