Skip to content

R Programming Interview Questions & Answers

All 200 unique questions in one place — 58 easy, 97 medium, 45 hard — grouped by topic.

Practise by topic

Solved overallStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

What is R and why is it popular for data analysis?

Save to ▾
Show answer
R is an open-source language and environment built for statistics, data analysis and graphics. It is popular because of CRAN, which hosts over 20,000 packages, strong visualization with ggplot2 and built-in statistical functions. Analysts, biostatisticians and data scientists use it for reporting, modelling and research. For example, a pharma analytics team may use R for clinical trial analysis because many statistical methods are first released as R packages.
02

What are the atomic data types in R?

Save to ▾
Show answer
R has six atomic types: logical (TRUE/FALSE), integer (5L), double or numeric (3.14), character ('text'), complex (2+3i) and raw (bytes). typeof() returns the internal type while class() returns the class attribute used for method dispatch. For example, typeof(5) is 'double' but typeof(5L) is 'integer'. Knowing types matters because mixing them in one vector triggers coercion to the most flexible type.
03

What is the difference between <- and = for assignment in R?

Save to ▾
Show answer
Both assign values at the top level, but <- is the conventional assignment operator in R style guides, while = is mainly used to pass named arguments inside function calls. For example, mean(x = 1:10) passes an argument and does not create x in the workspace, but mean(x <- 1:10) creates x as a side effect. Using <- for assignment keeps code readable and avoids confusion between assignment and argument matching.
04

How do you install and load a package, and what is the difference between library() and require()?

Save to ▾
Show answer
install.packages() downloads from CRAN once; library() loads it in every session. library() throws an error if the package is missing, while require() returns FALSE with a warning, so require() suits conditional checks. install.packages('dplyr') library(dplyr) if (!require('data.table')) { install.packages('data.table') library(data.table) }
05

What is a factor in R and when would you use one?

Save to ▾
Show answer
A factor stores categorical data as integer codes with a set of labels called levels. Factors are used for variables like gender, city or rating, and modelling functions such as lm() turn them into dummy variables automatically. Ordered factors, created with factor(x, levels = c('Low', 'Medium', 'High'), ordered = TRUE), support comparisons. A common pitfall is as.numeric() on a numeric factor, which returns codes; use as.numeric(as.character(f)) instead.
06

A numeric column in your data has been read as character. How do you fix it?

Save to ▾
Show answer
I first find the offending values, for example with unique(df$amount[is.na(as.numeric(df$amount))]), which reveals entries like '1,200', 'NA ' or '-'. Then I clean them, removing commas with gsub(',', '', x) and spaces with trimws(), and convert with as.numeric(). With readr I can also pass na = c('', '-', 'NA') and col_types so the column is parsed correctly at load time instead of being fixed later.
07

How do you create sequences and repeated values in R?

Save to ▾
Show answer
seq(), rep() and the colon operator build most vectors. 1:10 # integers 1 to 10 seq(0, 100, by = 10) # 0, 10, ..., 100 seq(1, 2, length.out = 5) # 5 evenly spaced values rep(c('A', 'B'), times = 3) # A B A B A B rep(c('A', 'B'), each = 2) # A A B B seq_along(c('x', 'y', 'z')) # 1 2 3, safe for empty vectors seq_len(0) # empty, unlike 1:0
08

How do you handle missing values in calculations in R?

Save to ▾
Show answer
Most summary functions return NA if any value is missing, so pass na.rm = TRUE or remove NAs first. x <- c(10, NA, 30, 40) mean(x) # NA mean(x, na.rm = TRUE) # 26.67 sum(is.na(x)) # count missing: 1 x[!is.na(x)] # drop NAs x[is.na(x)] <- median(x, na.rm = TRUE) # impute df[complete.cases(df), ] # rows with no NA
09

Why did you choose to learn R?

Save to ▾
Show answer
I chose R because I enjoy working with data and statistics, and R is designed exactly for that. During my coursework I used it for a project analysing student performance, where dplyr and ggplot2 helped me move from raw data to clear insights quickly. I like that results are reproducible with R Markdown. I am also learning SQL and basic Python, so I can work comfortably in a mixed team and pick the right tool for each task.
10

How do you manage working directories and file paths in an R project?

Save to ▾
Show answer
getwd() shows and setwd() changes the working directory, but a hardcoded setwd() breaks on other machines. RStudio projects with the here package build paths relative to the project root. getwd() library(here) sales <- read.csv(here('data', 'sales.csv')) write.csv(summary_df, here('output', 'summary.csv'), row.names = FALSE) file.exists(here('data', 'sales.csv')) list.files(here('data'), pattern = 'csv$')
11

Your analysis gives slightly different results every time you run it. How do you make it reproducible?

Save to ▾
Show answer
Functions like sample(), rnorm() and random train-test splits depend on the random number generator. I call set.seed(42) at the start of the script so the same random sequence is generated every run, which lets reviewers reproduce results. For parallel code I use reproducible streams, for example future with seed = TRUE. I also record the R version, because the default sampling algorithm changed in R 3.6.0 and can change results between versions.
12

Explain the difference between NA, NULL and NaN in R.

Save to ▾
Show answer
NA means a missing value and has a type, such as NA_integer_ or NA_character_. NULL means the absence of an object, has length 0 and disappears when combined with c(). NaN means not a number, the result of undefined maths like 0/0. is.na() returns TRUE for both NA and NaN, while is.nan() is TRUE only for NaN. For example, length(c(1, NULL, 3)) is 2 but length(c(1, NA, 3)) is 3.
13

What is type coercion in R and how can it cause bugs?

Save to ▾
Show answer
Coercion is the automatic conversion of values to a common type when they are combined in an atomic vector. The order is logical, then integer, then double, then character. So c(1, 'a', TRUE) becomes the character vector '1', 'a', 'TRUE'. Explicit conversion uses as.numeric(), as.character() and similar functions. A common bug is a numeric column with one stray text value, which turns the whole column into character and breaks calculations.
14

What is vectorization in R and why does it matter?

Save to ▾
Show answer
Vectorization means applying an operation to a whole vector at once instead of looping over elements. Most R functions, like +, sqrt() and ifelse(), are vectorized and implemented in C, so they are much faster than R-level for loops. For example, prices * 1.18 adds 18 percent GST to every price in one step. Writing vectorized code is the first optimization an R developer should try before parallel processing or Rcpp.
15

What is the recycling rule in R?

Save to ▾
Show answer
When two vectors of different lengths are used in an operation, R repeats the shorter one to match the longer one. For example, c(1, 2, 3, 4) + c(10, 20) gives 11, 22, 13, 24. If the longer length is not a multiple of the shorter, R gives a warning but still computes. Recycling is convenient for scalars, but silent recycling of mismatched vectors is a frequent source of wrong results in analysis code.
16

Your R script works on your laptop but fails on a colleague's machine with 'could not find function'. What do you check?

Save to ▾
Show answer
First I check that the package providing the function is installed and loaded with library() at the top of the script, not only in my interactive session. Then I compare R and package versions using sessionInfo(), because functions get renamed or deprecated. To prevent this, I use renv to snapshot exact package versions into a lockfile, so the colleague runs renv::restore() and gets the same environment. Namespacing calls like dplyr::filter() also avoids masking conflicts.
17

Reading a 2 GB CSV file with read.csv() is very slow. What would you do?

Save to ▾
Show answer
read.csv() is single-threaded and guesses types slowly. I would switch to data.table::fread() or readr::read_csv(), which are many times faster and multi-threaded. I would read only the needed columns with the select argument and set column types explicitly. If the file is reused, I convert it once to a binary format like Parquet with the arrow package, which loads in seconds and supports reading just a subset of columns.
18

How do you find out why your R code is slow?

Save to ▾
Show answer
Measure before optimizing. system.time() gives total time, bench::mark() compares alternatives, and profvis shows which lines consume time and memory. system.time(result <- slow_function(df)) bench::mark( loop = sum_loop(x), vec = sum(x) ) library(profvis) profvis({ out <- clean_data(raw) model <- fit_model(out) })
19

How would you compare R and Python for a data role?

Save to ▾
Show answer
R is strongest for statistics, exploratory analysis, visualization and reproducible reporting, with mature packages for biostatistics, econometrics and survey analysis. Python is a general-purpose language that is stronger for production software, deep learning and web integration. Many teams use both: R for analysis and reporting, Python for pipelines and deployment. In an interview, avoid language wars and explain that the choice depends on the team's stack, the problem and who maintains the code.
20

Tell me about a time you automated a manual report.

Save to ▾
Show answer
Situation: my team spent two days every month building a sales report in Excel. Task: I was asked to reduce the effort. Action: I wrote an R script that pulled data from the database with DBI, cleaned it with dplyr, created charts with ggplot2 and rendered a Quarto report scheduled through cron. Result: the report ran in ten minutes, copy-paste errors disappeared and the team used the saved time for deeper analysis.
21

Explain environments and lexical scoping in R.

Save to ▾
Show answer
An environment is a collection of name-value bindings with a pointer to a parent environment. R uses lexical scoping: when a function looks up a variable, it searches its own environment, then the environment where it was defined, up through the global environment and attached packages. So a function defined inside another can read the outer function's variables, which enables closures. The <<- operator modifies a binding in a parent environment and should be used sparingly.
22

What is lazy evaluation in R?

Save to ▾
Show answer
R evaluates function arguments lazily, only when they are first used inside the function body. Arguments are stored as promises holding the expression and its environment. For example, f <- function(x, y) x * 2 works with f(5, stop('error')) because y is never touched. Lazy evaluation enables defaults that depend on other arguments and non-standard evaluation in dplyr, but it can surprise you when creating closures in a loop, which force() fixes.
23

What does copy-on-modify mean in R and how does it affect performance?

Save to ▾
Show answer
When you assign y <- x, both names point to the same object, and R makes a copy only when one of them is modified. tracemem() shows when copies happen. This is why growing a vector in a loop with x <- c(x, value) is slow, because each step can copy the whole vector. Preallocating with vector('numeric', n), using vectorized functions or data.table's modify-by-reference avoids repeated copies and memory spikes.
24

Your R session runs out of memory while processing a large dataset. What steps do you take?

Save to ▾
Show answer
I check object sizes with lobstr::obj_size() and remove large intermediates with rm() followed by gc(). I load only the needed columns and use data.table, which modifies by reference without copies. For data larger than RAM, I push computation into a database through dbplyr, or use arrow with Parquet files so filters and aggregations run before data enters R memory. Chunked reading with readr::read_csv_chunked() is another option for one-pass jobs.
25

What are the differences between S3, S4 and R6 classes?

Save to ▾
Show answer
S3 is R's simplest object system: an object is a list with a class attribute, and generic functions like print() dispatch on it through UseMethod(). S4 adds formal class definitions with setClass(), typed slots and validity checks, and is common in Bioconductor. R6, from a package, provides reference semantics with mutable objects and encapsulated methods, similar to classes in Python or Java, and is used inside Shiny. Most analysis code needs only S3.
26

What is the difference between a vector and a list in R?

Save to ▾
Show answer
An atomic vector holds elements of a single type, such as all numbers or all strings, while a list can hold elements of any type, including other lists, data frames or functions. c(1, 'a') coerces to character, but list(1, 'a', TRUE) keeps each type. Lists are used for nested data such as JSON responses and for returning multiple results from a function, which is why model objects like lm() output are lists.
27

What is a data frame in R?

