@drsimonj here with five simple tricks I find myself sharing all the time with fellow R users to improve their code!
This post was originally published on DataCamp’s community as one of their top 10 articles in 2017
 1. More fun to sequence from 1
Next time you use the colon operator to create a sequence from 1 like 1:n, try seq().
# Sequence a vector
x [1] 1 2 3 4 5 6 7 8 9 10
# Sequence an integer
seq(nrow(mtcars))
#__ [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#__ [24] 24 25 26 27 28 29 30 31 32
The colon operator can produce unexpected results that can create all sorts of problems without you noticing! Take a look at what happens when you want to sequence the length of an empty vector:
# Empty vector
x [1] 1 0
seq(x)
#__ integer(0)
You’ll also notice that this saves you from using functions like length(). When applied to an object of a certain length, seq() will automatically create a sequence from 1 to the length of the object.
 2. vector() what you c()
Next time you create an empty vector with c(), try to replace it with vector(&quot;type&quot;, length).
# A numeric vector with 5 elements
vector(&quot;numeric&quot;, 5)
#__ [1] 0 0 0 0 0
# A character vector with 3 elements
vector(&quot;character&quot;, 3)
#__ [1] &quot;&quot; &quot;&quot; &quot;&quot;
Doing this improves memory usage and increases speed! You often know upfront what type of values will go into a vector, and how long the vector will be. Using c() means R has to slowly work both of these things out. So help give it a boost with vector()!
A good example of this value is in a for loop. People often write loops by declaring an empty vector and growing it with c() like this:
x x at step 2 : 1, 2
#__ x at step 3 : 1, 2, 3
#__ x at step 4 : 1, 2, 3, 4
#__ x at step 5 : 1, 2, 3, 4, 5
Instead, pre-define the type and length with vector(), and reference positions by index, like this:
n x at step 3 : 1, 2, 3, 0, 0
#__ x at step 4 : 1, 2, 3, 4, 0
#__ x at step 5 : 1, 2, 3, 4, 5
Here’s a quick speed comparison:
n [1] 6 7
# No which
x[x __ 5]
#__ [1] 6 7
Or counting number of values greater than 5:
# Using which
length(which(x __ 5))
#__ [1] 2
# Without which
sum(x __ 5)
#__ [1] 2
Why should you ditch which()? It’s often unnecessary and boolean vectors are all you need.
For example, R lets you select elements flagged as TRUE in a boolean vector:
condition 5
condition
#__ [1] FALSE FALSE FALSE TRUE TRUE
x[condition]
#__ [1] 6 7
Also, when combined with sum() or mean(), boolean vectors can be used to get the count or proportion of values meeting a condition:
sum(condition)
#__ [1] 2
mean(condition)
#__ [1] 0.4
which() tells you the indices of TRUE values:
which(condition)
#__ [1] 4 5
And while the results are not wrong, it’s just not necessary. For example, I often see people combining which() and length() to test whether any or all values are TRUE. Instead, you just need any() or all():
x 10)) __ 0)
print(&quot;At least one value is greater than 10&quot;)
#__ [1] &quot;At least one value is greater than 10&quot;
# Wrapping a boolean vector with `any()`
if (any(x __ 10))
print(&quot;At least one value is greater than 10&quot;)
#__ [1] &quot;At least one value is greater than 10&quot;
# Using `which()` and `length()` to test if all values are positive
if (length(which(x __ 0)) == length(x))
print(&quot;All values are positive&quot;)
#__ [1] &quot;All values are positive&quot;
# Wrapping a boolean vector with `all()`
if (all(x __ 0))
print(&quot;All values are positive&quot;)
#__ [1] &quot;All values are positive&quot;
Oh, and it saves you a little time…
x .5)])
#__ user system elapsed #__ 1.245 0.486 1.856
system.time(x[x __ .5])
#__ user system elapsed #__ 1.085 0.395 1.541
 4. factor that factor!
Ever removed values from a factor and found you’re stuck with old levels that don’t exist anymore? I see all sorts of creative ways to deal with this. The simplest solution is often just to wrap it in factor() again.
This example creates a factor with four levels (&quot;a&quot;, &quot;b&quot;, &quot;c&quot; and &quot;d&quot;):
# A factor with four levels
x [1] a b c d
#__ Levels: a b c d
plot(x)
If you drop all cases of one level (&quot;d&quot;), the level is still recorded in the factor:
# Drop all values for one level
x [1] a b c
#__ Levels: a b c d
plot(x)
A super simple method for removing it is to use factor() again:
x [1] a b c
#__ Levels: a b c
plot(x)
This is typically a good solution to a problem that gets a lot of people mad. So save yourself a headache and factor that factor!
Aside, thanks to Amy Szczepanski who contacted me after the original publication of this article and mentioned droplevels(). Check it out if this is a problem for you!
 5. First you get the $, then you get the power
Next time you want to extract values from a data.frame column where the rows meet a condition, specify the column with $ before the rows with [.
 Examples
Say you want the horsepower (hp) for cars with 4 cylinders (cyl), using the mtcars data set. You can write either of these:
# rows first, column second - not ideal
mtcars[mtcars$cyl == 4, ]$hp
#__ [1] 93 62 95 66 52 65 97 66 91 113 109
# column first, rows second - much better
mtcars$hp[mtcars$cyl == 4]
#__ [1] 93 62 95 66 52 65 97 66 91 113 109
The tip here is to use the second approach.
But why is that?
First reason: do away with that pesky comma! When you specify rows before the column, you need to remember the comma: mtcars[mtcars$cyl == 4,]$hp. When you specify column first, this means that you’re now referring to a vector, and don’t need the comma!
Second reason: speed! Let’s test it out on a larger data frame:
# Simulate a data frame...
n user system elapsed #__ 0.559 0.152 0.758
# column first, rows second - much better
system.time(d$a[d$b __ .5])
#__ user system elapsed #__ 0.093 0.013 0.107
Worth it, right?
Still, if you want to hone your skills as an R data frame ninja, I suggest learning dplyr. You can get a good overview on the dplyr website or really learn the ropes with online courses like DataCamp’s Data Manipulation in R with dplyr.
 Sign off
Thanks for reading and I hope this was useful for you.
For updates of recent blog posts, follow @drsimonj on Twitter, or email me at drsimonjackson@gmail.com to get in touch.
If you’d like the code that produced this blog, check out the blogR GitHub repository.