VOOZH about

URL: https://www.javacodegeeks.com/2015/04/r-removing-for-loops.html

⇱ R: Removing for loops - Java Code Geeks


In my last blog post I showed the translation of a likelihood function from Think Bayes into R and in my first attempt at this function I used a couple of nested for loops.

likelihoods = function(names, mixes, observations) {
 scores = rep(1, length(names))
 names(scores) = names
 
 for(name in names) {
 for(observation in observations) {
 scores[name] = scores[name] * mixes[[name]][observation] 
 }
 } 
 return(scores)
}
Names = c("Bowl 1", "Bowl 2")
 
bowl1Mix = c(0.75, 0.25)
names(bowl1Mix) = c("vanilla", "chocolate")
bowl2Mix = c(0.5, 0.5)
names(bowl2Mix) = c("vanilla", "chocolate")
Mixes = list("Bowl 1" = bowl1Mix, "Bowl 2" = bowl2Mix)
Mixes
 
Observations = c("vanilla", "vanilla", "vanilla", "chocolate")
l = likelihoods(Names, Mixes, Observations)
 
> l / sum(l)
 Bowl 1 Bowl 2 
0.627907 0.372093

We pass in a vector of bowls, a nested dictionary describing the mixes of cookies in each bowl and the observations that we’ve made. The function tells us that there’s an almost 2/3 probability of the cookies coming from Bowl 1 and just over 1/3 of being Bowl 2.

In this case there probably won’t be much of a performance improvement by getting rid of the loops but we should be able to write something that’s more concise and hopefully idiomatic.

Let’s start by getting rid of the inner for loop. That can be replace by a call to the Reduce function like so:

likelihoods2 = function(names, mixes, observations) {
 scores = rep(0, length(names))
 names(scores) = names
 
 for(name in names) {
 scores[name] = Reduce(function(acc, observation) acc * mixes[[name]][observation], Observations, 1)
 } 
 return(scores)
}
l2 = likelihoods2(Names, Mixes, Observations)
 
> l2 / sum(l2)
 Bowl 1 Bowl 2 
0.627907 0.372093

So that’s good, we’ve still got the same probabilities as before. Now to get rid of the outer for loop. The Map function helps us out here:

likelihoods3 = function(names, mixes, observations) {
 scores = rep(0, length(names))
 names(scores) = names
 
 scores = Map(function(name) 
 Reduce(function(acc, observation) acc * mixes[[name]][observation], Observations, 1), 
 names)
 
 return(scores)
}
 
l3 = likelihoods3(Names, Mixes, Observations)
> l3
$`Bowl 1`
 vanilla 
0.1054688 
 
$`Bowl 2`
vanilla 
 0.0625

We end up with a list instead of a vector which we need to fix by using the unlist function:

likelihoods3 = function(names, mixes, observations) {
 scores = rep(0, length(names))
 names(scores) = names
 
 scores = Map(function(name) 
 Reduce(function(acc, observation) acc * mixes[[name]][observation], Observations, 1), 
 names)
 
 return(unlist(scores))
}
 
l3 = likelihoods3(Names, Mixes, Observations)
 
> l3 / sum(l3)
Bowl 1.vanilla Bowl 2.vanilla 
 0.627907 0.372093

Now we just have this annoying ‘vanilla’ in the name. That’s fixed easily enough:

likelihoods3 = function(names, mixes, observations) {
 scores = rep(0, length(names))
 names(scores) = names
 
 scores = Map(function(name) 
 Reduce(function(acc, observation) acc * mixes[[name]][observation], Observations, 1), 
 names)
 
 result = unlist(scores)
 names(result) = names
 
 return(result)
}
 
l3 = likelihoods3(Names, Mixes, Observations)
 
> l3 / sum(l3)
 Bowl 1 Bowl 2 
0.627907 0.372093

A slightly cleaner alternative makes use of the sapply function:

likelihoods3 = function(names, mixes, observations) {
 scores = rep(0, length(names))
 names(scores) = names
 
 scores = sapply(names, function(name) 
 Reduce(function(acc, observation) acc * mixes[[name]][observation], Observations, 1))
 names(scores) = names
 
 return(scores)
}
 
l3 = likelihoods3(Names, Mixes, Observations)
 
> l3 / sum(l3)
 Bowl 1 Bowl 2 
0.627907 0.372093

That’s the best I’ve got for now but I wonder if we could write a version of this using matrix operations some how – but that’s for next time!

Reference: R: Removing for loops from our JCG partner Mark Needham at the Mark Needham Blog blog.
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Thank you!

We will contact you soon.

Tags
R
👁 Photo of Mark Needham
Mark Needham
April 22nd, 2015Last Updated: April 22nd, 2015
0 92 2 minutes read
Back to top button
Close
wpDiscuz