Save to ▾
Show answer
A data frame is a list of equal-length vectors, where each vector is a column with its own type. It is R's main structure for tabular data, similar to a spreadsheet or SQL table. str(df) shows column types, nrow() and ncol() give dimensions and summary() gives quick statistics. Tibbles from the tidyverse are modern data frames that print neatly, never convert strings to factors and do not partially match column names.
28

How is a matrix different from a data frame?

Save to ▾
Show answer
A matrix is a two-dimensional atomic vector, so all elements share one type, usually numeric. A data frame allows a different type per column. Matrices are faster for linear algebra, such as %*% multiplication, solve() and distance calculations, while data frames suit mixed real-world data. For example, the output of cor() is a matrix, while customer records with names, dates and amounts belong in a data frame. as.matrix() and as.data.frame() convert between them.
29

Show different ways to index vectors and data frames in R.

Save to ▾
Show answer
R indexes from 1 and supports positive, negative, logical and name-based indexing. x <- c(a = 10, b = 20, c = 30, d = 40) x[2] # 20 x[-1] # drop first x[c('a', 'd')] # by name x[x > 15] # logical filter which(x > 15) # positions df[df$age > 30, c('name', 'city')] df[order(-df$salary), ][1:5, ] # top 5 salaries
30

Dates in your file look like 25/12/2025 and as.Date() returns NA. What is wrong and how do you fix it?

Save to ▾
Show answer
Indian files often store dates as dd/mm/yyyy, but as.Date() expects yyyy-mm-dd by default, so values become NA. I specify the format, as.Date(x, format = '%d/%m/%Y'), or use lubridate::dmy(x), which handles different separators automatically. Then I count NAs before and after conversion to confirm nothing failed silently. If the column came from Excel as serial numbers, I use as.Date(x, origin = '1899-12-30') instead.
31

What is an array in R?

Save to ▾
Show answer
An array is a multi-dimensional generalization of a matrix, created with array(data, dim = c(rows, cols, layers)). All elements share one type. For example, array(1:24, dim = c(2, 3, 4)) has four layers of 2 by 3 matrices, and you index with arr[1, 2, 3]. Arrays are used for image data, simulation outputs and time by region by product cubes, though for business analysis long-format data frames are usually easier to work with.
32

How do you explain technical results to non-technical managers?

Save to ▾
Show answer
I start with the business question and the answer in one sentence, then show one or two clear charts instead of tables of coefficients. For example, in a college project on customer churn, I said that customers with more than three complaints were twice as likely to leave, showed a simple bar chart and suggested a follow-up call process. I keep technical details in an appendix and invite questions so managers can decide confidently.
33

What is the difference between [ ], [[ ]] and $ when subsetting?

Save to ▾
Show answer
For lists, [ ] returns a sub-list, while [[ ]] and $ return the element itself. So lst['a'] is a list of length one and lst[['a']] is the value. $ allows partial name matching and cannot take a variable, while [[ ]] accepts a string variable like lst[[col]]. On data frames, df['x'] returns a one-column data frame, and df[['x']] or df$x returns a vector. Think of [ ] as the train car and [[ ]] as its contents.
34

What does drop = FALSE do when subsetting?

Save to ▾
Show answer
When you subset a single column or row from a matrix or base data frame with [ ], R simplifies the result to a vector by default. Writing m[, 1, drop = FALSE] keeps it as a matrix or data frame. This matters inside functions, because code expecting a data frame breaks when a selection leaves only one column. Tibbles never drop dimensions, which is one reason developers prefer them in reusable code and packages.
35

Explain the apply family of functions in R.

Save to ▾
Show answer
apply() works over rows or columns of a matrix, lapply() applies a function to each element of a list and returns a list, sapply() simplifies the result to a vector or matrix when possible, vapply() is like sapply() but requires a declared output type, making it safer, and mapply() iterates over several vectors in parallel. tapply() applies a function by groups. For example, sapply(df, class) returns the class of each column.
36

How do you create, modify and combine lists in R?

Save to ▾
Show answer
Lists are built with list(), modified by name and combined or flattened when needed. emp <- list(name = 'Asha', skills = c('R', 'SQL'), exp = 3) emp$city <- 'Pune' # add element emp[['exp']] <- 4 # update emp$skills <- NULL # remove names(emp) parts <- lapply(1:3, function(i) data.frame(id = i, sq = i^2)) do.call(rbind, parts) # combine data frames unlist(list(a = 1, b = list(c = 2))) # flatten
37

You receive 60 monthly CSV files with the same structure. How do you combine them into one data frame?

Save to ▾
Show answer
I list the files with list.files(pattern = 'csv$', full.names = TRUE), then read them all at once with readr::read_csv(files, id = 'file'), which also records the source file. Alternatively I use purrr::map() with read_csv and dplyr::bind_rows(). Before combining, I check that column names and types match, because one file with text in a numeric column will fail or coerce the whole column. I then derive the month from the file name for traceability.
38

A loop that adds rows to a data frame with rbind() takes very long. How do you speed it up?

Save to ▾
Show answer
Calling rbind() inside a loop copies the growing data frame each iteration, so time grows roughly quadratically. I instead store each piece in a preallocated list, results[[i]] <- piece, and combine once at the end with dplyr::bind_rows() or data.table::rbindlist(), which is the fastest. Better still is to vectorize the computation or use purrr::map() followed by list_rbind(). On 10,000 iterations this can cut runtime from minutes to seconds.
39

What is a tibble and how does it differ from a base data frame?

Save to ▾
Show answer
A tibble is the tidyverse version of a data frame. It prints only the rows and columns that fit the screen along with column types, never converts strings to factors, never changes column names, does not partially match with $ and always returns a tibble when subsetting with [ ]. It also supports list-columns easily. You convert with as_tibble(). Tibbles prevent many silent bugs, though some older packages expect base data frames.
40

What is data.table and when would you use it?

Save to ▾
Show answer
data.table is a high-performance package for large tabular data. Its syntax DT[i, j, by] means filter rows with i, compute j, grouped by by. It updates columns by reference with :=, avoiding copies, and offers fast keyed joins and fread()/fwrite() for file IO. For example, DT[city == 'Delhi', .(avg_sal = mean(salary)), by = dept] filters and aggregates in one step. It is popular for datasets with tens of millions of rows.
41

Write common data.table operations for filtering, aggregating and joining.

Save to ▾
Show answer
Read, filter, aggregate, add columns by reference and join: library(data.table) DT <- fread('orders.csv') DT[status == 'delivered', .N, by = city] DT[, revenue := qty * price] DT[, .(total = sum(revenue)), by = .(city, month)][order(-total)] customers <- fread('customers.csv') merged <- customers[DT, on = 'customer_id'] fwrite(merged, 'merged.csv')
42

How do you clean and manipulate text data in R?

Save to ▾
Show answer
The stringr package gives consistent functions starting with str_. library(stringr) x <- c(' Rahul Sharma ', 'priya VERMA') str_trim(x) str_to_title(x) str_detect(x, 'Sharma') str_replace_all('9876-543-210', '-', '') str_extract('Order ID: 45821', '[0-9]+') str_split('a,b,c', ',')[[1]] str_pad('7', width = 3, pad = '0') # '007'
43

How are dates and times handled in R?

Save to ▾
Show answer
Base R stores dates as the Date class, counting days since 1970-01-01, and date-times as POSIXct, counting seconds. as.Date('2026-03-15') parses ISO strings and format() controls output. The lubridate package simplifies parsing with ymd(), dmy() and mdy(), extracting parts with month() and wday(), and arithmetic like date + months(1). Time zones matter: Indian data usually uses 'Asia/Kolkata', and mixing UTC with IST can shift records across days.
44

After merging two data frames you get more rows than expected. What happened?

Save to ▾
Show answer
Extra rows after a join usually mean the key is duplicated in one or both tables, so each match multiplies rows. I check uniqueness with df %>% count(key) %>% filter(n > 1) on both sides. Then I decide whether to deduplicate, aggregate before joining or join on a composite key such as customer_id plus month. In dplyr 1.1 and later, the relationship argument, for example 'many-to-one', makes the join fail loudly when this assumption breaks.
45

Describe a time you found a data quality issue in your analysis.

Save to ▾
Show answer
Situation: while preparing a monthly revenue dashboard, totals were 8 percent higher than finance figures. Task: find the cause before the review meeting. Action: I traced row counts after each step in my R script and found a join on customer ID that duplicated rows because some customers had two active addresses. I deduplicated the address table and added a row-count check. Result: numbers matched finance, and the check now runs in every refresh.
46

Tell me about a time you had two urgent analysis requests at the same time.

Save to ▾
Show answer
Situation: two managers needed different analyses on the same Friday. Task: deliver both without compromising quality. Action: I asked each what decision the analysis would support and the minimum needed by Friday, reused one cleaned dataset in R for both, and shared a draft of the simpler one on Wednesday for early feedback. Result: both received usable outputs on time, and the fuller version of the second analysis followed on Monday as agreed.
47

What is a list-column and why is it useful?

Save to ▾
Show answer
A list-column is a data frame column whose cells are lists, such as nested data frames or fitted models. With tidyr::nest() you group data, for example by region, into a column of sub-data frames, then use purrr::map() to fit a model per region and broom::tidy() to extract coefficients. This keeps data, models and results aligned row by row, which is cleaner than managing separate lists of models and names.
48

Write code to fit one regression model per group using nested data.

Save to ▾
Show answer
Fit one model per region with list-columns: library(dplyr); library(tidyr) library(purrr); library(broom) models <- sales %>% group_by(region) %>% nest() %>% mutate( fit = map(data, ~ lm(revenue ~ ad_spend, data = .x)), coefs = map(fit, tidy), r2 = map_dbl(fit, ~ glance(.x)$r.squared) ) models %>% unnest(coefs) %>% select(region, term, estimate)
49

Are factors more memory efficient than character vectors in modern R?

Save to ▾
Show answer
Not by much. R keeps a global string pool, so each unique string is stored once and a character vector only holds pointers, which makes repeated values already compact. Factors still matter for controlling level order in plots and models and for representing a fixed set of categories. For huge data, data.table and arrow handle strings efficiently, and converting high-cardinality IDs to factors usually adds overhead without any benefit.
50

An API returns deeply nested JSON. How do you turn it into a tidy data frame in R?

Save to ▾
Show answer
I make the request with httr2, handling authentication and pagination, then parse with jsonlite::fromJSON(), which simplifies arrays of objects into data frames, using flatten = TRUE to spread nested objects into columns. For deeper nesting I keep a list and use tidyr::unnest_wider() and unnest_longer() to expand list-columns step by step. Optional keys become NA, so I check missing fields across records and validate types before analysis.
51

What is the tidyverse?

Save to ▾
Show answer
The tidyverse is a collection of R packages that share a common design and grammar for data science. Core packages include readr for importing, dplyr for transformation, tidyr for reshaping, ggplot2 for visualization, purrr for functional programming, stringr for text, forcats for factors and lubridate for dates. library(tidyverse) loads the core set. Its consistent function names and the pipe make analysis code readable, which is why most R analytics teams use it.
52

What are the main dplyr verbs?

Save to ▾
Show answer
dplyr has a small set of verbs for data transformation: filter() keeps rows that meet conditions, select() picks columns, mutate() creates or changes columns, arrange() sorts rows, summarise() reduces groups to summary rows and group_by() defines groups for the next operations. Others include distinct(), rename(), relocate(), count() and slice(). Each takes a data frame as the first argument and returns a data frame, so verbs chain naturally with the pipe.
53

