R: R Data Analysis Report
Last updated: 2026-08-26
This is the final lesson of the R tutorial—it brings together everything you’ve learned in the previous 29 lessons to create a complete end-to-end project. From reading data to cleaning it, performing exploratory data analysis (EDA), building models, visualizing results, and generating reports, this lesson simulates a typical day in the life of a data analyst.
After completing this lesson, you’ll be able to independently complete a full R data analysis project—at the level of a data science job interview portfolio.
1. What You'll Learn
- 6-stage end-to-end project (Data → Cleaning → EDA → Modeling → Visualization → Reporting)
- Comprehensive use of: readr + tidyr + dplyr + ggplot2 + broom + rmarkdown
- R Markdown automatically generates reports
- saveRDS Persistence and Model Deployment
- Generate PDF/HTML reports
- Practical Guide: Comprehensive Report on Customer Behavior Analysis
2. A Day in the Life of a Data Analyst
(1) Pain Point: It takes 3 days to turn data into a report
Alice is a data analyst who has been assigned the task of analyzing customer behavior in 2024 and providing her manager with a comprehensive report.
Traditional process: Import Excel data → Clean the data → Create an Excel pivot table → Generate a chart → Copy to PowerPoint → Write the analysis → Manager requests to see it one week later.
(2) Solution using R
# 1. One line R Markdown Report
rmarkdown::render('customer_analysis.Rmd')
1 line of code → Complete HTML/PDF report (including code, results, charts, and analysis).
3. The 6 Stages of an End-to-End Project
graph TB
A[1. Data Loading] --> B[2. Data Cleaning]
B --> C[3. EDA Explore]
C --> D[4. Descriptive Statistics]
D --> E[5. Modeling and Analysis]
E --> F[6. Visualization and Reporting]
A --> A1[readr/DBI]
B --> B1[tidyr/stringr]
C --> C1[skimr/GGally]
D --> D1[dplyr summary]
E --> E1[lm/glm]
F --> F1[ggplot2/Rmd]
style A fill:#fff3cd
style B fill:#cce5ff
style C fill:#d4edda
style D fill:#f8d7da
style E fill:#e1d4ff
style F fill:#ffe1d4
(1) 6-Stage Goals
| Phase | Objective | Output |
|---|---|---|
| 1. Loading Data | Reading Data | tibble |
| 2. Data Cleaning | Handling Missing/Outlier/Duplicate Values | Clean tibble |
| 3. EDA | Explore Distribution/Relationships | Charts + Statistics |
| 4. Descriptive Statistics | Key Metrics | Summary Table |
| 5. Modeling | Regression/Classification/Clustering | Model Objects |
| 6. Report | Synthesis + Analysis | HTML/PDF |
4. Hands-On: End-to-End Customer Behavior Analysis Project
(1) Complete R script
# ============================================
# Customer Behavior Analysis - End-to-End Projects
# Stage: 1. Data Loading -> 6. Report Output
# ============================================
library(readr)
library(dplyr)
library(tidyr)
library(stringr)
library(lubridate)
library(ggplot2)
library(broom)
library(skimr)
# ========== Stage 1: Data Loading ==========
cat('=== Stage 1: Data Loading ===\n')
set.seed(42)
n <- 2000
customers_raw <- tibble(
customer_id = 1:n,
age = round(rnorm(n, 35, 12)),
gender = sample(c('M', 'F'), n, replace = TRUE),
city = sample(c('Beijing', 'Shanghai', 'Guangzhou', 'Shenzhen', 'Hangzhou'), n, replace = TRUE),
register_date = sample(seq(as.Date('2023-01-01'),
as.Date('2024-06-30'), by = 'day'), n, replace = TRUE),
monthly_visits = round(rnorm(n, 10, 5)),
avg_order_value = round(rnorm(n, 200, 80)),
support_calls = sample(0:10, n, replace = TRUE),
plan = sample(c('Basics', 'Advanced', 'Company'), n, replace = TRUE,
prob = c(0.5, 0.3, 0.2))
) |>
mutate(
logit_p = -2 + 0.02 * age - 0.05 * monthly_visits + 0.2 * support_calls,
p = 1 / (1 + exp(-logit_p)),
churn = rbinom(n, 1, p)
) |>
select(-logit_p, -p) |>
mutate(
age = ifelse(row_number() %in% sample(n, 10), NA, age),
avg_order_value = ifelse(row_number() %in% sample(n, 5), -999, avg_order_value),
register_date = ifelse(row_number() %in% sample(n, 8), NA, register_date)
)
write_csv(customers_raw, 'customer_raw.csv')
cat('Loaded', nrow(customers_raw), 'Raw Data Row\n\n')
# ========== Stage 2: Data Cleaning ==========
cat('=== Stage 2: Data Cleaning ===\n')
customers <- customers_raw |>
janitor::clean_names() |>
distinct() |>
mutate(
age = ifelse(is.na(age) | age < 0 | age > 150,
median(age[age > 0 & age < 150], na.rm = TRUE), age),
avg_order_value = ifelse(avg_order_value < 0, NA, avg_order_value)
) |>
drop_na(register_date) |>
filter(monthly_visits >= 0, support_calls >= 0)
cat('After cleaning:', nrow(customers), 'rows\n')
cat(' - Duplicates:', nrow(customers_raw) - nrow(distinct(customers_raw)), 'removed\n')
cat(' - Age Missing/Exception: Processed\n')
cat(' - Abnormal Order Amount: Set to NA\n\n')
# ========== Stage 3: EDA Explore ==========
cat('=== Stage 3: EDA Explore ===\n')
cat('Data Dimensions:', nrow(customers), 'rows x', ncol(customers), 'cols\n')
cat('Churn rate:', round(mean(customers$churn) * 100, 2), '%\n')
churn_by_plan <- customers |>
group_by(plan) |>
summarise(
n = n(),
churn_rate = round(mean(churn) * 100, 2),
avg_age = round(mean(age), 1),
avg_visits = round(mean(monthly_visits), 1)
)
cat('\nChurn Rate by Plan Type:\n')
print(churn_by_plan)
p1 <- ggplot(customers, aes(x = monthly_visits, y = avg_order_value,
color = factor(churn))) +
geom_point(alpha = 0.5) +
geom_smooth(method = 'lm', se = FALSE) +
scale_color_brewer(palette = 'Set1', labels = c('Not lost', 'Loss')) +
labs(title = 'Number of visits vs Average Order Value',
x = 'Monthly Visits', y = 'Average Order Value', color = 'Status') +
theme_minimal()
cat('Generate 2 Key Charts\n\n')
# ========== Stage 4: Descriptive Statistics ==========
cat('=== Stage 4: Descriptive Statistics ===\n')
key_metrics <- customers |>
summarise(
Total Number of Customers = n(),
Number of Lost Customers = sum(churn),
Churn rate = round(mean(churn) * 100, 2),
Average Age = round(mean(age), 1),
Average Monthly Visits = round(mean(monthly_visits), 1),
Average Order Value = round(mean(avg_order_value, na.rm = TRUE), 2),
Average Number of Customer Service Inquiries = round(mean(support_calls), 1)
)
print(key_metrics)
by_city <- customers |>
group_by(city) |>
summarise(
Number of customers = n(),
Churn rate = round(mean(churn) * 100, 2),
Average Order = round(mean(avg_order_value, na.rm = TRUE), 2)
) |>
arrange(desc(Number of customers))
cat('\nBy City:\n')
print(by_city)
cat('\n')
# ========== Stage 5: Modeling and Analysis ==========
cat('=== Stage 5: Modeling and Analysis ===\n')
# 5.1 Logistic Regression: Churn Prediction
churn_model <- glm(churn ~ age + gender + plan + monthly_visits +
avg_order_value + support_calls,
data = customers, family = binomial)
cat('Logistic Regression Model:\n')
summary(churn_model)
cat('\nOdds Ratio Analysis:\n')
or_df <- tidy(churn_model, conf.int = TRUE, exponentiate = TRUE) |>
filter(term != '(Intercept)')
print(or_df |> select(term, estimate, std.error, p.value, conf.low, conf.high))
# 5.3 Linear Regression: Visits Forecast
visit_model <- lm(monthly_visits ~ age + plan + avg_order_value,
data = customers)
cat('\nVisits Forecast Model:\n')
summary(visit_model)
# 5.4 Model Evaluation
library(pROC)
customers$churn_prob <- predict(churn_model, type = 'response')
roc_obj <- roc(customers$churn, customers$churn_prob)
cat('\nChurn Model AUC:', round(auc(roc_obj), 3), '\n\n')
# ========== Stage 6: Visualization and Reporting ==========
cat('=== Stage 6: Visualization and Reporting ===\n')
p2 <- customers |>
group_by(plan, churn) |>
summarise(n = n(), .groups = 'drop') |>
ggplot(aes(x = plan, y = n, fill = factor(churn))) +
geom_col(position = 'fill') +
scale_y_continuous(labels = scales::percent) +
scale_fill_brewer(palette = 'Set1', labels = c('Not lost', 'Loss')) +
labs(title = 'Churn Rates by Plan Type', x = 'Plan', y = 'Ratio', fill = 'Status') +
theme_minimal()
p3 <- customers |>
group_by(plan) |>
summarise(
n = n(),
churn_rate = mean(churn)
) |>
ggplot(aes(x = plan, y = churn_rate, fill = plan)) +
geom_col() +
geom_text(aes(label = paste0(round(churn_rate * 100, 1), '%')),
vjust = -0.5) +
scale_y_continuous(labels = scales::percent,
expand = expansion(mult = c(0, 0.15))) +
labs(title = 'Churn Rates by Plan Type', x = 'Plan', y = 'Churn rate') +
theme_minimal() +
theme(legend.position = 'none')
p4 <- ggplot(customers, aes(x = plan, y = monthly_visits, fill = plan)) +
geom_boxplot() +
labs(title = 'Distribution of Monthly Visits by Plan', x = 'Plan', y = 'Monthly Visits') +
theme_minimal() +
theme(legend.position = 'none')
# 6.2 Save Chart
ggsave('chart_visits_vs_order.png', p1, width = 8, height = 6, dpi = 300)
ggsave('chart_churn_by_plan.png', p2, width = 8, height = 6, dpi = 300)
ggsave('chart_churn_rate.png', p3, width = 8, height = 6, dpi = 300)
ggsave('chart_visits_by_plan.png', p4, width = 8, height = 6, dpi = 300)
# 6.3 Save Model
saveRDS(churn_model, 'churn_model.rds')
saveRDS(visit_model, 'visit_model.rds')
# 6.4 Save the processed data
write_csv(customers, 'customer_clean.csv')
saveRDS(customers, 'customer_clean.rds')
# 6.5 Summary of Business Insights
cat('\n=== Summary of Business Insights ===\n')
cat('1. Overall attrition rate:', round(mean(customers$churn) * 100, 2), '%\n')
cat('2. Customers with >5 support calls churn rate:',
round(mean(customers$churn[customers$support_calls > 5]) * 100, 2), '%\n')
cat('3. Customers with <5 monthly visits churn rate:',
round(mean(customers$churn[customers$monthly_visits < 5]) * 100, 2), '%\n')
cat('4. The Basic Plan has the highest churn rate (',
round(mean(customers$churn[customers$plan == 'Basics']) * 100, 2), '%)\n')
cat('5. Older age and fewer visits -> higher probability of attrition\n')
cat('6. Suggestion: Add customers with >5 support calls to the high-risk list, proactively retain\n')
cat('\n=== All Done ===\n')
cat('Output Files:\n')
cat(' - customer_raw.csv (Raw Data)\n')
cat(' - customer_clean.csv / .rds (Data After Cleaning)\n')
cat(' - chart_*.png (4 charts)\n')
cat(' - churn_model.rds (Churn Prediction Model)\n')
cat(' - visit_model.rds (Visits Forecast Model)\n')
(2) R Markdown Report Template (Simplified Version)
Create a new customer_report.Rmd file with the complete Rmd template structure (YAML + 6 sections + R code blocks + explanatory text):
YAML metadata (at the beginning of the file): define title / author / output format (html_document + theme: flatly + toc: true).
6 Main Chapters:
- Project Overview - A brief background introduction + 3 analysis objectives
- Data Overview - Load cleaned data + Skimr summary
- Exploratory Analysis - Churn Rate + Distribution by Plan + Scatter Plot
- Statistical Model - Load the saved churn_model.rds file and tidy it up to display OR
- Key Findings - bulleted list, 3–5 items OR interpretation
- Business Recommendations - 3 actionable recommendations + list of appendices
Each chapter is separated by R code blocks (```{r}) embedding analysis code, with ## 1. xxx / ## 2. xxx headings between sections.
(3) Generate a report
# Generate HTML Report
rmarkdown::render('customer_report.Rmd',
output_format = 'html_document',
output_file = 'customer_report.html')
# Generate PDF Report (LaTeX installation required)
rmarkdown::render('customer_report.Rmd',
output_format = 'pdf_document',
output_file = 'customer_report.pdf')
Expected Output:
- 1 HTML report of 10–15 pages (including code, results, charts, and analysis)
- 4 PNG charts
- 2 .rds models
- 1 CSV file containing clean data
5. Complete Learning Path for R Tutorials
(1) 5 Stages
graph TB
A[Phase 1 Basics 10 lessons] --> B[Phase 2 Data 7 lessons]
B --> C[Phase 3 Visualization 5 lessons]
C --> D[Phase 4 Statistics 5 lessons]
D --> E[Phase 5 Practical Application 3 lessons]
E --> F[End Able to work independently on projects]
style A fill:#cce5ff
style B fill:#d4edda
style C fill:#f8d7da
style D fill:#e1d4ff
style E fill:#ffe1d4
style F fill:#fff3cd
(2) List of 30 Lessons
| Phase | Class | Topic |
|---|---|---|
| 1 Basics | 01-10 | Introduction to R / Basic Syntax / Data Types / Vectors / Operators / Control Flow / Functions / Matrices / Lists / Data Frames |
| 2 Data | 11-17 | CSV / Excel / JSON / Database / String / Regular Expressions / Refactoring |
| 3 Visualization | 18–22 | Basic Plotting / Introduction to ggplot2 / Advanced / Themes / Maps |
| 4 Statistics | 23–27 | Descriptive Statistics / Probability Distributions / Hypothesis Testing / Linear Regression / Logistic Regression |
| 5 Practical Exercises | 28–30 | EDA / Data Cleaning / Comprehensive Report |
6. Suggestions for Further Study
(1) Advanced R Packages
| Bag | Purpose |
|---|---|
| Shiny | Web Application (Interactive Dashboard) |
| plumber | REST API (Machine Learning Deployment) |
| tidymodels | Modern Machine Learning (caret alternative) |
| torch | Deep Learning |
| arrow | Big Data (Parquet files) |
(2) Essential Resources
| Resource | Description |
|---|---|
| R for Data Science (2e) | Hadley's official book, hadley/r4ds |
| Advanced R (2nd ed.) | Advanced R Programming |
| ggplot2: Elegant Graphics | ggplot2 principles book |
| R Markdown Cookbook | Report Generation |
| RStudio Cheatsheets | Quick Reference Cards |
(3) Real-World Projects
- Kaggle (kaggle.com) — Real-world data science competitions
- TidyTuesday (tidytues.day) — Free weekly datasets
- My own data (work / hobbies / investments)
❓ FAQ
.Rmd file (YAML metadata + Markdown text + R code blocks). rmarkdown::render() Generate HTML/PDF. Use the RStudio "Knit" button to generate a report with a single click.📖 Summary
- 6 Stages of an End-to-End Project: Data → Cleaning → EDA → Description → Modeling → Reporting
- R Markdown = A reporting tool that combines documentation, code, results, and charts
saveRDSpersists a single object,write_csvpersists a table, andggsavepersists a chart- RStudio Project + renv + Git = The Data Science Trio
- The 30 lessons cover 80% of the work involved in R data analysis; the remaining 20% requires machine learning/deep learning extensions.
- Next: tidymodels (machine learning) / Shiny (dashboards) / plumber (API) / tidytext (text)
- Key Concept: End-to-end workflow from data to insights = the fundamental skills of a data scientist
- Tutorial Complete—Now You Can Independently Complete R Data Analysis Projects
📝 Exercises
Graduation Project Assignment (Complete End-to-End Data Analysis Project, Final Project for R Tutorial Lesson 30):
- Data Selection: Select 1 public dataset (recommended: Titanic / Iris / mtcars / mpg / nycflights13)
- Complete Process:
- Step 1: Read the data (using
readrordatasets) - Phase 2: Cleaning (Missing/Anomalous/Duplicate/Type)
- Phase 3: EDA (summary + skimr + visualization)
- Phase 4: Descriptive Statistics (Aggregated by Group)
- Step 5: Modeling (lm or glm)
- Phase 6: Report (R Markdown HTML)
- Step 1: Read the data (using
- Deliverables:
analysis.RMain script (200+ lines)report.RmdR Markdown report- 5+ charts
-
- Summary of Business Insights (500 characters)
- Grading Criteria:
- The code runs (20 points)
- Complete process (20 points)
- Depth of Analysis (20 points)
- Aesthetically pleasing charts (20 points)
- Readability of the report (20 points) Completing the graduation project = Completing the R tutorial!
▶ Example: Summary of Lesson 30
# ============================================
# R Tutorial 30 Lesson Study Summary Script
# After running, it outputs the topic for each lesson
# ============================================
lessons <- c(
"01 UnderstandingR", "02 Basic Grammar", "03 Data Types", "04 Vector",
"05 Operators", "06 Control Flow", "07 Function", "08 Matrices and Arrays",
"09 List", "10 Data Frames and Factors",
"11 CSV", "12 Excel", "13 JSON and XML", "14 Database",
"15 String", "16 Regular", "17 Data Reimagined",
"18 Basic Drawing", "19 ggplot2 Getting Started", "20 ggplot2 Advanced",
"21 Theme Customization", "22 Map",
"23 Descriptive Statistics", "24 Probability Distribution", "25 Hypothesis Testing",
"26 Linear Regression", "27 Logistic Regression",
"28 EDA", "29 Data Cleaning", "30 Comprehensive Report"
)
cat("R Tutorial 30 Course List:\n")
for (i in seq_along(lessons)) {
cat(sprintf("%2d. %s\n", i, lessons[i]))
}
Expected Output:
R Tutorial 30 Course List:
1. 01 UnderstandingR
2. 02 Basic Grammar
...
30. 30 Comprehensive Report
7. Congratulations on completing Lesson 30 of the R Tutorial
You’ve now systematically completed the 30 lessons in R Data Science—from basic syntax to end-to-end projects—and are ready to tackle real-world data analysis tasks on your own. Next up is hands-on practice—finding real data, working on real projects, and building your portfolio. We wish you every success in becoming an outstanding data scientist!