American Express R Programming Interview Questions & Answers
Curated interview practice questions with answers. These are practice scenarios, not a verified list of past interview questions.
About American Express hiring for R Programming roles
American Express is a global payments and card company offering charge and credit cards, travel services and merchant acquiring. Its India centres in Gurugram and Bengaluru support technology, risk, analytics and servicing. It hires for software engineers, QA engineers, data analysts, data scientists and credit risk analysts.
For R Programming roles, this American Express practice set focuses most on Data Wrangling with dplyr and tidyr (5), Modelling and Machine Learning in R (5), Reports, Shiny and Production R (5), Data Structures in R (5). It has 7 easy, 22 medium, 1 hard questions, so you can start easy and work up to the harder ones.
Company type
Banking & finance
Headquarters
New York, USA
Main India offices
Gurugram, Bengaluru
American Express R Programming interview process
Online assessment (aptitude + coding or analytics)
Technical round
Case or domain round
Hiring manager round
HR round
Typical pattern based on public candidate experiences. Rounds vary by role, team and year.
Solved for American ExpressStart 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
How would you impute missing values differently for each group?
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.
02
Your data is heavily skewed and the sample is small. Can you still use a t-test?
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.
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.
05
How would you compare R and Python for a data role?
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.
06
How do you reshape data between wide and long formats in R?
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')
)
})
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.
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.
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.
12
What is the difference between Pearson and Spearman correlation?
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.
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.
14
How do you interpret the summary output of an lm() model?
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.
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.
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.
17
Show different ways to index vectors and data frames in R.
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
18
Your model has R-squared 0.92 on training data but 0.55 on test data. What do you do?
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.
19
Your R script works on your laptop but fails on a colleague's machine with 'could not find function'. What do you check?
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.
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.
21
Tell me about a time you had two urgent analysis requests at the same time.
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.
22
How do you apply the same transformation to many columns in dplyr?
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}'))
23
How does a random forest work and which R packages implement it?
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.
24
You receive 60 monthly CSV files with the same structure. How do you combine them into one data frame?
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.
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.
26
You need month-over-month sales growth for each product. How do you calculate it in R?
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.
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.
28
How do you produce descriptive statistics for each group in R?
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.
30
How do you build a logistic regression model for churn in R?
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)
Tips to crack the American Express R Programming interview
Learn credit card business basics like spend, revolve, delinquency and customer lifetime value for analytics interviews.
Practise SQL, Python and statistics, including model evaluation for risk or marketing use cases.
Read about American Express's Blue Box values and its strong focus on customer service.
Keep a one-minute story ready for every project on your CV: problem, your part, tools, result.
Practise the hard questions on this page aloud; American Express interviewers usually ask follow-ups on your first answer.
Frequently asked questions
How many rounds are there in the American Express R Programming interview?
Candidates usually go through 5 stages: Online assessment (aptitude + coding or analytics); Technical round; Case or domain round; Hiring manager round; HR round. The exact rounds change with the role, team, location and your experience, so confirm the process with the recruiter.
Which topics should I prepare for the American Express R Programming interview?
This practice set leans on Data Wrangling with dplyr and tidyr (5), Modelling and Machine Learning in R (5), Reports, Shiny and Production R (5), Data Structures in R (5). Revise those first, then practise explaining one or two of your own projects end to end, because most American Express interviewers ask you to walk through real work.
Are these the exact questions asked at American Express?
No. These are curated practice questions that match the skills and difficulty usually tested in banking & finance interviews like American Express's. They are not a leaked or verified list of past questions.
Where does American Express hire R Programming professionals in India?
American Express has large teams in Gurugram, Bengaluru. Openings and locations change often, so check the American Express careers page and filter by city and experience.