What are the principles of tidy data?

Save to ▾
Show answer
Tidy data follows three rules: each variable is a column, each observation is a row and each type of observational unit forms a table. For example, a sales sheet with separate columns for Jan, Feb and Mar is not tidy, because month is a variable spread across columns. Reshaping it into month and sales columns makes it tidy. Tidy data works directly with dplyr, ggplot2 and modelling functions, reducing reshaping effort later.
54

Write dplyr code to find total and average sales by city, sorted by total.

Save to ▾
Show answer
Group, summarise and sort: library(dplyr) city_summary <- sales %>% filter(!is.na(amount)) %>% group_by(city) %>% summarise( orders = n(), total = sum(amount), avg_order = mean(amount), .groups = 'drop' ) %>% arrange(desc(total)) head(city_summary, 10)
55

How do you split one column into several, or combine columns into one?

Save to ▾
Show answer
tidyr provides separate_wider_delim() to split and unite() to combine. library(tidyr) df <- tibble(full_name = c('Amit Kumar', 'Neha Singh'), dob = c('12-05-1999', '03-11-2000')) df %>% separate_wider_delim(full_name, delim = ' ', names = c('first', 'last')) df %>% separate_wider_delim(dob, '-', names = c('d', 'm', 'y')) %>% unite('dob_iso', y, m, d, sep = '-')
56

Finance says 120 transactions are missing from your report compared with their system. How do you find them?

Save to ▾
Show answer
I load both datasets and standardise the key, for example trimming spaces and matching data types for transaction_id. Then anti_join(finance, report, by = 'transaction_id') lists transactions in finance but not in my report, and the reverse anti_join shows extras. I examine the missing rows for patterns such as a date range, status or filter in my code. Usually the cause is a timezone cut-off or an excluded status.
57

What is the difference between mutate() and summarise()?

Save to ▾
Show answer
mutate() adds or modifies columns and keeps the same number of rows, so each row gets a value. summarise() collapses each group into one row of summary values. For example, group_by(city) %>% mutate(city_avg = mean(sales)) adds the city average to every row, useful for comparing each row with its group, while group_by(city) %>% summarise(city_avg = mean(sales)) returns one row per city.
58

What is the difference between %>% and |> in R?

Save to ▾
Show answer
%>% comes from the magrittr package and |> is the native pipe built into R since version 4.1. Both pass the left side as the first argument of the right side, so df |> filter(x > 1) equals filter(df, x > 1). The native pipe is faster and needs no package, but it uses _ as a named placeholder only, while %>% supports the dot placeholder anywhere. New code increasingly uses |>, and both work with dplyr.
59

How do you create a column with multiple conditions in dplyr?

Save to ▾
Show answer
case_when() evaluates conditions in order and returns the value of the first one that is TRUE; .default handles the rest. customers <- customers %>% mutate(segment = case_when( spend >= 50000 ~ 'Platinum', spend >= 20000 ~ 'Gold', spend >= 5000 & visits > 5 ~ 'Silver', .default = 'Regular' )) # simple two-way split mutate(df, high_value = if_else(spend > 20000, 'Yes', 'No'))
60

Explain the different types of joins in dplyr.

Save to ▾
Show answer
left_join() keeps all rows of the left table and adds matching columns from the right, inner_join() keeps only matching rows, right_join() keeps all rows of the right table and full_join() keeps all rows from both, filling NA where there is no match. Keys are given with by = join_by(customer_id) or by = c('id' = 'cust_id') for different names. Left joins are most common when enriching a fact table with lookup details.
61

How do you reshape data between wide and long formats in R?

Save to ▾
Show answer
tidyr's pivot_longer() turns columns into rows and pivot_wider() does the reverse. library(tidyr) # wide: product, Jan, Feb, Mar long <- sales_wide %>% pivot_longer(cols = Jan:Mar, names_to = 'month', values_to = 'sales') wide <- long %>% pivot_wider(names_from = month, values_from = sales, values_fill = 0)
62

How do you apply the same transformation to many columns in dplyr?

Save to ▾
Show answer
across() applies one or more functions to a set of columns selected with tidyselect helpers. df %>% mutate(across(where(is.character), str_trim)) %>% mutate(across(starts_with('amt_'), ~ round(.x, 2))) df %>% group_by(region) %>% summarise(across(c(sales, profit), list(mean = mean, max = max), .names = '{.col}_{.fn}'))
63

What window functions does dplyr provide?

Save to ▾
Show answer
Window functions return one value per row while looking at other rows in the group. Common ones are lag() and lead() for previous or next values, row_number(), min_rank() and dense_rank() for ranking, cumsum() and cummean() for running totals, and ntile() for buckets. For example, group_by(product) %>% arrange(month) %>% mutate(prev = lag(sales)) gives the previous month's sales per product, which is the basis for growth calculations.
64

You need month-over-month sales growth for each product. How do you calculate it in R?

Save to ▾
Show answer
I first aggregate to one row per product and month with group_by() and summarise(). Then I group by product, arrange by month and use mutate(growth = (sales - lag(sales)) / lag(sales) * 100). The first month for each product becomes NA, which is correct. I make sure months with zero sales exist using tidyr::complete(), otherwise lag() compares non-consecutive months. Finally I round and format growth for reporting.
65

A customer table has multiple records per customer. How do you keep only the latest record for each?

Save to ▾
Show answer
I group by customer_id and keep the row with the latest updated_at using slice_max(updated_at, n = 1, with_ties = FALSE), then ungroup. An alternative is arrange(desc(updated_at)) followed by distinct(customer_id, .keep_all = TRUE). I check that updated_at is a proper date-time and has no NAs, since missing timestamps would be dropped or mis-sorted. Finally I confirm that n_distinct(customer_id) equals the number of rows.
66

Salary data has a few extreme values that distort averages. How do you handle them?

Save to ▾
Show answer
First I investigate whether they are data errors, such as an extra zero, or genuine high earners. I flag outliers with the IQR rule, values beyond Q1 - 1.5 IQR or Q3 + 1.5 IQR, or with percentiles. Errors I fix or remove with documentation. Genuine values I keep, but I report the median alongside the mean, or winsorize at the 1st and 99th percentiles for modelling. The choice depends on the business question.
67

How would you impute missing values differently for each group?

Save to ▾
Show answer
I group by the relevant category, such as product category, and replace NAs with that group's median: group_by(category) %>% mutate(price = coalesce(price, median(price, na.rm = TRUE))) %>% ungroup(). Group medians are more realistic than a global value. I also add a flag column marking imputed rows so models and reviewers can see them. If a whole group is missing, I fall back to the overall median, and for important features I consider model-based imputation.
68

What are semi_join() and anti_join() used for?

Save to ▾
Show answer
They are filtering joins: they keep rows of the left table based on matches in the right table but add no columns. semi_join() keeps rows that have a match, and anti_join() keeps rows that have no match. For example, anti_join(customers, orders, by = 'customer_id') lists customers who never ordered. They are also safer than inner joins for filtering, since they never duplicate rows when the right table has repeated keys.
69

Why is ungroup() important in dplyr?

Save to ▾
Show answer
A grouped data frame stays grouped after mutate() and some other verbs, so later operations silently run per group. For example, a mutate(share = sales / sum(sales)) meant to compute share of grand total would compute share within each group instead. Calling ungroup() after grouped work, or using .groups = 'drop' in summarise() or the .by argument for one-off grouping, prevents these subtle bugs in long pipelines.
70

Tell me about the messiest dataset you have cleaned.

Save to ▾
Show answer
Situation: I received three years of vendor invoices from different branches in Excel files with inconsistent headers, merged cells and dates in four formats. Task: build one clean table for spend analysis. Action: I used readxl to read all sheets, janitor::clean_names() to standardise headers, lubridate to parse dates and a mapping table for vendor name variants. I wrote validation checks for totals. Result: a clean dataset of 180,000 rows that finance now refreshes monthly.
71

Your dplyr pipeline is too slow on a 50 million row dataset. What are your options?

Save to ▾
Show answer
I can keep dplyr syntax but change the backend. dtplyr translates dplyr code to data.table, which is much faster in memory. duckdb with dbplyr runs the pipeline in an embedded columnar database, often handling data larger than RAM. arrow lets me query Parquet files with dplyr verbs lazily. I would also filter and select early, avoid row-wise operations and profile the pipeline to find the slow step before rewriting anything.
72

What is dbplyr and how does it work?

Save to ▾
Show answer
dbplyr is a dplyr backend that translates dplyr verbs into SQL and runs them inside a database. You connect with DBI, reference a table with tbl(con, 'orders') and write normal dplyr code. Queries are lazy: nothing runs until you call collect(), and show_query() prints the generated SQL. This lets analysts work with large warehouse tables without pulling all rows into R, though some R functions have no SQL translation.
73

What is tidy evaluation and why do you need {{ }} in functions?

Save to ▾
Show answer
dplyr uses data masking, so you can write column names without quotes. Inside your own function, a column passed as an argument is not found automatically because R looks for a variable with that name. Embracing the argument with {{ }} tells dplyr to use the column the caller supplied. For column names stored as strings, you use .data[[var]]. For new column names, use the glue syntax '{{var}}_mean' := with the walrus operator.
74

Write a reusable function that summarises any numeric column by any grouping column using dplyr.

Save to ▾
Show answer
Use {{ }} to pass columns into data-masking verbs: library(dplyr) summarise_by <- function(data, group_col, value_col) { data %>% group_by({{ group_col }}) %>% summarise( n = n(), mean_val = mean({{ value_col }}, na.rm = TRUE), total = sum({{ value_col }}, na.rm = TRUE), .groups = 'drop' ) %>% arrange(desc(total)) } summarise_by(sales, city, amount)
75

Describe a mistake you made in an analysis and how you handled it.

Save to ▾
Show answer
Situation: I shared a retention analysis showing improvement, but a week later I noticed I had excluded customers with missing signup dates, who were mostly churned users. Task: correct it before decisions were made. Action: I informed my manager immediately, reran the analysis with proper handling, explained the impact clearly and added a missing-value check to my template. Result: the corrected numbers were used, and my manager appreciated the transparency.
76

What is the grammar of graphics in ggplot2?

Save to ▾
Show answer
The grammar of graphics describes a plot as layers built from components: data, aesthetic mappings that link variables to visual properties like x, y and colour, geoms that draw shapes, stats that transform data, scales, coordinate systems, facets and themes. In ggplot2 you start with ggplot(data, aes(x, y)) and add layers with +, such as geom_point(). This makes complex charts systematic and easy to modify.
77

Which chart types would you use for comparing categories, trends and distributions?

Save to ▾
Show answer
For comparing categories I use a bar chart, sorted by value, or a dot plot when there are many categories. For trends over time I use a line chart with time on the x-axis. For distributions I use histograms or density plots for one variable and boxplots or violin plots to compare groups. For relationships between two numeric variables I use a scatter plot. I avoid pie charts beyond three or four slices.
78

Write ggplot2 code for a monthly sales line chart with points.

Save to ▾
Show answer
A basic time-series line chart: library(ggplot2) ggplot(monthly, aes(x = month, y = sales)) + geom_line(colour = 'steelblue', linewidth = 1) + geom_point(size = 2) + scale_y_continuous(labels = scales::label_comma()) + scale_x_date(date_labels = '%b %Y', date_breaks = '2 months') + labs(title = 'Monthly Sales', x = NULL, y = 'Sales (INR)') + theme_minimal()
79

