R is a popular language among academics and data scientists. While Python is considerably more popular, R is good for what it does: data wrangling, statistics, visualization and machine learning. Follow along and learn the 23 most advanced R Interview Questions and Answers (solved with code) to practice before your next Data Science and Machine Learning interview.
These components are the function’s body(), formals() and environment().
The formals(), the list of arguments that control how you call the function.
The body(), the code inside the function.
The environment(), the data structure that determines how the function finds the values associated with the names.
While the formals and body are specified explicitly when you create a function, the environment is specified implicitly, based on where you defined the function. The function environment always exists, but it is only printed when the function isn’t defined in the global environment.
However, there is one exception to the rule that functions have three components. Primitive functions, like sum(), call C code directly with .Primitive() and contain no R code. Therefore, their formals(), body(), and environment() are all NULL.
Using the dplyr tidyverse package, we can create new data frame columns using mutate and then use case_when to implement conditional logic.`
For example, let's suppose that we want to add a text field that describes a value. First, let’s set up some simple example data in a data frame with one column named vals:
df <- data.frame(vals = 1:5)Now let’s implement logic that creates a field called new_vals.
vals is less than or equal to 2, we’ll return 2 or less.vals is between greater than 2 and less than or equal to 4, we’ll return 2 to 44:df %>%
mutate(new_vals = case_when(vals <= 2 ~ "2 or less",
vals > 2 & vals <= 4 ~ "2 to 4",
TRUE ~ "over 4"))
#> vals new_vals
#> 1 1 2 or less
#> 2 2 2 or less
#> 3 3 2 to 4
#> 4 4 2 to 4
#> 5 5 over 4The enclosing is the environment where the function was created. For example, if we create a function at the command line or load it in a package its enclosing environment is the global workspace. If we define a function f() inside another function g() its enclosing environment is the environment inside g().
The enclosing environments are important because a function can use variables in the enclosing environment to share information with other functions or with other invocations of itself.
The parent environment, on the other hand, is defined when we invoke a function. If we invoke lm() at the command line its parent environment is the global workspace, if we invoke it inside a function f() then its parent environment is the environment inside f().
Parent environments are important because things like model formulas need to be evaluated in the environment the function was called from since that’s where all the variables will be available.
f2 and f3 differ from f1?Consider:
letters <- c("a", "b", "c", "d")
f1 <- factor(letters)
levels(f1) <- rev(levels(f1))
f2 <- rev(factor(letters))
f3 <- factor(letters, levels = rev(letters))f1 the underlying integer values stay the same, but the levels are changed, making it look like the data has changed.# Before change
f1 <- factor(letters)
f1
#> [1] a b c d
#> Levels: a b c d
# After change
levels(f1) <- rev(levels(f1))
f1
#> [1] d c b a
#> Levels: d c b af2 the order of the factor elements is being reversed but the levels stay the same. f2 <- rev(factor(letters)
f2
#> [1] d c b a
#> Levels: a b c dFor f3 the order of the factor levels is being reversed but the elements stay the same.
f3 <- factor(letters, levels = rev(letters))
f3
#> [1] a b c d
#> Levels: d c b aTherefore, for f2 and f3 either the order of the factor elements or its levels are being reversed. For f1 both transformations are occurring.
switch() with numeric values?In switch(n, ...), if n is numeric, it will return the nth argument from .... This means that if n = 1, switch() will return the first argument in ..., if n = 2, the second, and so on. For example,
switch(1, "apple", "banana", "cantaloupe")
#> [1] "apple"
switch(2, "apple", "banana", "cantaloupe")
#> [1] "banana"If you use a non-integer number for the first argument of switch(), it will ignore the non-integer part.
switch(1.2, "apple", "banana", "cantaloupe")
#> [1] "apple"
switch(2.8, "apple", "banana", "cantaloupe")
#> [1] "banana"In other words, switch() truncates the numeric value, it does not round to the nearest integer.
next statement in R?A next statement is useful when we want to skip the current iteration of a loop without terminating it. On encountering next, the R parser skips further evaluation and starts the next iteration of the loop.
For example, the code below
x <- 1:5
for (val in x) {
if (val == 3){
next
}
print(val)
} Provides the following output:
[1] 1
[1] 2
[1] 4
[1] 5In the above example, we use the next statement inside a condition to check if the value is equal to 3. If the value is equal to 3, the current evaluation stops (value is not printed) but the loop continues with the next iteration. The output reflects this situation.
[ ] and [[ ]] for accessing the elements of a list or dataframe? The significant differences between the two methods are the class of the objects they return when used for extraction and whether they may accept a range of values, or just a single value during an assignment.
The [] method returns objects of class list or data frame. Also, the [] operator may be used to access a range of slots in a list or columns in a data frame.
The [[]] method returns objects whose class is determined by the type of their values. As an operator, [[]] is limited to accessing a single slot or column.
with() function and why is it good?with evaluate an R expression in an environment constructed from data, possibly modifying (a copy of) the original data.
Is recommended to use with to save typing and make the code clearer. The more frequently we would need to re-type our data frame name for a single command (and the longer your data frame name is), the greater the benefit of using with. For example, consider the mtcars dataset.
# without with(), we would be stuck here:
z = mean(mtcars$cyl + mtcars$disp + mtcars$wt)
# using with(), we can clean this up:
z = with(mtcars, mean(cyl + disp + wt))We could also find with very useful when we need to use the results of another function, for example rle. If we only need the results once, then his example with(rle(data), lengths[values > 1]) lets us use the rle(data) results anonymously.
Consider:
x = list(1, 2, 3, 4)
x2 = list(1:4)A list is an object that can contain any other class as each element. So we can have a list where the first element could be a character vector, the second is a data frame, etc. This is because R lists are very much like a hash map data structure in that each index value can be associated with any object.
In this case, you have created two different lists that's why we get different results.
x is a list that has four vectors, each of length 1.> x = list(1,2,3,4)
> x
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
[[4]]
[1] 4x2 is a list that has 1 vector of length 4. > x2 = list(1:4)
> x2
[[1]]
[1] 1 2 3 4join dataframes using SQL style joins (inner, outer, left, right) in R?We can perform this operation using the merge function and its optional parameters:
Inner join or natural join: merge(df1, df2) joins the frames by common variable names, but it's recommended to specify merge(df1, df2, by = "feature") to make sure that you were matching on only the fields we desired. We could also use the by.x and by.y parameters if the matching variables have different names in the different data frames.
Full outer join: merge(x = df1, y = df2, by = "feature", all = TRUE).
Left outer: merge(x = df1, y = df2, by = "feature", all.x = TRUE).
Right outer: merge(x = df1, y = df2, by = "feature", all.y = TRUE).
The most general way to handle this is to return a list object. For example, if you have an integer foo and a vector of strings bar in your function, you could create a list that combines these items:
foo <- 12
bar <- c("a", "b", "e")
newList <- list("integer" = foo, "names" = bar)Then return this list. After calling your function, you can then access each of these with newList$integer or newList$names.
Lists or matrices that comply with the restrictions that the data frame structure imposes can be coerced into data frames with the as.data.frame() function.
A data frame is similar to the structure of a matrix, where the columns can be of different types. There are also similarities with lists, where each column is an element of the list and each element has the same length. Any matrices or lists that we want to convert need to satisfy these restrictions.
For example, the matrix A can be converted because each column contains values of the numeric data type.
A = matrix(c(2, 4, 3, 1, 5, 7), nrow=2, ncol=3, byrow = TRUE)
A_df <- as.data.frame(A)
A
#> [,1] [,2] [,3]
#> [1,] 2 4 3
#> [2,] 1 5 7The same procedures follow for lists, except this time we may assign names to the list to get a better-looking result.
number = c(2, 3, 5)
string = c("aa", "bb", "cc")
boolean = c(TRUE, FALSE, TRUE)
x = list("n" = number, "s" = string, "b" = boolean, "i" = 3)
x_df <- as.data.frame(x, col.names = (names(x)))
x_df
#> n s b i
#> 1 2 aa TRUE 3
#> 2 3 bb FALSE 3
#> 3 5 cc TRUE 3While both Python and R can accomplish many of the same data tasks, they each have their own unique strengths. If we know you’ll be spending lots of time on certain data tasks, we might want to prioritize the language that excels at those tasks.
Is better to use Python for:
On other hand, is better to use R for:
R is a specific language that is used for statistical modelling, the R libraries are robust and it is the primary tool for creating statistical tools for data science. This gives R an essential advantage over other programming languages like Python.
R was developed with a focus on statistics, so R has more data analysis functionality built-in, while Python relies on packages.
In R, the dashboard creation is easy using Shiny. This enables people without much technical experience to create and publish dashboards to share with their colleagues. Python's Dash is an alternative, but not as mature.
= and <- assignment operators in R?The difference in assignment operators is clearer when you use them to set an argument value in a function call. For example:
median(x = 1:10)
x
#> Error: object 'x' not found In this case, x is declared within the scope of the function, so it does not exist in the user workspace. Now if we use the operator <-:
median(x <- 1:10)
x
#> [1] 1 2 3 4 5 6 7 8 9 10 In this case, x is declared in the user workspace, so we can use it after the function call has been completed.
Furthermore, = and <- have slightly different operator precedence (which determines the order of evaluation when they are mixed in the same expression). In fact, ?Syntax in R gives the following operator precedence table, from highest to lowest:
‘-> ->>’ rightwards assignment
‘<- <<-’ assignment (right to left)
‘=’ assignment (right to left)%>% do in R?What the operator does is to pass the left hand side of the operator to the first argument of the right hand side of the operator. In the following example, the data frame iris gets passed to head():
library(magrittr)
iris %>% head()
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 5.1 3.5 1.4 0.2 setosa
#> 2 4.9 3.0 1.4 0.2 setosa
#> 3 4.7 3.2 1.3 0.2 setosa
#> 4 4.6 3.1 1.5 0.2 setosa
#> 5 5.0 3.6 1.4 0.2 setosa
#> 6 5.4 3.9 1.7 0.4 setosaThe infix operator %>% is not part of base R, but is in fact defined by the package magrittr and is heavily used by dplyr. It works like a pipe in Unix.
When applying an operation to two vectors that require them to be the same length, R automatically recycles, or repeats, the shorter one, until it is long enough to match the longer one. This is called element recycling.
Example:
c(1,2,4) + c(6,0,9,20,22)
#> [1] 7 2 13 21 24
#> Warning message:
#> In c(1, 2, 4) + c(6, 0, 9, 20, 22) :
#> longer object length is not a multiple of shorter object lengthThe shorter vector was recycled, so the operation was taken to be as follows:
c(1,2,4,1,2) + c(6,0,9,20,22)apply, lapply and sapply? apply is used when you want to apply a function to the rows or columns of a matrix (and higher-dimensional analogues); is not generally advisable for data frames as it will coerce to a matrix first. For example:M <- matrix(seq(1,16), 4, 4)
M
#> [,1] [,2] [,3] [,4]
#> [1,] 1 5 9 13
#> [2,] 2 6 10 14
#> [3,] 3 7 11 15
#> [4,] 4 8 12 16
apply(M, 1, min)
#> [1] 1 2 3 4
apply(M, 2, max)
#> [1] 4 8 12 16lapply is used when you want to apply a function to each element of a list in turn and get a list back. Example:x <- list(a = 1, b = 1:3, c = 10:100)
lapply(x, FUN = length)
#> $a
#> [1] 1
#>
#> $b
#> [1] 3
#>
#> $c
#> [1] 91sapply is used when you want to apply a function to each element of a list in turn, but you want a vector back, rather than a list. x <- list(a = 1, b = 1:3, c = 10:100)
sapply(x, FUN = length)
#> a b c
#> 1 3 911 == "1" true? Why is -1 < FALSE true? Why is "one" < 2 false?These comparisons are carried out by operator-functions (==, <), which coerce their arguments to a common type. In the examples above, these types will be character, double and character:
1 will be coerced to "1", FALSE is represented as 0, and -1 < 0,2 turns into "2" and numbers precede letters in lexicographic order (may depend on locale).read.table() function?factor() function?Prepare for AI developer and engineer interviews with 19 answered OpenClaw questions covering Gateway architecture, channels, agent workspaces, memory, MCP, model failover, multi-agent routing, security, sandboxing, approvals, and remote operations....
Prepare for AI agent developer interviews with 15 Model Context Protocol (MCP) questions covering tools, resources, prompts, JSON-RPC, transports, roots, sampling, security, and practical MCP server design....
Amazone runs the internet as we know it. Amazon Web Services (AWS) offers a comprehensive suite of machine learning (ML) services that cater to various needs and expertise levels. Follow along and learn the 23 most common AWS machine-learning intervi...