The idea to make the set of the papers for R script enhancement and advanced performance have arisen due to:

Content

vectorization

The brief example of see here - 2.3.2 Example of vectorization

fast reading data

The overview of fast reading options see here

fast writing data

The overview of fast reading options see here

R script enhancements

Vectorise and pre-allocate data structures

Examples are taken from here

# Create the data frame
col1 <- runif (12^5, 0, 2)
col2 <- rnorm (12^5, 0, 2)
col3 <- rpois (12^5, 3)
col4 <- rchisq (12^5, 2)
df <- data.frame (col1, col2, col3, col4)

The logic we are about to optimise:
For every row on this data frame (df), check if the sum of all values is greater than 4.

If it is, a new 5th variable gets the value “greater_than_4”, else, it gets “lesser_than_4”.

# Original R code: Before vectorization and pre-allocation
system.time({
  for (i in 1:nrow(df)) { # for every row
    if ((df[i, 'col1'] + df[i, 'col2'] + df[i, 'col3'] + df[i, 'col4']) > 4) { # check if > 4
      df[i, 5] <- "greater_than_4" # assign 5th column
    } else {
      df[i, 5] <- "lesser_than_4" # assign 5th column
    }
  }
})
   user  system elapsed 
 936.58   62.32 1233.08 
df[,5] <- NULL
# after vectorization and pre-allocation
output <- character (nrow(df)) # initialize output vector for vectorization
# loop with preallocated vector
system.time({
  for (i in 1:nrow(df)) {
    if ((df[i, 'col1'] + df[i, 'col2'] + df[i, 'col3'] + df[i, 'col4']) > 4) {
      output[i] <- "greater_than_4" #looping through the vector but not a dataframe
    } else {
      output[i] <- "lesser_than_4" #looping through the vector but not a dataframe
    }
  }
  
# actual vectorization: in place of row-by-row transactions we manipulate the single vector only.  
df$output <- output 
}
)
   user  system elapsed 
  31.77    0.07   42.01 
df[,5] <- NULL

Place IF statements (expressions) outside the loop.

Examples are taken from here

# initialize output vector for vectorization
output <- character (nrow(df))
# the expression in IF statement
condition <- (df$col1 + df$col2 + df$col3 + df$col4) > 4  # condition check outside the loop
system.time({
  for (i in 1:nrow(df)) {
    if (condition[i]) {
      output[i] <- "greater_than_4"
    } else {
      output[i] <- "lesser_than_4"
    }
  }
  df$output <- output
})
   user  system elapsed 
   1.61    0.00    2.53 
df[,5] <- NULL

The LOOP only for True conditions

Examples are taken from here

# initialize output vector for vectorization
output <- character (nrow(df))
# the expression in IF statement
condition <- (df$col1 + df$col2 + df$col3 + df$col4) > 4  # condition check outside the loop
system.time({
  for (i in (1:nrow(df))[condition]) {  # run loop only for true conditions
    if (condition[i]) {
      output[i] <- "greater_than_4"
    } else {
      output[i] <- "lesser_than_4"
    }
  }
# actual vectorization: in place of row-by-row transactions we manipulate the single vector only.    
df$output <- output
})
   user  system elapsed 
   0.39    0.00    0.41 
df[,5] <- NULL

Use ifelse() whenever possible

Examples are taken from here

You can make this logic much simpler and faster by using the ifelse() statement.

Looks like this is going to be a highly preferred option to speed up simple loops.

system.time({
  output <- ifelse ((df$col1 + df$col2 + df$col3 + df$col4) > 4, "greater_than_4", "lesser_than_4")
  df$output <- output
})
   user  system elapsed 
   0.17    0.00    0.17 
df[,5] <- NULL

Using which()

Examples are taken from here

system.time({
  want = which(rowSums(df) > 4)
  output = rep("less than 4", times = nrow(df))
  output[want] = "greater than 4"
  df$output <- output
}) 
   user  system elapsed 
   0.02    0.00    0.02 
df[,5] <- NULL

Use apply family of functions instead of for-loops

Examples are taken from here