Write code to show the distribution of order values using a histogram and a boxplot by category.

Save to ▾
Show answer
Histogram for one variable, boxplot to compare groups: ggplot(orders, aes(x = order_value)) + geom_histogram(binwidth = 500, fill = 'grey60', colour = 'white') + labs(x = 'Order value (INR)', y = 'Orders') ggplot(orders, aes(x = category, y = order_value)) + geom_boxplot(outlier.alpha = 0.3) + coord_flip() + labs(x = NULL, y = 'Order value (INR)')
80

How do you save a ggplot chart for a report or presentation?

Save to ▾
Show answer
ggsave() saves the last plot or a named plot with exact size and resolution. p <- ggplot(df, aes(city, sales)) + geom_col() ggsave('output/sales_by_city.png', plot = p, width = 8, height = 5, dpi = 300) ggsave('output/sales_by_city.pdf', plot = p, width = 8, height = 5) # vector, sharp at any zoom # svg for web use ggsave('output/sales_by_city.svg', plot = p)
81

Bars in your chart appear in alphabetical order instead of by value. How do you fix it?

Save to ▾
Show answer
ggplot2 orders discrete axes by factor levels, which default to alphabetical. I reorder the factor by the value with forcats: aes(x = fct_reorder(city, sales), y = sales), and add coord_flip() or put the category on the y-axis for long labels. For a fixed custom order, such as months or ratings, I set levels explicitly with factor(x, levels = c(...)). fct_infreq() orders by frequency for count bars.
82

What is the difference between base R graphics and ggplot2?

Save to ▾
Show answer
Base graphics use functions like plot(), hist() and barplot() that draw directly on a device, and you add elements with lines() or legend() step by step. They are quick for exploration. ggplot2 builds plots as objects from layers using the grammar of graphics, handles legends and facets automatically and is easier to style consistently. Base plots are fine for quick checks, while ggplot2 is preferred for reports and publications.
83

Your manager says your charts are confusing. How do you respond?

Save to ▾
Show answer
I would thank them and ask which part was unclear, such as too many colours, missing labels or an unclear message. In my internship this happened with a crowded chart of twelve product lines. I simplified it by highlighting the top three, greying the rest, adding a clear title stating the finding and labelling values directly. My manager found the new version easy to present, and I now review every chart for one clear message.
84

What is the difference between mapping and setting an aesthetic in ggplot2?

Save to ▾
Show answer
Mapping links an aesthetic to a variable inside aes(), so values change with the data and a legend is created, for example aes(colour = region). Setting fixes an aesthetic to a constant outside aes(), for example geom_point(colour = 'steelblue'). A common mistake is writing aes(colour = 'blue'), which treats 'blue' as a data value, creates a legend called blue and uses the default red colour instead.
85

What is the difference between geom_bar() and geom_col()?

Save to ▾
Show answer
geom_bar() counts rows for each x value by default using stat = 'count', so you give only x, for example the number of orders per city from raw data. geom_col() uses y values as they are, so you supply already summarised data, for example total sales per city. geom_bar(stat = 'identity') is equivalent to geom_col(). Using geom_bar() with a y aesthetic gives an error, which is a common beginner issue.
86

What are facets in ggplot2?

Save to ▾
Show answer
Facets split a plot into small multiples, one panel per category, sharing the same axes and geoms. facet_wrap(~ region) wraps panels for one variable, and facet_grid(rows = vars(segment), cols = vars(year)) creates a grid for two variables. scales = 'free_y' lets each panel have its own y-axis. Facets are often clearer than one chart with many overlapping coloured lines, for example comparing sales trends across ten states.
87

How do you customise scales, labels and themes in ggplot2?

Save to ▾
Show answer
Scales control how data maps to visuals, and themes control non-data elements. p + scale_y_continuous(labels = scales::label_percent()) + scale_fill_brewer(palette = 'Set2') + labs(title = 'Conversion by Channel', subtitle = 'FY 2025-26', caption = 'Source: CRM') + theme_minimal(base_size = 12) + theme(legend.position = 'bottom', plot.title = element_text(face = 'bold'), panel.grid.minor = element_blank())
88

Your scatter plot of 200,000 points looks like a solid blob. How do you fix it?

Save to ▾
Show answer
This is overplotting. I reduce point size and add transparency with geom_point(alpha = 0.1, size = 0.5). Better options are geom_hex() or geom_bin2d(), which show density as colour, or geom_density_2d() contours. I could also plot a random sample for shape and a smoothed trend with geom_smooth() on the full data. If x values are discrete, geom_jitter() spreads points. The goal is to make density visible, not every point.
89

Some stakeholders are colour-blind. How do you design charts for them?

Save to ▾
Show answer
I use colour-blind-safe palettes such as viridis with scale_colour_viridis_d() or the Okabe-Ito palette, and avoid red-green contrasts. I never rely on colour alone: I add direct labels, different shapes or line types, and facets. I limit categories to around six colours and highlight one key series while greying the rest. I also check charts with a colour-blindness simulator, such as the colorblindr package, before sharing.
90

How do you create interactive charts in R?

Save to ▾
Show answer
plotly's ggplotly() converts an existing ggplot into an interactive chart with hover tooltips, zoom and legend toggling. ggiraph adds interactive tooltips and selection to ggplot geoms with fine control. highcharter and echarts4r wrap JavaScript charting libraries, and leaflet builds interactive maps. These outputs work in R Markdown or Quarto HTML reports and Shiny apps. For static PDF reports, standard ggplot2 is still the better choice.
91

How do you add labels and annotations to a ggplot chart?

Save to ▾
Show answer
Use geom_text() or geom_label() for data labels and annotate() for one-off notes. ggplot(city_sales, aes(reorder(city, sales), sales)) + geom_col(fill = 'steelblue') + geom_text(aes(label = scales::comma(sales)), hjust = -0.1, size = 3.5) + annotate('text', x = 2, y = 9e5, label = 'Festive season push') + coord_flip() + expand_limits(y = 1.1e6) + labs(x = NULL, y = 'Sales (INR)')
92

What do geom_smooth() and stat_summary() do?

Save to ▾
Show answer
geom_smooth() adds a fitted trend line with a confidence band, using loess for small data and a GAM for large data by default, or method = 'lm' for a straight line. stat_summary() computes summaries of y for each x, for example stat_summary(fun = mean, geom = 'point') to plot group means, or fun.data = mean_cl_normal for error bars. Both let you show patterns without precomputing summaries.
93

What makes a chart misleading?

Save to ▾
Show answer
Common problems are a truncated y-axis on bar charts, which exaggerates differences because bar length should start at zero, inconsistent scales across panels, 3D effects, cherry-picked time ranges, dual axes with arbitrary ranges and too many colours. Area or bubble charts can mislead when size is mapped to radius instead of area. Good practice is to start bars at zero, label units, cite the data source and show context such as targets or prior periods.
94

Tell me about a chart or visualization that changed a business decision.

Save to ▾
Show answer
Situation: the operations team believed late deliveries were spread evenly across the week. Task: I was asked to review delivery data. Action: in R I built a heatmap of late deliveries by weekday and hour with ggplot2, which showed a sharp cluster on Monday mornings linked to weekend order backlog. Result: management added a Sunday evening shift, and late deliveries dropped by about 18 percent the next quarter.
95

Leadership wants a single report page with 15 charts. How do you approach it?

Save to ▾
Show answer
I first ask which decisions the page supports and which three to five metrics matter most, because 15 charts usually hide the message. I put headline KPIs at the top, followed by trend charts and then breakdowns, with consistent colours, scales and a shared theme function. Less important views go to a drill-down tab in a Shiny or Quarto dashboard. I test the draft with one stakeholder and remove charts nobody uses.
96

Why are dual-axis charts discouraged and how does ggplot2 handle secondary axes?

Save to ▾
Show answer
Dual-axis charts plot two measures with different scales on one chart, and the visual relationship between the lines depends on arbitrary axis ranges, so readers can be misled about correlation. ggplot2 only allows a secondary axis that is a one-to-one transformation of the primary axis through sec_axis(), such as Celsius and Fahrenheit. For two different metrics, I prefer two aligned panels using facets or the patchwork package.
97

Rendering a ggplot with 10 million points is extremely slow. What would you do?

Save to ▾
Show answer
I first question whether all points are needed. I aggregate before plotting, for example binning into hexagons with geom_hex() or summarising by time interval. If raw points are required, the scattermore package rasterizes millions of points quickly, and ggrastr rasterizes just the point layer while keeping text as vector. Saving as PNG instead of PDF also helps, because vector files with millions of shapes are huge and slow to open.
98

What is the difference between coord_cartesian() limits and scale limits in ggplot2?

Save to ▾
Show answer
Setting limits with scale_y_continuous(limits = c(0, 100)) or ylim() removes data outside the range before statistics are calculated, which changes boxplots, smooth lines and bar totals and gives warnings about removed rows. coord_cartesian(ylim = c(0, 100)) only zooms the view, keeping all data in calculations. So for zooming into part of a chart without altering the summary, coord_cartesian() is the correct choice.
99

How would you create a reusable branded theme for all team charts?

Save to ▾
Show answer
Wrap theme settings and palettes in functions stored in an internal package: theme_team <- function(base_size = 12) { theme_minimal(base_size = base_size) + theme( plot.title = element_text(face = 'bold', colour = '#1F3A5F'), panel.grid.minor = element_blank(), legend.position = 'top' ) } scale_fill_team <- function(...) { scale_fill_manual(values = c('#1F3A5F', '#F28C28', '#2A9D8F'), ...) } ggplot(df, aes(x, y, fill = g)) + geom_col() + theme_team() + scale_fill_team()
100

How do you create maps in R?

Save to ▾
Show answer
The sf package stores spatial data as data frames with a geometry column, and ggplot2's geom_sf() draws them. You read shapefiles or GeoJSON with st_read(), join your data, for example sales by state, and fill polygons by value to make a choropleth. tmap is a dedicated thematic mapping package and leaflet builds interactive web maps. Coordinate reference systems must match, and st_transform() reprojects layers when they do not.
101

When would you report the median instead of the mean?

Save to ▾
Show answer
The mean uses every value and is sensitive to outliers, while the median is the middle value and is robust to them. I report the median for skewed data such as salaries, house prices, order values or delivery times, where a few extreme values pull the mean up. For example, if most employees earn 6 LPA and a few earn 80 LPA, the median describes a typical employee better. The mode suits categorical data.
102

What is the difference between variance and standard deviation?

Save to ▾
Show answer
Variance is the average squared deviation from the mean, and standard deviation is its square root. Because variance is in squared units, standard deviation is easier to interpret since it uses the same units as the data. In R, var() and sd() both use the sample formula with n - 1 in the denominator. For example, delivery times with mean 30 minutes and SD 5 minutes are far more consistent than with SD 15.
103

Why does correlation not imply causation?

Save to ▾
Show answer
Two variables can move together because of a third confounding variable, reverse causation or pure chance. For example, ice cream sales and drowning incidents are correlated because both rise in summer. To claim causation you need a randomized experiment such as an A/B test, or careful causal methods like difference-in-differences or regression with controls. In interviews, mention that observational correlations are useful for hypotheses but not proof of impact.
104

How do you produce descriptive statistics for each group in R?

