{"id":261,"date":"2013-07-15T13:55:27","date_gmt":"2013-07-15T18:55:27","guid":{"rendered":"http:\/\/homepages.uc.edu\/~yaozo\/wordpress\/?p=261"},"modified":"2013-07-15T13:55:27","modified_gmt":"2013-07-15T18:55:27","slug":"writing-a-for-loop-in-r","status":"publish","type":"post","link":"https:\/\/zhuoyao.net\/index.php\/2013\/07\/15\/writing-a-for-loop-in-r\/","title":{"rendered":"Writing a for-loop in R"},"content":{"rendered":"<div>by\u00a0<a title=\"Posts by Patrick\" href=\"http:\/\/paleocave.sciencesortof.com\/author\/patrick\/\" rel=\"author\">Patrick<\/a>\u00a0on\u00a0<abbr title=\"2013-03-23T07:38:56-0700\">23 March, 2013<\/abbr>\u00a0in\u00a0<a title=\"View all posts in Patrick's Ponderables\" href=\"http:\/\/paleocave.sciencesortof.com\/category\/patricks-ponderables\/\">Patrick&#8217;s Ponderables<\/a><\/div>\n<section>There may be no R topic that is more controversial than the humble for-loop. And, to top it off, good help is hard to find. I was astounded by the lack of useful posts when I googled \u201cfor loops in R\u201d (the top return linked to a page that did not exist). In fact, even searching for help within R is not easy and not even that helpful when successful (<code>?for<\/code>\u00a0won\u2019t get you anywhere.\u00a0<code>?'for'<\/code>\u00a0will get you the help page but it is by no means exhaustive.) So, at the request of Sam, a faithful reader of the Paleocave blog, I\u2019m going to throw my hat into the ring and brace myself for the potential onslaught of internet troll wrath.<\/p>\n<h3>How to loop in R<\/h3>\n<p>Use the for loop if you want to do the same task a specific number of times.<br \/>\nIt looks like this.<\/p>\n<p><code>for (counter in vector) {commands}<\/code><\/p>\n<p>I\u2019m going to set up a loop to square every element of my dataset,\u00a0<code>foo<\/code>, which contains the odd integers from 1 to 100 (keep in mind that vectorizing would be faster for my trivial example \u2013 see below).<\/p>\n<p><code><br \/>\nfoo = seq(1, 100, by=2)<\/code><\/p>\n<p>foo.squared = NULL<\/p>\n<p>for (i in 1:50 ) {<br \/>\nfoo.squared[i] = foo[i]^2<br \/>\n}<\/p>\n<p><code><\/code><br \/>\nIf the creation of a new vector is the goal, first you have to set up a vector to store things in prior to running the loop. This is the\u00a0<code>foo.squared<\/code>\u00a0part. This was a hard lesson for me to learn. R doesn\u2019t like being told to operate on a vector that doesn\u2019t exist yet. So, we set up an empty vector to add stuff to later (note that this isn\u2019t the most speed efficient way to do this, but it\u2019s fairly fool-proof). Next, the real for-loop begins. This code says we\u2019ll loop 50 times(<code>1:50<\/code>). The counter we set up is \u2018i\u2019 (but you can put whatever variable name you want there). For our new vector\u00a0<code>foo.squared<\/code>, the\u00a0<code>i<\/code>th element will equal the number of loops that we are on (for the first loop,\u00a0<code>i=1<\/code>; second loop,\u00a0<code>i=2<\/code>).<\/p>\n<p>If you are new to programming it is sometimes difficult to keep straight the difference in the number of loops you are on versus the value of the element of vector being operated on. For example when we\u2019ve looped through the instructions 4 times, the next loop will be loop number 5 (so i=5). However the 5th element of foo will be\u00a0<code>foo[5]<\/code>, which is equal to 9. Therefore,\u00a0<code>foo.squared[5]<\/code>\u00a0should equal 81.<\/p>\n<p><strong>Silly mistakes to be made<\/strong><br \/>\nIf you are having problems with your loop, it could be one of these silly mental slips.<\/p>\n<p>Did you reset your vector inside the loop? Is it possible you put a\u00a0<code>new.vector = NULL\u00a0<\/code>inside the loop instead of before it? Yeah, I&#8217;ve done it. About 45 minutes later I finally figured out what was wrong with my loop.<\/p>\n<p>Did you forget to subscript your new vector? Possibly the inside of your loop looks like this<br \/>\n<code>{ foo.squared = foo[i]^2 }<\/code>.<br \/>\nYou are missing your square brackets with a counter on the left side of the\u00a0<code>operator. This will result in\u00a0<\/code><code>foo.squared<\/code>\u00a0containing only one value \u2013 the last value calculated by the loop.<\/p>\n<h3>Why is this controversial?<\/h3>\n<p>A little background:<br \/>\n1) Loops are slow in R. This fact puts lots of R users on the defense from the very beginning. Users of almost any other language can just bring up looping speed when they want to get under R users&#8217; skins. The fact is, for many people, it doesn&#8217;t matter. Computers are fast and even slow looping will likely accomplish what you need in a reasonable length of time unless you are working with a really huge dataset. And there are lots of workarounds for users of big data in R.<\/p>\n<p>2) R itself is primarily written in C (or some variant like C++). When you set up a vector in R, you can easily do operations on the entire vector (this is the vectorization that gets discussed so frequently in R literature).<\/p>\n<p><code>foo.squared = foo^2<\/code><\/p>\n<p>Underneath the R code you just executed is blazingly fast C code running loops to get you the answer. The upshot here is that C is much faster than R and if you can do get what you seek in R by applying a command to a vector it&#8217;s typically a good idea to do so.<\/p>\n<p>3) R is a functional language, the result of that is the flow control and programming is somewhat de-emphasized. Many R natives would prefer that you use the\u00a0<code>apply<\/code>\u00a0family of functions rather than writing a for-loop (often possible, but not always). Adding a layer of vitriol to this preference for the\u00a0<code>apply<\/code>command is the rumor (left over from the S language from which R was derived) that\u00a0<code>apply<\/code>\u00a0is faster than a for-loop. This is false (at least theoretically), because inside the code for the\u00a0<code>apply<\/code>\u00a0command is a for-loop written in R. There are a couple of functions in the\u00a0<code>apply<\/code>\u00a0family which do avoid R loops and therefore probably are faster than a loop. But most\u00a0<code>apply<\/code>\u00a0functions are no faster than a well constructed loop (more on well constructed later). But using\u00a0<code>apply<\/code>\u00a0is best left for another post, we have plenty to tackle just learning how to write a half-way decent loop.<\/p>\n<p><strong>Some more advanced looping thoughts<\/strong><\/p>\n<p>If you are writing a for-loop inside of a larger construct, the number of times you want to loop could depend on the length of a vector which could change depending on other factors. Therefore, you can set up your counter in vector part of the loop like this<\/p>\n<p><code>for (i in 1:length(foo)) {<br \/>\n#stuff to do the number of times that foo is long<br \/>\n}<\/code><\/p>\n<p><strong>The well constructed loop<\/strong><\/p>\n<p>If you are running into speed problems there are a couple of things to try (see also the\u00a0<a href=\"http:\/\/www.burns-stat.com\/pages\/Tutor\/R_inferno.pdf\">R inferno<\/a>).<\/p>\n<p>Get as much stuff as possible out of the loop. If there are any operations that could be done to the vector prior to looping, get them outside of those curly brackets.<\/p>\n<p><strong>Avoid growing your object<\/strong><\/p>\n<p>In the example above we created an empty vector to store our new values in (<code>foo.squared<\/code>). That vector is empty, and every time we go through the loop we grow the vector by one. It would be faster if we could set up our vector to be the right length ahead of time and then just simply fill that vector with the correct values.<br \/>\n<code>foo.squared = numeric(length=50) #generates a vector of 50 zeros; now we run the loop as before<\/code><\/p>\n<p>Of course, sometimes when we write loops we don&#8217;t know how many things are going to come out the other end. Usually we can guess on an upper bound though. It&#8217;s going to be faster to partially fill a very long vector using a loop then get rid of the meaningless stuff at the end than to grow a vector one loop at a time. We can make a very large vector full of NAs and dump them at the end. Give these two loops a try and note the speed difference on your computer.<\/p>\n<p><code><br \/>\nbar = seq(1,200000, by=2)<br \/>\nbar.squared = rep(NA, 200000)<\/code><\/p>\n<p>for (i in 1:length(bar) ) {<br \/>\nbar.squared[i] = bar[i]^2<br \/>\n}<\/p>\n<p><code>#get rid of excess NAs<br \/>\nbar.squared = bar.squared[!is.na(bar.squared)]<br \/>\nsummary(bar.squared)<br \/>\n<\/code><\/p>\n<p>Versus<\/p>\n<p><code><br \/>\nbar = seq(1, 200000, by=2)<br \/>\nbar.squared = NULL<\/code><\/p>\n<p><code><\/code><code>for (i in 1:length(bar) ) {<br \/>\nbar.squared[i] = bar[i]^2<br \/>\n}<br \/>\nsummary(bar.squared)<\/code><\/p>\n<\/section>\n","protected":false},"excerpt":{"rendered":"<p>by\u00a0Patrick\u00a0on\u00a023 March, 2013\u00a0in\u00a0Patrick&#8217;s Ponderables There may be no R topic that is more controversial than the humble for-loop. And, to top it off, good help&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20],"tags":[],"class_list":["post-261","post","type-post","status-publish","format-standard","hentry","category-r"],"_links":{"self":[{"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/posts\/261","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/comments?post=261"}],"version-history":[{"count":0,"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/posts\/261\/revisions"}],"wp:attachment":[{"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/media?parent=261"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/categories?post=261"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zhuoyao.net\/index.php\/wp-json\/wp\/v2\/tags?post=261"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}