# apply family
system.time({
  myfunc <- function(x) {
    if ((x['col1'] + x['col2'] + x['col3'] + x['col4']) > 4) {
      "greater_than_4"
    } else {
      "lesser_than_4"
    }
  }
  output <- apply(df[, c(1:4)], 1, FUN=myfunc)  # apply 'myfunc' on every row
  df$output <- output
})
   user  system elapsed 
   3.01    0.02    3.85 
df[,5] <- NULL

Use byte code compilation for functions cmpfun()

We will use initial dataframe as the input and the initial FOR loop (as in the first example).

f <- function(df){
   for (i in 1:nrow(df)) { # for every row
    if ((df[i, 'col1'] + df[i, 'col2'] + df[i, 'col3'] + df[i, 'col4']) > 4) { # check if > 4
      df[i, 5] <- "greater_than_4" # assign 5th column
    } else {
      df[i, 5] <- "lesser_than_4" # assign 5th column
    }
  }
}
library(compiler)
g <- cmpfun(f)
system.time(
  g(df)
)
   user  system elapsed 
 558.29  254.10  872.24 
df[,5] <- NULL
LS0tDQp0aXRsZTogIkVuaGFuY2VkIFIgc2NyaXB0Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQphdXRob3I6IERlbXlkIER6eXViYW4NCmRhdGU6IDE2LzEyLzIwMTYNCi0tLQ0KDQpUaGUgaWRlYSB0byBtYWtlIHRoZSBzZXQgb2YgdGhlIHBhcGVycyBmb3IgUiBzY3JpcHQgZW5oYW5jZW1lbnQgYW5kIGFkdmFuY2VkIHBlcmZvcm1hbmNlIGhhdmUgYXJpc2VuIGR1ZSB0bzogIA0KDQoNCiogW1IgaW4gYWN0aW9uXShodHRwczovL3d3dy5tYW5uaW5nLmNvbS9ib29rcy9yLWluLWFjdGlvbi1zZWNvbmQtZWRpdGlvbikuDQpJdCBpcyBzdHJvbmdseSByZWNvbW1lbmRlZCBmb3Igd2lkZSByYW5nZSBvZiBuZXdjb21lcnMsIGNvbXB1dGF0aW9uYWwgZ2Vla3MsIGV0Yy4gYXMgYSBzdGFydGluZyBwb2ludCB0byB0cmF2ZWwgdG8gYW1hemluZyBSIGluZmVybmFsIHNob3Jlcy4gIA0KDQoqIFtSIElORkVSTk9dKGh0dHA6Ly93d3cuYnVybnMtc3RhdC5jb20vZG9jdW1lbnRzL2Jvb2tzL3RoZS1yLWluZmVybm8vKS4NClRoaXMgaXMgYW4gZXhjZWxsZW50IHdheSB0byBzdGFydCBpbmNyZWRpYmxlIHRyaXAgdGhyb3VnaCBSIGluZmVybmFsIGNpcmNsZXMgOi0pDQoNCiogW0FkdmFuY2VkIFJdKGh0dHA6Ly9hZHYtci5oYWQuY28ubnovKS4NCk5pY2UgYm9vayB0byByZWFkIGZvciB0aG9zZSB3aG8gc3Vydml2ZWQgcHJldmlvdXMgc3RhZ2VzLg0KDQoqIFtTdGFja292ZXJmbG93LmNvbV0oaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tLykuDQpUaGUgZW5kbGVzcyBmb3VudGFpbiBvZiB0aGUgZXRlcm5hbCB3aXNkb20gb2YgUiBkd2VsbGVycyA6LSkNCg0KKiBbd3d3LnItYmxvZ2dlcnMuY29tXShodHRwczovL3d3dy5yLWJsb2dnZXJzLmNvbS8pDQpWZXJ5IG5pY2UgcGxhY2Ugb2Ygc21hcnQsIHBsYWluIGFuZCBzaG9ydCBoaW50cywgY29tbWVudHMgYW5kIGV4cGxhbmF0aW9ucy4NCg0KDQoNCiMjIyAqKkNvbnRlbnQqKg0KDQoqIHZlY3Rvcml6YXRpb24NCiogZmFzdCBkYXRhIHJlYWRpbmcgDQoqIGZhc3QgZGF0YSB3cml0aW5nDQoqIHNjcmlwdCBlbmhhbmNlbWVudA0KICANCg0KDQojIyMjICoqdmVjdG9yaXphdGlvbioqDQoNClRoZSBicmllZiBleGFtcGxlIG9mIFtzZWUgaGVyZSAtIDIuMy4yIEV4YW1wbGUgb2YgdmVjdG9yaXphdGlvbl0oaHR0cHM6Ly9ycHVicy5jb20vZGVteWRkLzIxMDU0MSkNCg0KDQojIyMjICoqZmFzdCByZWFkaW5nIGRhdGEqKg0KVGhlIG92ZXJ2aWV3IG9mIGZhc3QgcmVhZGluZyBvcHRpb25zIFtzZWUgaGVyZSBdKGh0dHBzOi8vcnB1YnMuY29tL2RlbXlkZC8yMTA1NDEpDQoNCg0KDQojIyMjICoqZmFzdCB3cml0aW5nIGRhdGEqKg0KVGhlIG92ZXJ2aWV3IG9mIGZhc3QgcmVhZGluZyBvcHRpb25zIFtzZWUgaGVyZSBdKGh0dHBzOi8vcnB1YnMuY29tL2RlbXlkZC8yMTA1NDEpDQoNCg0KIyMjICoqUiBzY3JpcHQgZW5oYW5jZW1lbnRzKioNCg0KDQojIyMjICpWZWN0b3Jpc2UgYW5kIHByZS1hbGxvY2F0ZSBkYXRhIHN0cnVjdHVyZXMqDQpFeGFtcGxlcyBhcmUgdGFrZW4gZnJvbSBbaGVyZV0oaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vc3RyYXRlZ2llcy10by1zcGVlZHVwLXItY29kZS8pDQoNCg0KYGBge3J9DQojIENyZWF0ZSB0aGUgZGF0YSBmcmFtZQ0KY29sMSA8LSBydW5pZiAoMTJeNSwgMCwgMikNCmNvbDIgPC0gcm5vcm0gKDEyXjUsIDAsIDIpDQpjb2wzIDwtIHJwb2lzICgxMl41LCAzKQ0KY29sNCA8LSByY2hpc3EgKDEyXjUsIDIpDQpkZiA8LSBkYXRhLmZyYW1lIChjb2wxLCBjb2wyLCBjb2wzLCBjb2w0KQ0KDQpgYGANCg0KKlRoZSBsb2dpYyB3ZSBhcmUgYWJvdXQgdG8gb3B0aW1pc2U6KiAgDQpGb3IgZXZlcnkgcm93IG9uIHRoaXMgZGF0YSBmcmFtZSAoZGYpLCBjaGVjayBpZiB0aGUgc3VtIG9mIGFsbCB2YWx1ZXMgaXMgZ3JlYXRlciB0aGFuIDQuIA0KDQpJZiBpdCBpcywgYSBuZXcgNXRoIHZhcmlhYmxlIGdldHMgdGhlIHZhbHVlICJncmVhdGVyX3RoYW5fNCIsIGVsc2UsIGl0IGdldHMgImxlc3Nlcl90aGFuXzQiLg0KDQpgYGB7cn0NCg0KIyBPcmlnaW5hbCBSIGNvZGU6IEJlZm9yZSB2ZWN0b3JpemF0aW9uIGFuZCBwcmUtYWxsb2NhdGlvbg0Kc3lzdGVtLnRpbWUoew0KICBmb3IgKGkgaW4gMTpucm93KGRmKSkgeyAjIGZvciBldmVyeSByb3cNCiAgICBpZiAoKGRmW2ksICdjb2wxJ10gKyBkZltpLCAnY29sMiddICsgZGZbaSwgJ2NvbDMnXSArIGRmW2ksICdjb2w0J10pID4gNCkgeyAjIGNoZWNrIGlmID4gNA0KICAgICAgZGZbaSwgNV0gPC0gImdyZWF0ZXJfdGhhbl80IiAjIGFzc2lnbiA1dGggY29sdW1uDQogICAgfSBlbHNlIHsNCiAgICAgIGRmW2ksIDVdIDwtICJsZXNzZXJfdGhhbl80IiAjIGFzc2lnbiA1dGggY29sdW1uDQogICAgfQ0KICB9DQp9KQ0KDQpkZlssNV0gPC0gTlVMTA0KDQpgYGANCg0KYGBge3J9DQojIGFmdGVyIHZlY3Rvcml6YXRpb24gYW5kIHByZS1hbGxvY2F0aW9uDQpvdXRwdXQgPC0gY2hhcmFjdGVyIChucm93KGRmKSkgIyBpbml0aWFsaXplIG91dHB1dCB2ZWN0b3IgZm9yIHZlY3Rvcml6YXRpb24NCg0KIyBsb29wIHdpdGggcHJlYWxsb2NhdGVkIHZlY3Rvcg0Kc3lzdGVtLnRpbWUoew0KICBmb3IgKGkgaW4gMTpucm93KGRmKSkgew0KICAgIGlmICgoZGZbaSwgJ2NvbDEnXSArIGRmW2ksICdjb2wyJ10gKyBkZltpLCAnY29sMyddICsgZGZbaSwgJ2NvbDQnXSkgPiA0KSB7DQogICAgICBvdXRwdXRbaV0gPC0gImdyZWF0ZXJfdGhhbl80IiAjbG9vcGluZyB0aHJvdWdoIHRoZSB2ZWN0b3IgYnV0IG5vdCBhIGRhdGFmcmFtZQ0KICAgIH0gZWxzZSB7DQogICAgICBvdXRwdXRbaV0gPC0gImxlc3Nlcl90aGFuXzQiICNsb29waW5nIHRocm91Z2ggdGhlIHZlY3RvciBidXQgbm90IGEgZGF0YWZyYW1lDQogICAgfQ0KICB9DQogIA0KIyBhY3R1YWwgdmVjdG9yaXphdGlvbjogaW4gcGxhY2Ugb2Ygcm93LWJ5LXJvdyB0cmFuc2FjdGlvbnMgd2UgbWFuaXB1bGF0ZSB0aGUgc2luZ2xlIHZlY3RvciBvbmx5LiAgDQpkZiRvdXRwdXQgPC0gb3V0cHV0IA0KfQ0KKQ0KDQpkZlssNV0gPC0gTlVMTA0KYGBgDQoNCiMjIyMgKlBsYWNlIElGIHN0YXRlbWVudHMgKGV4cHJlc3Npb25zKSBvdXRzaWRlIHRoZSBsb29wLioNCg0KRXhhbXBsZXMgYXJlIHRha2VuIGZyb20gW2hlcmVdKGh0dHBzOi8vd3d3LnItYmxvZ2dlcnMuY29tL3N0cmF0ZWdpZXMtdG8tc3BlZWR1cC1yLWNvZGUvKQ0KDQpgYGB7cn0NCiMgaW5pdGlhbGl6ZSBvdXRwdXQgdmVjdG9yIGZvciB2ZWN0b3JpemF0aW9uDQpvdXRwdXQgPC0gY2hhcmFjdGVyIChucm93KGRmKSkNCg0KIyB0aGUgZXhwcmVzc2lvbiBpbiBJRiBzdGF0ZW1lbnQNCmNvbmRpdGlvbiA8LSAoZGYkY29sMSArIGRmJGNvbDIgKyBkZiRjb2wzICsgZGYkY29sNCkgPiA0ICAjIGNvbmRpdGlvbiBjaGVjayBvdXRzaWRlIHRoZSBsb29wDQpzeXN0ZW0udGltZSh7DQogIGZvciAoaSBpbiAxOm5yb3coZGYpKSB7DQogICAgaWYgKGNvbmRpdGlvbltpXSkgew0KICAgICAgb3V0cHV0W2ldIDwtICJncmVhdGVyX3RoYW5fNCINCiAgICB9IGVsc2Ugew0KICAgICAgb3V0cHV0W2ldIDwtICJsZXNzZXJfdGhhbl80Ig0KICAgIH0NCiAgfQ0KICBkZiRvdXRwdXQgPC0gb3V0cHV0DQp9KQ0KDQpkZlssNV0gPC0gTlVMTA0KYGBgDQoNCg0KIyMjIyAqVGhlIExPT1Agb25seSBmb3IgVHJ1ZSBjb25kaXRpb25zKg0KDQpFeGFtcGxlcyBhcmUgdGFrZW4gZnJvbSBbaGVyZV0oaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vc3RyYXRlZ2llcy10by1zcGVlZHVwLXItY29kZS8pDQoNCmBgYHtyfQ0KIyBpbml0aWFsaXplIG91dHB1dCB2ZWN0b3IgZm9yIHZlY3Rvcml6YXRpb24NCm91dHB1dCA8LSBjaGFyYWN0ZXIgKG5yb3coZGYpKQ0KDQojIHRoZSBleHByZXNzaW9uIGluIElGIHN0YXRlbWVudA0KY29uZGl0aW9uIDwtIChkZiRjb2wxICsgZGYkY29sMiArIGRmJGNvbDMgKyBkZiRjb2w0KSA+IDQgICMgY29uZGl0aW9uIGNoZWNrIG91dHNpZGUgdGhlIGxvb3ANCg0Kc3lzdGVtLnRpbWUoew0KICBmb3IgKGkgaW4gKDE6bnJvdyhkZikpW2NvbmRpdGlvbl0pIHsgICMgcnVuIGxvb3Agb25seSBmb3IgdHJ1ZSBjb25kaXRpb25zDQogICAgaWYgKGNvbmRpdGlvbltpXSkgew0KICAgICAgb3V0cHV0W2ldIDwtICJncmVhdGVyX3RoYW5fNCINCiAgICB9IGVsc2Ugew0KICAgICAgb3V0cHV0W2ldIDwtICJsZXNzZXJfdGhhbl80Ig0KICAgIH0NCiAgfQ0KIyBhY3R1YWwgdmVjdG9yaXphdGlvbjogaW4gcGxhY2Ugb2Ygcm93LWJ5LXJvdyB0cmFuc2FjdGlvbnMgd2UgbWFuaXB1bGF0ZSB0aGUgc2luZ2xlIHZlY3RvciBvbmx5LiAgICANCmRmJG91dHB1dCA8LSBvdXRwdXQNCn0pDQoNCmRmWyw1XSA8LSBOVUxMDQpgYGANCg0KIyMjIyAqVXNlIGlmZWxzZSgpIHdoZW5ldmVyIHBvc3NpYmxlKg0KDQpFeGFtcGxlcyBhcmUgdGFrZW4gZnJvbSBbaGVyZV0oaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vc3RyYXRlZ2llcy10by1zcGVlZHVwLXItY29kZS8pDQoNCllvdSBjYW4gbWFrZSB0aGlzIGxvZ2ljIG11Y2ggc2ltcGxlciBhbmQgZmFzdGVyIGJ5IHVzaW5nIHRoZSBpZmVsc2UoKSBzdGF0ZW1lbnQuIA0KDQpMb29rcyBsaWtlIHRoaXMgaXMgZ29pbmcgdG8gYmUgYSBoaWdobHkgcHJlZmVycmVkIG9wdGlvbiB0byBzcGVlZCB1cCBzaW1wbGUgbG9vcHMuDQoNCmBgYHtyfQ0Kc3lzdGVtLnRpbWUoew0KICBvdXRwdXQgPC0gaWZlbHNlICgoZGYkY29sMSArIGRmJGNvbDIgKyBkZiRjb2wzICsgZGYkY29sNCkgPiA0LCAiZ3JlYXRlcl90aGFuXzQiLCAibGVzc2VyX3RoYW5fNCIpDQogIGRmJG91dHB1dCA8LSBvdXRwdXQNCn0pDQoNCmRmWyw1XSA8LSBOVUxMDQpgYGANCg0KIyMjIyAqVXNpbmcgd2hpY2goKSoNCg0KRXhhbXBsZXMgYXJlIHRha2VuIGZyb20gW2hlcmVdKGh0dHBzOi8vd3d3LnItYmxvZ2dlcnMuY29tL3N0cmF0ZWdpZXMtdG8tc3BlZWR1cC1yLWNvZGUvKQ0KDQpgYGB7cn0NCg0Kc3lzdGVtLnRpbWUoew0KICB3YW50ID0gd2hpY2gocm93U3VtcyhkZikgPiA0KQ0KICBvdXRwdXQgPSByZXAoImxlc3MgdGhhbiA0IiwgdGltZXMgPSBucm93KGRmKSkNCiAgb3V0cHV0W3dhbnRdID0gImdyZWF0ZXIgdGhhbiA0Ig0KICBkZiRvdXRwdXQgPC0gb3V0cHV0DQp9KSANCmRmWyw1XSA8LSBOVUxMDQpgYGANCg0KIyMjIyBVc2UgYXBwbHkgZmFtaWx5IG9mIGZ1bmN0aW9ucyBpbnN0ZWFkIG9mIGZvci1sb29wcw0KDQpFeGFtcGxlcyBhcmUgdGFrZW4gZnJvbSBbaGVyZV0oaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vc3RyYXRlZ2llcy10by1zcGVlZHVwLXItY29kZS8pDQoNCmBgYHtyfQ0KIyBhcHBseSBmYW1pbHkNCnN5c3RlbS50aW1lKHsNCiAgbXlmdW5jIDwtIGZ1bmN0aW9uKHgpIHsNCiAgICBpZiAoKHhbJ2NvbDEnXSArIHhbJ2NvbDInXSArIHhbJ2NvbDMnXSArIHhbJ2NvbDQnXSkgPiA0KSB7DQogICAgICAiZ3JlYXRlcl90aGFuXzQiDQogICAgfSBlbHNlIHsNCiAgICAgICJsZXNzZXJfdGhhbl80Ig0KICAgIH0NCiAgfQ0KICBvdXRwdXQgPC0gYXBwbHkoZGZbLCBjKDE6NCldLCAxLCBGVU49bXlmdW5jKSAgIyBhcHBseSAnbXlmdW5jJyBvbiBldmVyeSByb3cNCiAgZGYkb3V0cHV0IDwtIG91dHB1dA0KfSkNCmRmWyw1XSA8LSBOVUxMDQpgYGANCg0KIyMjIyBVc2UgYnl0ZSBjb2RlIGNvbXBpbGF0aW9uIGZvciBmdW5jdGlvbnMgY21wZnVuKCkNCg0KV2Ugd2lsbCB1c2UgaW5pdGlhbCBkYXRhZnJhbWUgYXMgdGhlIGlucHV0IGFuZCB0aGUgaW5pdGlhbCBGT1IgbG9vcCAoYXMgaW4gdGhlIGZpcnN0IGV4YW1wbGUpLg0KDQpgYGB7cn0NCg0KZiA8LSBmdW5jdGlvbihkZil7DQogICBmb3IgKGkgaW4gMTpucm93KGRmKSkgeyAjIGZvciBldmVyeSByb3cNCiAgICBpZiAoKGRmW2ksICdjb2wxJ10gKyBkZltpLCAnY29sMiddICsgZGZbaSwgJ2NvbDMnXSArIGRmW2ksICdjb2w0J10pID4gNCkgeyAjIGNoZWNrIGlmID4gNA0KICAgICAgZGZbaSwgNV0gPC0gImdyZWF0ZXJfdGhhbl80IiAjIGFzc2lnbiA1dGggY29sdW1uDQogICAgfSBlbHNlIHsNCiAgICAgIGRmW2ksIDVdIDwtICJsZXNzZXJfdGhhbl80IiAjIGFzc2lnbiA1dGggY29sdW1uDQogICAgfQ0KICB9DQp9DQoNCmxpYnJhcnkoY29tcGlsZXIpDQoNCmcgPC0gY21wZnVuKGYpDQoNCnN5c3RlbS50aW1lKA0KICBnKGRmKQ0KKQ0KZGZbLDVdIDwtIE5VTEwNCmBgYA0KDQoNCg0KDQoNCg0K