Save to ▾
Show answer
Combine summary functions with dplyr, or use quick helpers for exploration. summary(df$salary) quantile(df$salary, c(0.1, 0.5, 0.9), na.rm = TRUE) df %>% group_by(department) %>% summarise(n = n(), mean = mean(salary, na.rm = TRUE), median = median(salary, na.rm = TRUE), sd = sd(salary, na.rm = TRUE), iqr = IQR(salary, na.rm = TRUE)) skimr::skim(df)
105

What are skewness and kurtosis?

Save to ▾
Show answer
Skewness measures asymmetry of a distribution. Positive or right skew has a long right tail, typical of income and order values, so the mean exceeds the median. Negative skew has a long left tail. Kurtosis measures how heavy the tails are compared with a normal distribution; high kurtosis means more extreme values, common in financial returns. In R, the moments or e1071 packages provide skewness() and kurtosis() functions.
106

How do you keep improving your statistics knowledge?

Save to ▾
Show answer
I revise core concepts from a standard textbook and practise each method in R on public datasets, so I understand both the theory and the code. For example, after learning hypothesis testing, I reproduced published A/B test results from Kaggle datasets. I follow the R Weekly newsletter and read package vignettes. When I meet a method at work that I do not understand, I note it and study it that weekend.
107

What is the Central Limit Theorem and why is it important?

Save to ▾
Show answer
The Central Limit Theorem says that the distribution of sample means approaches a normal distribution as sample size grows, roughly beyond 30, regardless of the population's shape, provided observations are independent with finite variance. It is why t-tests, confidence intervals and A/B test calculations work on non-normal data such as order values. You can demonstrate it in R by repeatedly sampling from rexp() and plotting a histogram of the means.
108

What is a p-value?

Save to ▾
Show answer
A p-value is the probability of seeing results at least as extreme as the observed ones if the null hypothesis were true. A small p-value, typically below 0.05, means the data would be unusual under the null, so we reject it. It is not the probability that the null hypothesis is true and does not measure effect size. A tiny, unimportant difference can be significant with a huge sample, so always report effect sizes and confidence intervals too.
109

Explain Type I and Type II errors.

Save to ▾
Show answer
A Type I error is rejecting a true null hypothesis, a false positive, and its probability is the significance level alpha, usually 0.05. A Type II error is failing to reject a false null hypothesis, a false negative, with probability beta; power is 1 - beta. For example, launching a feature that does not actually help is a Type I error, while dropping a feature that really works is Type II. Larger samples reduce Type II errors.
110

How do you perform a t-test in R?

Save to ▾
Show answer
t.test() handles one-sample, two-sample and paired tests. Welch's test, which does not assume equal variances, is the default. # two independent groups t.test(score ~ batch, data = students) # paired: before vs after training t.test(after, before, paired = TRUE) # one-sample against a target of 30 minutes t.test(delivery_time, mu = 30, alternative = 'greater') res <- t.test(score ~ batch, data = students) res$p.value; res$conf.int
111

How do you test whether two categorical variables are related in R?

Save to ▾
Show answer
Use a chi-square test of independence on a contingency table; use Fisher's exact test when expected counts are small. tab <- table(survey$city_tier, survey$preferred_plan) tab res <- chisq.test(tab) res$p.value res$expected # check expected counts >= 5 fisher.test(tab) # for small samples # effect size library(rcompanion) cramerV(tab)
112

What is the difference between Pearson and Spearman correlation?

Save to ▾
Show answer
Pearson correlation measures the strength of a linear relationship between two numeric variables and is sensitive to outliers. Spearman correlation is computed on ranks, so it measures monotonic relationships and is robust to outliers and non-normal data. In R, cor(x, y, method = 'spearman') and cor.test() compute them. For example, ad spend and sales with diminishing returns may show a moderate Pearson value but a high Spearman value.
113

You ran an A/B test on a checkout page: 4.1 percent conversion versus 4.6 percent. How do you decide if the difference is real?

Save to ▾
Show answer
Conversion is a proportion, so I use a two-proportion test: prop.test(c(conv_a, conv_b), c(n_a, n_b)). I check the p-value and, more importantly, the confidence interval for the difference. Before trusting it, I confirm the sample size was planned in advance, the test ran for full weeks to cover weekday effects, users were randomized properly and nobody stopped the test early when results looked good. Then I judge business significance.
114

Your data is heavily skewed and the sample is small. Can you still use a t-test?

Save to ▾
Show answer
With small, heavily skewed samples the t-test's normality assumption is doubtful. I would check with a histogram, Q-Q plot or shapiro.test(). Options are a non-parametric test, wilcox.test() for two groups or kruskal.test() for more, a log transformation if the data is right-skewed and positive, or a bootstrap confidence interval for the difference in means. With large samples, the Central Limit Theorem usually makes the t-test acceptable.
115

What does a 95 percent confidence interval mean?

Save to ▾
Show answer
If we repeated the sampling many times and built an interval each time, about 95 percent of those intervals would contain the true population value. It does not mean there is a 95 percent probability that this specific interval contains it. A narrow interval shows precise estimation and a wide one shows uncertainty. For example, average order value of 850 INR with CI 820 to 880 is far more useful than CI 600 to 1100.
116

Explain the d, p, q and r functions for probability distributions in R.

Save to ▾
Show answer
Each distribution has four functions: d for density, p for cumulative probability, q for quantiles and r for random draws. dnorm(0) # density at 0 pnorm(1.96) # P(Z <= 1.96) = 0.975 qnorm(0.975) # 1.96 rnorm(5, mean = 50, sd = 10) dbinom(3, size = 10, prob = 0.2) # exactly 3 successes ppois(2, lambda = 4) # P(X <= 2) qt(0.975, df = 20) # t critical value
117

How do you check whether data is normally distributed in R?

Save to ▾
Show answer
Combine visual checks with formal tests, because tests become oversensitive with large samples. hist(x, breaks = 30) qqnorm(x); qqline(x, col = 'red') shapiro.test(x) # works for n between 3 and 5000 library(ggplot2) ggplot(df, aes(sample = x)) + stat_qq() + stat_qq_line() # for model residuals plot(lm_fit, which = 2)
118

How do you compare means across more than two groups in R?

Save to ▾
Show answer
Use one-way ANOVA, then a post-hoc test to see which pairs differ. fit <- aov(sales ~ region, data = stores) summary(fit) # overall F-test TukeyHSD(fit) # pairwise comparisons # check assumptions plot(fit, which = 2) # Q-Q of residuals bartlett.test(sales ~ region, data = stores) # non-parametric alternative kruskal.test(sales ~ region, data = stores)
119

Product wants to detect a lift in conversion from 5 to 5.5 percent. How many users do you need per group?

Save to ▾
Show answer
I use power analysis before the test starts. In R, power.prop.test(p1 = 0.05, p2 = 0.055, power = 0.8, sig.level = 0.05) gives roughly 31,000 users per group. Smaller lifts need far larger samples, since sample size scales with the inverse square of the effect. I would then convert the sample into test duration using daily traffic, round up to full weeks, and agree on the stopping rule in advance to avoid peeking bias.
120

What is the multiple testing problem and how do you correct for it?

Save to ▾
Show answer
When you run many hypothesis tests, the chance of at least one false positive rises sharply. With 20 independent tests at alpha 0.05, it is about 64 percent. Corrections adjust p-values: Bonferroni multiplies by the number of tests and is conservative, Holm is a less strict step-down version, and Benjamini-Hochberg controls the false discovery rate. In R, p.adjust(pvals, method = 'BH') applies them, which is common when testing many metrics or segments.
121

What is bootstrapping and when would you use it?

Save to ▾
Show answer
Bootstrapping estimates the sampling distribution of a statistic by resampling the data with replacement many times and recomputing the statistic each time. The spread of those results gives standard errors and confidence intervals without assuming normality. It is useful for medians, ratios or complex metrics like revenue per user, where formulas are hard. In R, the boot package or a simple replicate() loop with sample(x, replace = TRUE) does it.
122

A manager says a test with p = 0.06 proves the change had no effect. How do you respond?

Save to ▾
Show answer
I explain that failing to reject the null is not proof of no effect. A p-value of 0.06 means the evidence is weak or the test was underpowered, and the 0.05 cut-off is a convention, not a law. I would show the confidence interval for the effect, which probably ranges from slightly negative to clearly positive, check whether the sample size met the planned power and suggest extending the test or weighing the decision on cost and risk.
123

You are analysing a national survey where some groups were deliberately oversampled. How do you compute correct averages?

Save to ▾
Show answer
Simple averages would be biased toward oversampled groups, so I use the survey weights provided with the data. In R, the survey package defines the design with svydesign(ids = ~psu, strata = ~stratum, weights = ~wt, data = df), then svymean(), svytotal() and svyglm() give weighted estimates with correct standard errors that account for clustering and stratification. The srvyr package offers the same with dplyr-style syntax.
124

Overall, treatment A has a higher success rate than B, but B is better in every hospital. How is that possible?

Save to ▾
Show answer
This is Simpson's paradox. It happens when a confounding variable, here hospital or patient severity, is unevenly distributed between groups. If A was used mostly in hospitals with easier cases, its overall rate looks better even though B wins within each hospital. In R I would group by hospital and compare rates, then use a stratified analysis or regression with hospital as a covariate to estimate the adjusted effect.
125

Tell me about a time your analysis did not support what a stakeholder hoped to see.

Save to ▾
Show answer
Situation: a marketing head expected a new campaign to have doubled sign-ups. Task: evaluate its impact. Action: my analysis in R using a pre-post comparison with a control region showed only a 6 percent lift, much of it seasonal. I presented the method and confidence interval openly, acknowledged what went well and suggested a cleaner randomized test. Result: the stakeholder accepted the finding, and the next campaign was run as a proper experiment.
126

How do you write a function in R with default arguments?

Save to ▾
Show answer
A function is created with the function keyword and returns the value of its last expression, or an explicit return(). gst_price <- function(price, rate = 0.18, round_to = 2) { if (!is.numeric(price)) stop('price must be numeric') round(price * (1 + rate), round_to) } gst_price(1000) # 1180 gst_price(1000, rate = 0.05) gst_price(c(100, 250)) # vectorized
127

What is the difference between if, ifelse() and dplyr's if_else()?

Save to ▾
Show answer
if is a control-flow statement that checks a single TRUE or FALSE value and runs one branch, used for program logic. ifelse() is vectorized and returns a vector of the same length as the condition, used for transforming data. dplyr::if_else() is a stricter vectorized version that requires both outputs to have the same type, preserves classes like dates and has a missing argument for NA conditions, making it safer than ifelse().
128

Explain for, while and repeat loops in R.

Save to ▾
Show answer
A for loop iterates over elements of a vector, for (i in seq_along(x)), and is used when the number of iterations is known. A while loop runs while a condition stays TRUE, useful for convergence or polling. repeat runs indefinitely until break is called. next skips to the next iteration. In R, loops are fine when each iteration is heavy, but for element-wise work vectorized functions or purrr::map() are usually faster and cleaner.
129

Write a recursive function in R to calculate factorial and Fibonacci numbers.

Save to ▾
Show answer
A recursive function calls itself with a smaller input and needs a base case. fact <- function(n) { if (n <= 1) return(1) n * fact(n - 1) } fact(5) # 120 fib <- function(n) { if (n <= 2) return(1) fib(n - 1) + fib(n - 2) } fib(10) # 55 # vectorized and efficient alternative factorial(5); cumprod(1:5)
130

How does the switch() function work in R?

Save to ▾
Show answer
switch() selects one of several alternatives based on a value, which is cleaner than a long chain of if-else statements. With a character input, it matches names: switch(type, mean = mean(x), median = median(x), stop('Unknown type')). The final unnamed argument acts as the default. Empty arguments fall through to the next value, so switch(x, a = , b = 'AB') returns 'AB' for both. It is not vectorized, so use it for single values.
131

Describe a time you learned something from a teammate.

Save to ▾
Show answer
Situation: during my final-year project, our group's R code ran very slowly on a large dataset. Task: I was responsible for the cleaning step. Action: a teammate showed me how to replace my nested for loops with vectorized dplyr operations and explained why loops were slow. I practised the approach on other parts of the code. Result: processing time fell from twenty minutes to under one, and I shared the lesson with the rest of the group.
132

How do you handle errors in R code?

Save to ▾
Show answer
tryCatch() catches errors and warnings so a script can recover or log them; finally runs cleanup. read_safe <- function(path) { tryCatch({ readr::read_csv(path, show_col_types = FALSE) }, warning = function(w) { message('Warning in ', path, ': ', conditionMessage(w)) NULL }, error = function(e) { message('Failed: ', path, ' - ', conditionMessage(e)) NULL }, finally = message('Done: ', path)) }
133

What does the ... (dots) argument do in an R function?

Save to ▾
Show answer
The dots let a function accept any number of additional arguments and pass them on to another function. For example, my_plot <- function(df, ...) ggplot(df, aes(x, y)) + geom_point(...) lets callers pass colour or size without declaring them. You can capture dots with list(...) or count them with ...length(). The downside is that misspelled argument names are silently ignored, so document them and validate with rlang::check_dots_used() in packages.
134

What is the purrr map family?

Save to ▾
Show answer
purrr's map() applies a function to each element of a list or vector and always returns a list. Typed variants return specific types: map_dbl(), map_chr(), map_lgl() and map_int(), and they error if a result has the wrong type, which is safer than sapply(). map2() iterates over two inputs, pmap() over many, and walk() is used for side effects like saving files. Formula shortcuts such as ~ .x * 2 keep code short.
135

Write code using map2() and pmap() to iterate over multiple inputs.

Save to ▾
Show answer
map2() pairs two vectors and pmap() takes a list or data frame of arguments. library(purrr) prices <- c(100, 250, 400) qty <- c(2, 1, 5) map2_dbl(prices, qty, ~ .x * .y) # 200 250 2000 params <- tibble::tibble( region = c('North', 'South'), year = c(2025, 2026) ) pmap(params, function(region, year) { build_report(region = region, year = year) }) walk2(plots, paths, ~ ggsave(.y, .x))
136

How do you validate inputs inside an R function?

Save to ▾
Show answer
Fail early with clear messages using stopifnot(), stop() and match.arg(). summarise_kpi <- function(df, metric = c('revenue', 'orders', 'aov'), min_date = NULL) { stopifnot(is.data.frame(df), nrow(df) > 0) metric <- match.arg(metric) if (!is.null(min_date) && !inherits(min_date, 'Date')) { stop('min_date must be a Date', call. = FALSE) } required <- c('date', metric) missing <- setdiff(required, names(df)) if (length(missing)) stop('Missing columns: ', toString(missing)) # ... compute }
137

Your function gives correct results when you test it but wrong results in the main script. What could be the cause?

Save to ▾
Show answer
A common cause is that the function reads a variable from the global environment instead of taking it as an argument. During testing that global variable had one value, and in the main script it has another. Lexical scoping finds it silently. I would check the function body for names not defined as arguments or locally, for example using codetools::findGlobals(fn), and pass everything explicitly so the function is self-contained.
138

How do you debug an R function?

Save to ▾
Show answer
After an error, traceback() shows the call stack so I can see which function failed. I insert browser() inside a function to pause execution and inspect variables interactively, stepping with n and continuing with c. debug(fn) or debugonce(fn) enters the browser on the next call without editing code. options(error = recover) lets me choose a frame to inspect after an error. RStudio breakpoints offer the same features visually.
139

Your function fails with 'the condition has length > 1' when given a vector. What is wrong?

Save to ▾
Show answer
An if statement can only check a single TRUE or FALSE value, and since R 4.2 a longer condition is an error. The function was written for one value but received a vector. I would replace if with a vectorized alternative such as ifelse(), dplyr::if_else() or case_when(). If the function is truly meant for single values, I validate the input length with stopifnot(length(x) == 1) or apply it over elements with purrr::map().
140

What is a pure function and why prefer them in data pipelines?

Save to ▾
Show answer
A pure function always returns the same output for the same inputs and has no side effects, such as modifying global variables, writing files or printing. Pure functions are easy to test, reuse, cache and run in parallel, because they do not depend on hidden state. In data pipelines, I keep transformations pure, taking a data frame and returning a new one, and isolate side effects such as reading and writing in a few clearly named functions.
141

The same 40 lines of cleaning code are copied into ten scripts. What would you do?

Save to ▾
Show answer
I would extract the logic into well-named functions with arguments for the parts that differ, then move them into one shared file loaded with source() or, better, a small internal R package. A package gives documentation with roxygen2, tests with testthat and versioning, so every script uses the same tested logic. Fixing a bug then happens in one place. I would migrate the scripts gradually and compare outputs to confirm nothing changed.
142

What is the difference between errors, warnings and messages in R?

Save to ▾
Show answer
An error, raised with stop(), halts execution because something cannot continue. A warning, raised with warning(), lets code continue but signals a possible problem, such as NAs introduced by coercion. A message, from message(), is informational, such as progress updates. Messages go to stderr, so they can be suppressed with suppressMessages() without hiding results. Use print() or cat() for output the user requested, not for diagnostics.
143

Tell me about feedback you received in a code review and what you changed.

Save to ▾
Show answer
Situation: in my first quarter, a senior reviewed my R reporting script. Task: address the review comments. Action: the main feedback was that my 300-line script mixed data loading, cleaning and plotting with repeated code. I split it into small functions, added input checks and moved constants to a config file. Result: the next report took half the time to build, and I now structure every new script this way from the start.
144

What are closures and function factories in R?

Save to ▾
Show answer
A closure is a function that remembers the environment in which it was created. A function factory is a function that returns such functions. For example, power <- function(exp) function(x) x^exp; square <- power(2) creates a function that remembers exp = 2. They are useful for creating families of related functions, counters and memoised functions. Because of lazy evaluation, call force(exp) inside the factory so the value is captured immediately.
145

A loop calls an external API 5,000 times and crashes at call 3,200. How do you make it robust?

Save to ▾
Show answer
I wrap each call with purrr::safely() or tryCatch() so one failure does not stop the loop, and add retries with exponential backoff, which httr2 supports through req_retry(). I respect rate limits with Sys.sleep() or req_throttle(). I save results incrementally, for example every 100 calls to an RDS file or database, so a restart resumes from the last checkpoint. Finally I log failed IDs and rerun only those.
146

How do you run R code in parallel?

Save to ▾
Show answer
The parallel package ships with R: mclapply() forks processes on Linux and macOS, while parLapply() uses a socket cluster that also works on Windows. The future framework gives a cleaner interface where you choose a plan, such as plan(multisession), and then use future_map() from furrr or future_lapply(). Parallelism helps when each task is independent and heavy, such as model fitting per group, but adds overhead for small tasks and multiplies memory use.
147

A simulation loop runs for 40 minutes. How would you speed it up?

Save to ▾
Show answer
First I profile with profvis to find the slow lines. Then I try vectorizing, for example generating all random numbers at once with rnorm(n * reps) and using matrix operations instead of nested loops. I preallocate outputs instead of growing them. If iterations are independent, I run them in parallel with future and furrr. If a tight loop cannot be vectorized, I rewrite it in C++ with Rcpp, which often gives a 10 to 100 times speed-up.
148

What is Rcpp and when would you use it?

Save to ▾
Show answer
Rcpp is a package that lets you write C++ functions and call them from R with almost no boilerplate, using cppFunction() for small snippets or sourceCpp() for files. It is used when R code has loops that cannot be vectorized, such as recursive calculations, simulations with dependence between steps or custom algorithms. Many popular packages, including dplyr and data.table internals, rely on compiled code. Use it only after profiling shows a real bottleneck.
149

How do you use Reduce(), Filter() and Map() in base R?

Save to ▾
Show answer
These higher-order functions come from functional programming. nums <- 1:10 Filter(function(x) x %% 2 == 0, nums) # even numbers Map(function(a, b) a + b, 1:3, 4:6) # list: 5 7 9 Reduce(`+`, 1:5, accumulate = TRUE) # 1 3 6 10 15 # join many data frames on a common key dfs <- list(sales, targets, regions) Reduce(function(x, y) merge(x, y, by = 'region_id'), dfs) # purrr equivalents: keep(), map2(), reduce()
150

A function that looks up exchange rates is called thousands of times with the same inputs and is slow. How do you fix it?

Save to ▾
Show answer
The function repeats expensive work for identical inputs, so I would cache its results with memoisation. The memoise package wraps a function, memo_rate <- memoise::memoise(get_rate), and stores results by argument values, returning cached answers instantly. I can set a cache that expires, for example daily for rates, or store it on disk with cachem so it survives sessions. Alternatively I fetch all needed rates once and join them as a lookup table.
151

How do you build a linear regression model in R?

Save to ▾
Show answer
lm() fits linear models using formula syntax; summary() shows coefficients and fit. fit <- lm(sales ~ ad_spend + price + region, data = stores) summary(fit) coef(fit) confint(fit) # 95% CIs for coefficients predict(fit, newdata = new_stores, interval = 'prediction') par(mfrow = c(2, 2)); plot(fit) # diagnostic plots broom::tidy(fit) # coefficients as a tibble
152

Why do we split data into training and test sets, and what is cross-validation?

Save to ▾
Show answer
A model must be evaluated on data it has not seen, otherwise performance looks better than reality. We train on one part, typically 70 to 80 percent, and evaluate on the held-out test set. Cross-validation, such as 5-fold or 10-fold, splits training data into folds, trains on all but one and validates on the remaining fold in turn, giving a more stable estimate for tuning. In tidymodels, initial_split() and vfold_cv() handle this.
153

What is overfitting and how do you prevent it?

Save to ▾
Show answer
Overfitting happens when a model learns noise in the training data, so it performs very well on training data but poorly on new data. Signs are a large gap between training and validation scores. Prevention includes using simpler models, regularization such as lasso or ridge, cross-validation for tuning, limiting tree depth, getting more data and removing leaky or irrelevant features. Underfitting is the opposite: the model is too simple to capture the pattern.
154

Explain the confusion matrix and the metrics derived from it.

Save to ▾
Show answer
A confusion matrix compares actual and predicted classes: true positives, false positives, true negatives and false negatives. Accuracy is the share of correct predictions. Precision is TP / (TP + FP), how many predicted positives are correct. Recall is TP / (TP + FN), how many actual positives were found. F1 is their harmonic mean. For a loan default model, recall matters if missing defaulters is costly; precision matters if rejecting good customers is costly.
155

What are the assumptions of linear regression?

Save to ▾
Show answer
The main assumptions are a linear relationship between predictors and the outcome, independent errors, constant variance of errors (homoscedasticity), normally distributed errors for valid inference and no severe multicollinearity. In R, plot(fit) shows residuals versus fitted values, a Q-Q plot and leverage, and car::vif() checks collinearity. Violations can be addressed with transformations like log, robust standard errors or different models such as GLMs.
156

Why should we hire you as a fresher for an R analyst role?

Save to ▾
Show answer
I have practical R skills, not just theory. In my projects I cleaned real datasets with dplyr, built ggplot2 dashboards and ran regression and hypothesis tests, and I can explain results simply. I also know SQL, which most analytics work needs. I learn quickly, accept feedback well and care about accuracy, so I double-check numbers before sharing them. I am ready to start contributing to reporting tasks from the first month.
157

How do you interpret the summary output of an lm() model?

Save to ▾
Show answer
Each coefficient is the expected change in the outcome for a one-unit increase in that predictor, holding others constant. The p-value tests whether the coefficient differs from zero. R-squared is the share of variance explained, and adjusted R-squared penalizes extra predictors. Residual standard error shows typical prediction error in outcome units. The F-statistic tests whether the model beats an intercept-only model. For factors, coefficients are differences from the reference level.
158

How do you build a logistic regression model for churn in R?

Save to ▾
Show answer
Use glm() with family = binomial; predictions with type = 'response' are probabilities. fit <- glm(churned ~ tenure + monthly_charges + contract, data = train, family = binomial) summary(fit) exp(coef(fit)) # odds ratios test$prob <- predict(fit, newdata = test, type = 'response') test$pred <- ifelse(test$prob > 0.5, 1, 0) table(actual = test$churned, predicted = test$pred)
159

What is tidymodels and how does it compare with caret?

Save to ▾
Show answer
tidymodels is a collection of packages for modelling with tidyverse principles: rsample for splitting and resampling, recipes for preprocessing, parsnip for a unified model interface, workflows to bundle them, tune for hyperparameter tuning and yardstick for metrics. caret, by the same original author, is an older single package that does similar work with one train() function. caret is stable and still widely used, but new development happens in tidymodels.
160

Write a tidymodels workflow to train and evaluate a random forest.

Save to ▾
Show answer
Split, preprocess, specify, fit and evaluate: library(tidymodels) set.seed(42) split <- initial_split(df, prop = 0.8, strata = churned) train <- training(split); test <- testing(split) rec <- recipe(churned ~ ., data = train) %>% step_impute_median(all_numeric_predictors()) %>% step_dummy(all_nominal_predictors()) rf <- rand_forest(trees = 500) %>% set_engine('ranger') %>% set_mode('classification') wf_fit <- workflow() %>% add_recipe(rec) %>% add_model(rf) %>% last_fit(split) collect_metrics(wf_fit)
161

You are building a fraud model where only 0.5 percent of transactions are fraud. How do you handle the imbalance?

Save to ▾
Show answer
Accuracy is useless here, since predicting no fraud gives 99.5 percent. I use stratified splits and evaluate with precision, recall, F1 and the precision-recall AUC. To help the model learn the minority class, I try class weights, downsampling the majority or SMOTE through the themis package in a recipe, applied only to training data. Then I tune the probability threshold based on the cost of missed fraud versus false alarms agreed with the business.
162

Your model has R-squared 0.92 on training data but 0.55 on test data. What do you do?

Save to ▾
Show answer
The gap indicates overfitting or data leakage. I first check for leakage, such as a feature computed using future information or the target itself, or duplicate records across train and test. Then I simplify the model, add regularization, reduce features or tune hyperparameters with cross-validation instead of a single split. If data is time-based, I make sure the split is chronological. I compare against a simple baseline to judge real improvement.
163

How does a random forest work and which R packages implement it?

Save to ▾
Show answer
A random forest builds many decision trees, each on a bootstrap sample of rows and considering a random subset of features at each split, then averages their predictions for regression or takes a majority vote for classification. This reduces the variance of single trees and handles non-linear relationships well. In R, randomForest is the classic package and ranger is a much faster implementation. Key parameters are the number of trees, mtry and minimum node size.
164

In your regression, coefficient signs look wrong and standard errors are huge. What might be the problem?

Save to ▾
Show answer
This is a classic sign of multicollinearity, where predictors are highly correlated, for example total spend and online spend. The model cannot separate their effects, so coefficients become unstable. I check correlations and the variance inflation factor with car::vif(); values above 5 or 10 are a concern. Solutions are removing or combining correlated variables, using principal components or ridge regression. Prediction accuracy may be fine, but interpretation is unreliable.
165

How do you perform k-means clustering in R?

Save to ▾
Show answer
Scale features first, choose k using the elbow or silhouette method, then fit. library(factoextra) X <- scale(customers[, c('recency', 'frequency', 'monetary')]) fviz_nbclust(X, kmeans, method = 'wss') # elbow fviz_nbclust(X, kmeans, method = 'silhouette') set.seed(42) km <- kmeans(X, centers = 4, nstart = 25) customers$segment <- km$cluster aggregate(cbind(recency, frequency, monetary) ~ segment, data = customers, FUN = mean)
166

How do you do feature engineering with recipes in tidymodels?

Save to ▾
Show answer
A recipe defines preprocessing steps that are learned on training data and applied identically to new data. rec <- recipe(price ~ ., data = train) %>% update_role(listing_id, new_role = 'id') %>% step_date(listed_on, features = c('month', 'dow')) %>% step_rm(listed_on) %>% step_log(area_sqft) %>% step_other(locality, threshold = 0.01) %>% step_dummy(all_nominal_predictors()) %>% step_normalize(all_numeric_predictors()) prep(rec) %>% bake(new_data = NULL) %>% glimpse()
167

What tools does R offer for time series forecasting?

Save to ▾
Show answer
The forecast package provides auto.arima(), ets() for exponential smoothing and easy plotting of forecasts with intervals. The newer tidyverts family, with tsibble for time-series data frames, fable for models and feasts for features and decomposition, works with tidy data and fits many series at once. prophet handles strong seasonality and holidays. Typical steps are visualizing, decomposing trend and seasonality, fitting candidates and comparing accuracy on a holdout period.
168

How do you calculate ROC AUC and plot an ROC curve in R?

Save to ▾
Show answer
yardstick in tidymodels or pROC compute AUC from predicted probabilities. library(yardstick) preds <- tibble(truth = factor(test$churned, levels = c('1', '0')), .pred_1 = test$prob) roc_auc(preds, truth, .pred_1) roc_curve(preds, truth, .pred_1) %>% autoplot() # with pROC library(pROC) r <- roc(test$churned, test$prob) auc(r); plot(r)
169

Walk me through an end-to-end machine learning project you have done in R.

Save to ▾
Show answer
Situation: a lending team wanted to reduce early loan defaults. Task: build a default risk score. Action: I cleaned two years of loan data with dplyr, engineered features like EMI to income ratio with recipes, compared logistic regression and ranger in tidymodels using 5-fold cross-validation and chose logistic regression for interpretability with AUC 0.78. Result: the score was used in a pilot, flagging 60 percent of defaulters in the riskiest 20 percent of applicants.
170

A predictor such as pincode has 500 levels. How do you use it in a model?

Save to ▾
Show answer
Dummy-encoding 500 levels creates sparse, noisy features and overfits rare levels. I first lump rare levels into 'other' with step_other(). Then I consider target or effect encoding with the embed package, applied inside cross-validation to avoid leakage, or mapping pincodes to meaningful higher-level features such as city tier, region or distance to a warehouse. Tree models in some engines handle many levels better, but grouping by business meaning usually works best.
171

You are asked to forecast daily demand for the Diwali season. How do you approach it?

Save to ▾
Show answer
I gather at least two or three years of daily history, since festive peaks happen once a year and Diwali moves across October and November. I add holiday regressors for Diwali, Dussehra and sale events rather than relying on calendar seasonality alone. I compare models like ETS, ARIMA with regressors and prophet in fable, validating on past festive seasons. I report prediction intervals and review with business teams for planned promotions or stock limits.
172

What is regularization and how do you apply it in R?

Save to ▾
Show answer
Regularization adds a penalty on coefficient size to reduce overfitting. Ridge (L2) shrinks all coefficients toward zero, useful with correlated predictors. Lasso (L1) can shrink some to exactly zero, performing feature selection. Elastic net mixes both. In R, glmnet fits these models, with alpha = 0 for ridge and alpha = 1 for lasso, and cv.glmnet() chooses the penalty lambda by cross-validation. Predictors should be standardized, which glmnet does by default.
173

Business users do not trust your gradient boosting model because it is a black box. What do you do?

Save to ▾
Show answer
I explain both global and individual behaviour. Globally, I show variable importance and partial dependence plots, using DALEX or the vip package, to show how key features affect predictions. For individual cases I use SHAP values, for example through the shapviz or fastshap packages, so a manager can see why a customer was flagged. I compare against a simple logistic model and walk users through real examples they know.
174

Your R model must score new customers every morning for the CRM team. How would you deploy it?

Save to ▾
Show answer
I save the fitted workflow, including the recipe, with saveRDS() or the vetiver package, which versions models and adds monitoring. For batch scoring, a scheduled R script reads new customers from the database, predicts and writes scores back, run by cron, Posit Connect or a container in the cloud. For real-time needs, I expose the model as a REST API with plumber or vetiver in Docker. I log inputs and track drift.
175

Tell me about a time a model you built did not perform as expected after deployment.

Save to ▾
Show answer
Situation: a demand model I built performed well in testing but its errors doubled two months after launch. Task: diagnose and fix it. Action: I compared input distributions and found a new product category and a pricing change that the training data never saw. I added drift monitoring, retrained with recent data and set up monthly retraining. Result: accuracy returned to target, and I learned to plan monitoring before deployment, not after.
176

What is R Markdown and why is it useful?

Save to ▾
Show answer
R Markdown is a file format that combines narrative text written in Markdown with R code chunks. When rendered with knitr, the code runs and its output, such as tables and charts, is inserted into an HTML, PDF or Word document. This makes reports reproducible: when data changes, you re-render instead of copying charts manually. It is used for monthly reports, research papers, client deliverables and teaching material.
177

What is Shiny and how is a Shiny app structured?

Save to ▾
Show answer
Shiny is an R package for building interactive web applications without writing HTML or JavaScript. An app has a ui that defines layout and inputs such as dropdowns and sliders, and a server function that contains R logic and creates outputs such as plots and tables. shinyApp(ui, server) runs the app. Analytics teams use Shiny for internal dashboards, what-if calculators and tools that let business users explore data.
178

What is renv and why should you use it?

Save to ▾
Show answer
renv is a package that creates a project-specific library and records exact package versions in a renv.lock file. renv::init() sets up the project, renv::snapshot() updates the lockfile and renv::restore() installs the same versions on another machine or server. This prevents code from breaking when packages update, makes analysis reproducible months later and is essential before deploying scripts or Shiny apps to production.
179

How do you connect R to a SQL database and run queries?

Save to ▾
Show answer
DBI provides a common interface, with drivers such as RPostgres, RMariaDB or odbc. library(DBI) con <- dbConnect(RPostgres::Postgres(), host = Sys.getenv('DB_HOST'), dbname = 'sales', user = Sys.getenv('DB_USER'), password = Sys.getenv('DB_PASS')) orders <- dbGetQuery(con, 'SELECT * FROM orders WHERE order_date >= $1', params = list('2026-01-01')) dbWriteTable(con, 'daily_summary', summary_df, append = TRUE) dbDisconnect(con)
180

Why should R projects use Git and how does RStudio support it?

Save to ▾
Show answer
Git tracks every change to code, lets you revert mistakes, work on branches and collaborate through pull requests and reviews. RStudio has a built-in Git pane to stage, commit, diff, pull and push, and usethis::use_git() and use_github() set up repositories. Keep data files, secrets and outputs out of Git with .gitignore, commit the renv.lock file and write clear commit messages. Version control is expected even for analysis work.
181

The finance team wants the daily output as a formatted Excel file, not a CSV. How do you produce it?

Save to ▾
Show answer
I use openxlsx2 or openxlsx to write a workbook with multiple sheets, formatted headers, number formats for INR, column widths, frozen panes and conditional formatting, all from R. writexl is a lightweight option for plain sheets without formatting. I create a template once with the team's preferred layout and generate the file in the scheduled script, then email or upload it to a shared drive. This removes manual formatting every day.
182

Where do you see yourself in three years in an R or analytics career?

Save to ▾
Show answer
In three years I see myself as a strong data analyst or junior data scientist who can own analyses end to end, from understanding the business question to building reproducible reports and models in R. I want to deepen my statistics and machine learning skills and learn cloud tools used by the team. I would also like to mentor new joiners, as seniors helped me, and contribute to reusable internal tools.
183

What is the difference between Quarto and R Markdown?

Save to ▾
Show answer
Quarto is the next-generation publishing system from Posit. It works with R, Python, Julia and Observable, and is a standalone command-line tool rather than an R package. It uses the same knitr engine for R and similar syntax, with chunk options written as #| comments. Quarto adds consistent support for websites, books, presentations and dashboards. R Markdown is still supported, but new projects increasingly use Quarto, especially in mixed R and Python teams.
184

Explain reactivity in Shiny.

Save to ▾
Show answer
Shiny uses reactive programming: outputs automatically update when the inputs they depend on change. Inputs are reactive sources, outputs such as renderPlot() are reactive endpoints, and reactive() expressions are cached intermediate results that recompute only when their dependencies change. For example, filtering data once in a reactive() and using it in three charts avoids filtering three times. Shiny tracks dependencies automatically, so you do not write explicit event handlers for most cases.
185

Write a minimal Shiny app that filters sales by region and plots them.

Save to ▾
Show answer
A ui with an input and an output, and a server that reacts to the input: library(shiny); library(ggplot2); library(dplyr) ui <- fluidPage( selectInput('region', 'Region', choices = unique(sales$region)), plotOutput('trend') ) server <- function(input, output, session) { filtered <- reactive(filter(sales, region == input$region)) output$trend <- renderPlot({ ggplot(filtered(), aes(month, revenue)) + geom_line() }) } shinyApp(ui, server)
186

How do you generate the same report for each of 20 regions automatically?

Save to ▾
Show answer
Use a parameterized Quarto or R Markdown report and render it in a loop. # report.qmd header: # params: # region: 'North' # then use params$region in the code regions <- unique(sales$region) purrr::walk(regions, function(r) { quarto::quarto_render( 'report.qmd', execute_params = list(region = r), output_file = paste0('report_', r, '.html') ) })
187

Your team wants to share a Shiny app with 200 internal users. What deployment options exist?

Save to ▾
Show answer
Options include shinyapps.io, a hosted service that is quickest to start but may not suit sensitive internal data, Posit Connect, a commercial on-premise or cloud server with authentication, scheduling and scaling, the free open-source Shiny Server on a Linux machine, and a Docker container behind a reverse proxy like Nginx, often with ShinyProxy for authentication. For internal data, I would choose Connect or containers inside the company network with single sign-on.
188

What is the structure of an R package?

Save to ▾
Show answer
A minimal package has a DESCRIPTION file with metadata and dependencies, a NAMESPACE file listing exported functions, an R/ folder with function code, a man/ folder for documentation and usually tests/ for testthat tests. The usethis and devtools packages create and manage this: usethis::create_package(), use_r(), use_test(), and devtools::document(), test() and check(). Documentation is written as roxygen2 comments above each function. Internal packages are ideal for sharing team utilities.
189

How do you write unit tests for an R function?

Save to ▾
Show answer
testthat organises tests into files under tests/testthat/ using expectations. # tests/testthat/test-gst.R test_that('gst_price adds 18 percent by default', { expect_equal(gst_price(100), 118) expect_equal(gst_price(c(100, 200)), c(118, 236)) }) test_that('gst_price rejects text input', { expect_error(gst_price('abc'), 'numeric') }) # run all tests devtools::test()
190

An R script must run every morning at 7 AM and email a report. How do you schedule it?

Save to ▾
Show answer
On a Linux server I schedule Rscript with cron, for example 0 7 * * * Rscript /path/report.R, and on Windows with Task Scheduler or the taskscheduleR package. Posit Connect can schedule Quarto reports and email them directly. GitHub Actions can run scheduled workflows for non-sensitive jobs. The script itself renders the report and sends it with blastula or emayili. I add logging and an alert on failure so silent misses are caught.
191

You notice database passwords hardcoded in a shared R script. What do you do?

Save to ▾
Show answer
I remove them immediately, inform the owner and ask for the password to be rotated, since it may exist in version history. Then I store credentials outside the code, in a user-level .Renviron file read with Sys.getenv(), the keyring package backed by the operating system's credential store, or the server's secret management, such as environment variables in Posit Connect. I make sure .Renviron is listed in .gitignore and scan the repository history.
192

What is plumber in R?

Save to ▾
Show answer
plumber turns R functions into REST API endpoints using special comments. You annotate a function with #* @get /predict and its arguments become query parameters, then run the API with pr_run(). Other systems, such as a Java web app or a Python service, can call the R model over HTTP and receive JSON. It is commonly used to serve model predictions, and it can be deployed in Docker or on Posit Connect.
193

Code reviews show inconsistent R code style across the team. How would you standardise it?

Save to ▾
Show answer
I would adopt the tidyverse style guide as the team standard, then automate it rather than relying on reviewers. styler reformats code automatically, including an RStudio add-in, and lintr flags issues such as long lines, unused variables and inconsistent naming. I add lintr to a pre-commit hook or a GitHub Actions check so pull requests are checked automatically. A short template for new scripts and projects helps new joiners follow the same structure.
194

How do you add logging to a production R script?

Save to ▾
Show answer
The logger package gives levelled, timestamped logs written to the console or a file. library(logger) log_appender(appender_file('logs/etl.log')) log_threshold(INFO) log_info('ETL started') res <- tryCatch({ df <- load_orders() log_info('Loaded {nrow(df)} rows') df }, error = function(e) { log_error('Load failed: {conditionMessage(e)}') quit(status = 1) }) log_info('ETL finished')
195

Tell me about a dashboard or app you built in R.

Save to ▾
Show answer
Situation: regional sales managers waited for a weekly emailed PDF and could not drill into their own data. Task: give them self-service access. Action: I built a Shiny app with filters by region, product and period, used pre-aggregated tables for speed and deployed it on the internal server with login. I ran a short demo and gathered feedback. Result: over 40 managers used it weekly, and ad hoc data requests to our team fell by about half.
196

Describe a disagreement with a teammate about a technical approach.

Save to ▾
Show answer
Situation: a teammate wanted to build our reporting pipeline in Excel macros, while I preferred R scripts. Task: agree on an approach quickly. Action: instead of arguing, we listed requirements together: refresh frequency, data size and who would maintain it. I built a small R prototype in a day to compare. Result: we chose R for the pipeline and kept an Excel output for users, and my teammate later helped improve the formatting.
197

Your Shiny dashboard becomes very slow when 50 users open it at once. How do you improve it?

Save to ▾
Show answer
I profile with profvis and reactlog to find slow reactives. I move heavy data loading outside the server function so it runs once per process, pre-aggregate data instead of computing on raw rows, and cache results with bindCache(). I use bindEvent() so expensive work runs only on a button click. Long computations can go to background tasks with ExtendedTask and promises. Finally I scale out with multiple R processes on Posit Connect or Shiny Server Pro.
198

What is the difference between reactive(), observe() and observeEvent() in Shiny?

Save to ▾
Show answer
reactive() creates a cached value that other code can read, such as filtered data, and it is lazy, recomputing only when needed. observe() runs code for its side effects whenever any reactive dependency changes, returning nothing. observeEvent() runs side effects only when a specific event fires, such as a button click, ignoring other dependencies. Use reactive() for computing values and observeEvent() for actions like saving data or showing notifications.
199

Your R pipeline works on your laptop but fails on the Linux server because of missing system libraries. How do you fix it permanently?

Save to ▾
Show answer
Packages like sf, xml2 or RPostgres need system libraries such as GDAL, libxml2 or libpq, which differ between machines. I would containerize the pipeline with Docker, starting from a rocker image like rocker/r-ver pinned to the R version, installing system dependencies in the Dockerfile and restoring packages with renv. The same image then runs on laptops, servers and the cloud, eliminating environment differences between development and production.
200

Tell me about a time a production job failed and you had to fix it under pressure.

Save to ▾
Show answer
Situation: the scheduled R job feeding the morning leadership dashboard failed at 6 AM after a source table added a new column type. Task: restore the dashboard before the 9 AM meeting. Action: I checked the logs, identified the parsing error, patched the column specification, reran the job and informed stakeholders of the delay. Afterwards I added schema validation and a failure alert. Result: data was live by 8:30 AM, and similar changes are now caught early.

Frequently asked questions

What jobs can I get after learning R programming?

R skills lead to roles such as Data Analyst, R Programmer, Statistical Programmer, Biostatistician, Data Scientist, Shiny Developer and Analytics Consultant. Analytics firms, consulting companies, pharma and clinical research organizations, banks, insurance companies and market research agencies hire R professionals. Freshers usually start as analysts working on reporting and data cleaning, then grow into modelling, statistical programming or dashboard development roles as they build experience and domain knowledge.

Who is eligible to learn R programming?

Anyone comfortable with basic mathematics can learn R. Students and graduates from B.Sc, B.Com, BBA, BCA, B.Tech, statistics, economics, life sciences and pharmacy backgrounds commonly take it up. Working professionals in finance, research, operations or Excel-heavy roles also switch to R for analytics. No prior coding experience is required, although basic statistics and SQL knowledge will help you progress faster and perform better in interviews.

How long does it take to learn R for a job?

With regular practice of one to two hours daily, most learners become job-ready for an entry-level analyst role in about three months. The first month covers fundamentals and data wrangling, the second visualization and statistics, and the third modelling, reporting and projects. Becoming strong in advanced areas such as Shiny development, statistical programming or machine learning usually takes another six to twelve months of hands-on work.

Is R still relevant in 2026 compared with Python?

Yes. R remains a leading language for statistics, biostatistics, clinical research, econometrics and reproducible reporting, and the tidyverse, tidymodels, Quarto and Shiny ecosystems are actively developed. Python is more common for general software and deep learning, so many teams use both. Learning R deeply along with SQL and basic Python makes you flexible across analytics, research and data science roles in India.

Do I need a certification to get an R job?

A certification helps show structured learning, but employers mainly judge practical ability. A course completion certificate combined with a portfolio of three or four projects on GitHub, such as a cleaned dataset analysis, a Quarto report, a predictive model and a Shiny dashboard, is far more convincing. Be ready to write dplyr and ggplot2 code live and to explain statistical results clearly during interviews.

What projects should I build to get hired as an R analyst?

Build projects that mirror real work: a sales or e-commerce analysis with dplyr and ggplot2, an A/B test analysis with proper hypothesis testing, a churn or credit risk model in tidymodels, a time series forecast for demand and an interactive Shiny dashboard. Use public Indian datasets where possible, publish code on GitHub with clear README files and write short summaries of business insights for each project.