R Programming for Descriptive Analytics
R Programming for Descriptive Analytics
Table of Contents
2. Basic R Operations
3. Data Structures in R
o 3.1 Vectors
o 3.2 Matrices
7. Descriptive Statistics
8. Correlation Analysis
9. Data Visualization
What is R?
R is a free, open-source programming language specifically designed for statistical computing and
data analysis. It provides a powerful environment for data manipulation, statistical modeling, and
graphical visualization. R has become the de facto standard in academia and industry for predictive
analytics due to its extensive library of statistical packages and active community support.
R vs R Studio
R is the core programming language and computational engine. When you install R, you get a basic
console interface where you can type commands and see results.
Organized workspace with separate panes for code, console, plots, and files
Better project management and debugging tools
2. Basic R Operations
In R, you can store values in variables using the assignment operator = (or <-).
# Creating variables
x=2
y=3
Explanation: Variables x and y now hold the values 2 and 3 respectively. Once assigned, you can
use these variable names in calculations instead of typing the numbers repeatedly. The # symbol
creates a comment - anything after # is ignored by R and serves as documentation for humans
reading the code.
# Basic arithmetic
x + y # Addition: 5
x - y # Subtraction: -1
x * y # Multiplication: 6
x / y # Division: 0.6666667
Explanation: R performs standard mathematical operations using familiar symbols. The results
appear immediately in the console when you execute each line. This interactive nature makes R
excellent for exploratory data analysis.
Explanation: R comes with numerous built-in mathematical functions. log() calculates the natural
logarithm, while exp() calculates e raised to the power of x. These functions are essential for
statistical transformations and modeling.
3. Data Structures in R
3.1 Vectors
Vectors are one-dimensional arrays that hold elements of the same data type. They are the
fundamental building blocks in R.
Creating Vectors
x = c(4, 6, 5, 9, 8)
Explanation (100 words): The c() function combines individual values into a vector. The 'c' stands
for "concatenate" or "combine." In this example, we create a vector x containing five numbers.
Vectors are homogeneous, meaning all elements must be of the same type (all numbers, all text,
etc.). This is different from data frames which can contain mixed types. Vectors are foundational in
R because most operations are vectorized - when you apply a function to a vector, it automatically
applies to all elements. This makes R extremely efficient for statistical computations on large
datasets.
# Consecutive integers
Explanation: The colon operator : creates a sequence of consecutive integers. This is extremely
useful when you need to generate regular sequences. The expression 101:200 creates a vector with
100 elements: [101, 102, 103, ..., 199, 200].
Important Note: R uses 1-based indexing, meaning the first element is at position 1 (not 0 like in
Python or Java). Square brackets [] are used to access elements by their position.
Logical Operations on Vectors
# Logical comparisons
Explanation (120 words): Logical operations in R are vectorized, meaning they apply element-by-
element. When you write x > 4, R compares each element of vector x to 4 and returns a vector of
TRUE/FALSE values. This boolean vector can then be used to filter the original data. The expression
x[x > 4] is a powerful two-step process: first, x > 4 creates a logical vector indicating which
elements satisfy the condition; second, this logical vector is used as an index to extract only those
elements where the condition is TRUE. This filtering mechanism is fundamental to data
manipulation in R and allows you to subset data based on complex conditions without writing
explicit loops.
Vector Length
length(x) # Returns: 5
3.2 Matrices
Matrices are two-dimensional data structures that contain elements of the same type (typically
numbers).
Creating Matrices
a = matrix(c(2, 3, 4, 6), 2, 2)
# Result:
# [,1] [,2]
# [1,] 2 4
# [2,] 3 6
Explanation (150 words): The matrix() function converts a vector into a two-dimensional matrix. It
takes three arguments:
By default, R fills matrices column-wise (top to bottom, left to right). So the first two values (2, 3)
fill the first column, and the next two values (4, 6) fill the second column. This default behavior is
important to understand because it affects how your data is organized. If you have data that's
naturally organized by rows (like reading left to right), you'll need to use the byrow parameter to
override this default behavior. Matrices are particularly useful for mathematical operations,
statistical calculations, and representing structured data like images or tables.
# Result:
# [,1] [,2]
# [1,] 2 3
# [2,] 4 6
Explanation: The byrow = TRUE parameter changes the filling order to row-wise (left to right, top
to bottom). Now values fill the first row completely before moving to the second row. This is more
intuitive for data that's naturally organized in rows.
Explanation (100 words): Matrix indexing uses the format [row, column]. You can access a single
element by specifying both row and column numbers. To select an entire row, leave the column
position empty: a[2, ]. To select an entire column, leave the row position empty: a[, 2]. This flexible
indexing system allows you to extract exactly the data you need. You can also use vectors of
indices to select multiple rows or columns simultaneously. Empty spaces in the brackets mean "all"
- so [2, ] means "row 2, all columns."
a[-3, ]
Explanation: The negative sign - before an index means "exclude" rather than "include." So -3
means "all except the third one." The c(3, 4) groups multiple indices together for simultaneous
deletion. This non-destructive approach creates a new matrix without the specified rows/columns,
leaving the original unchanged.
Key Properties:
Explanation (150 words): The [Link]() function imports comma-separated value files into R as
data frames. The [Link]() function opens an interactive dialog box allowing you to browse and
select the file from your computer's file system - this is especially helpful when you don't want to
type the full file path or when demonstrating in class.
The stringsAsFactors = TRUE parameter is important: it automatically converts text columns into
factors (categorical variables). In R, factors are a special data type for categorical variables that
have a limited number of unique values (like "Monday", "Tuesday", etc. for days of the week).
Factors are more memory-efficient than plain text and are required by many statistical modeling
functions. While newer R versions default to FALSE, explicitly setting it to TRUE ensures that
qualitative variables like "day of the week" or "event" are properly treated as categories rather
than arbitrary text strings.
Once data is loaded, several functions help you understand its structure and content.
head(d)
tail(d)
Explanation (80 words): head() displays the beginning of your dataset, giving you a quick glimpse
of what the data looks like without overwhelming the console with thousands of rows. The default
is 6 rows, but you can specify any number as the second argument. tail() shows the end of the
dataset, which is useful for checking if data import completed successfully. These functions are
essential first steps in any data analysis workflow, helping you verify that data loaded correctly and
understand its basic structure.
str(d)
Explanation (100 words): The str() function (short for "structure") provides a comprehensive
summary of your data frame. It shows:
This is one of the most useful diagnostic functions because it immediately reveals data type issues.
For example, if a numeric variable appears as "character" type, it indicates problems in the data
file (perhaps some cells contain text where they should contain numbers). Understanding data
types is crucial because many statistical functions require specific types.
Dataset Dimensions
Explanation: dim() returns a vector with two numbers: the number of rows (observations) and the
number of columns (variables). This is useful for quickly checking dataset size.
Variable Names
names(d)
Explanation: names() returns a vector containing all column names in your data frame. This helps
you know exactly what variable names to use when accessing specific columns, especially useful
when variable names are long or abbreviated.
Explanation (100 words): The dollar sign $ operator accesses individual columns (variables) from a
data frame. The syntax is dataframe$columnname. This extracts that column as a vector, allowing
you to perform operations on it. For example, d$sales gives you a vector of all sales values, which
you can then use in calculations, create plots, or analyze statistically. The dollar sign notation is
more readable than bracket notation for column access and is widely used in R code. You can use
this extracted column with any function that accepts vectors, such as mean(d$sales) or
max(d$sales).
Missing values are a common data quality issue. In R, missing values are represented by NA (Not
Available).
Importance: Most statistical functions in R will fail or produce incorrect results if missing values are
present. Therefore, identifying and handling NAs is a critical first step in data preparation.
[Link](x)
Explanation: The [Link]() function checks each element and returns a logical vector indicating which
values are missing. This is the fundamental function for NA detection.
sum([Link](d$sales))
Explanation (100 words): This elegant R idiom combines two functions: [Link]() returns TRUE/FALSE
for each element, and sum() treats TRUE as 1 and FALSE as 0, effectively counting the TRUEs. So
sum([Link](d$sales)) tells you exactly how many missing values exist in the sales column. This works
because R automatically converts logical values to numeric in mathematical contexts: TRUE
becomes 1, FALSE becomes 0. This pattern of combining logical operations with sum() is used
extensively in R for counting how many observations meet specific conditions, making it a
fundamental technique for data quality assessment.
colSums([Link](d))
Explanation (120 words): colSums() calculates the sum of each column separately. When combined
with [Link](d), it creates a matrix of TRUE/FALSE values (one for each cell in the data frame) and
then sums each column. The result is a named vector showing how many missing values exist in
each variable. This provides a comprehensive overview of data quality across all variables at once.
For example, if the output shows sales: 3, date: 0, event: 1, you know that the sales column has 3
missing values, date has none, and event has 1. This single command is invaluable during initial
data exploration because it immediately identifies which variables have data quality issues that
need attention before analysis.
which([Link](d$sales))
Explanation (90 words): The which() function returns the indices (positions) where a logical
condition is TRUE. So which([Link](d$sales)) gives you the exact row numbers where sales values
are missing. This is crucial for understanding patterns in missing data. For example, if all missing
values are in the last 10 rows, it might indicate incomplete data entry. If they're scattered
randomly, it might suggest sporadic measurement errors. Knowing the specific locations allows
you to inspect those rows in detail to understand why data is missing.
Explanation: The [Link] = TRUE parameter makes which() return a matrix with two columns: one
for row numbers and one for column numbers. This tells you exactly which cell is missing (row X,
column Y).
d = [Link](d)
Explanation (150 words): The [Link]() function removes entire rows that contain NA values in any
column. This is a simple but aggressive approach to handling missing data. The benefit is that you
get a complete dataset with no missing values, which most statistical functions can process
without issues. However, there are important considerations:
Caution: If a row has one missing value out of 20 variables, [Link]() deletes the entire row,
discarding 19 good values. This can substantially reduce your sample size if missingness is
common. Before using [Link](), check the percentage of missing data - if more than 5-10% of
rows contain NAs, deletion might not be appropriate. Alternative approaches include:
Analyzing why data is missing (Missing Completely At Random vs. systematic patterns)
For this course, [Link]() is used for simplicity, but real-world analysis requires more sophisticated
approaches.
Outliers are data points that are significantly different from other observations. They can result
from measurement errors, data entry mistakes, or genuine extreme values.
Outliers can:
Key Question: Is this outlier an error (should be corrected/removed) or a legitimate extreme value
(should be kept)?
boxplot(d$sales)
Explanation (180 words): A box plot (also called box-and-whisker plot) is a standardized way of
displaying the distribution of data based on five key statistics:
3. Median (Q2): The middle value; 50% of data falls below this
The "box" spans from Q1 to Q3, representing the middle 50% of data (called the Interquartile
Range or IQR). The line inside the box marks the median. The "whiskers" extend to the minimum
and maximum values that fall within 1.5 × IQR from the box edges.
Outliers are plotted as individual points beyond the whiskers. The 1.5 × IQR rule is a standard
statistical convention: values more than 1.5 times the IQR below Q1 or above Q3 are considered
potential outliers. Box plots allow you to instantly visualize data spread, skewness, and identify
unusual values that deserve investigation. They're particularly useful when comparing
distributions across multiple groups.
boxplot(d$sales)$stats
Explanation: The $stats component extracts the five numbers that define the box plot. These
values are fundamental descriptive statistics that summarize the distribution's center and spread.
boxplot(d$sales)$out
Explanation: The $out component returns the actual values that R has identified as outliers using
the 1.5 × IQR rule. These are the points plotted beyond the whiskers.
Explanation (90 words): Once you've identified the outlier threshold (146 in this case), which() tells
you the row numbers where this condition occurs. This allows you to examine the complete
records for those outlier observations. You might discover that all outliers occur on event days, or
all on Saturdays, revealing patterns that explain the extreme values. Understanding the context of
outliers is essential for deciding whether they represent errors that should be corrected or
legitimate extreme values that should be retained in the analysis.
Explanation (80 words): This command displays entire rows where sales exceeds 146. The comma
after the row index means "all columns." By viewing complete records, you can investigate
whether outliers make sense in context. For example, if sales of 217 occurred with an ordering
quantity of only 110, this is an inconsistency (you can't sell more than you ordered). Such logical
inconsistencies indicate data errors that must be corrected before analysis. Context helps
distinguish between errors and genuine extremes.
Explanation (150 words): When you've identified a data error (not just an outlier), you can replace
the incorrect value with the correct one. In the case study, rows 19 and 31 had sales values (217
and 234) that exceeded their ordering quantities (110 and 130). This is logically impossible - you
cannot sell more items than you have available. The professor determined that these were data
entry errors where the digits were likely swapped or mistyped.
The Correction Decision: The values were replaced with the ordering quantities (110 and 130)
based on domain knowledge that sales typically equal ordering quantity on high-demand days.
This type of manual correction requires:
Not all outliers should be corrected - only those identified as errors through logical inconsistency
or domain knowledge.
1. Upper Outliers: Check if sales > ordering quantity (logically impossible) - these are errors
requiring correction
2. Lower Outliers: Check if low sales occur on expected days (Saturdays, holidays) - these are
legitimate, no action needed
3. Context Matters: Always investigate the business reason before treating outliers
Key Principle: Don't automatically delete all outliers. Understand why they exist first.
7. Descriptive Statistics
attach(d)
Explanation (120 words): The attach() function makes all columns of a data frame directly
accessible without needing the d$ prefix. After attaching, you can type sales instead of d$sales,
event instead of d$event, etc. This reduces typing and makes code cleaner, especially in interactive
sessions.
Caution from Professor: While convenient, attach() is described as "a bad thing to do" in
production code because:
It can create naming conflicts if variable names clash with existing objects
It makes code less explicit about data sources
Recommendation: Use attach() for convenience during exploratory analysis and classroom
demonstrations, but use explicit d$ notation in final scripts and reports for clarity and
reproducibility.
summary(sales)
Output Example:
Explanation (150 words): The summary() function provides six key statistics:
3. Median (100): The middle value; half the days have sales below 100, half above
5. 3rd Quartile (114): 75% of days have sales below 114 units
Interpreting Quartiles: The quartiles divide your data into four equal parts. The distance between
quartiles indicates data spread - larger gaps suggest more variability in that range. In this example,
the gap between Q1 and median (100-92=8) is smaller than the gap between median and Q3 (114-
100=14), suggesting the data is slightly right-skewed with more spread in the upper range.
Mean vs. Median: When mean < median, the distribution is left-skewed; when mean > median, it's
right-skewed. Here they're very close, suggesting fairly symmetric distribution.
Standard Deviation Explanation (120 words): Standard deviation (SD) measures the average
distance of data points from the mean. A small SD means values cluster tightly around the mean; a
large SD means values are spread out widely. In the context of the kiosk case study, SD is "very
very important" because:
By identifying patterns (event days, holidays, day of week), we can reduce unexplained
variation
Lower SD in prediction errors means better ordering decisions and higher profit
SD essentially quantifies the business problem: how much does sales vary, and can we predict it
better?
8. Correlation Analysis
Correlation measures the strength and direction of the linear relationship between two
quantitative variables.
cor(d$OQ, d$sales)
# Result: 0.925
Explanation (150 words): The cor() function calculates the Pearson correlation coefficient, which
ranges from -1 to +1:
+1: Perfect positive correlation (as one increases, the other increases proportionally)
0: No linear relationship
-1: Perfect negative correlation (as one increases, the other decreases)
A correlation of 0.925 indicates a very strong positive relationship between ordering quantity and
sales. This suggests that, overall, the kiosk is doing a good job of matching ordering to sales
demand. Values above 0.7 are typically considered strong correlations.
Important Note: Correlation does not imply causation. High correlation means the variables move
together, but doesn't tell you why. In this case, the causation actually works both ways: ordering
quantity influences sales (you can't sell what you don't have), and sales patterns influence ordering
decisions (they order more on high-demand days).
When to Use Correlation: Only for two quantitative (numeric) variables. For relationships between
categorical and numeric variables, use other methods like tapply() or ANOVA.
attach(d)
# Result: 0.55
Explanation (180 words): This advanced syntax filters the data before calculating correlation. The
expression OQ[event == "yes"] extracts only the ordering quantities where the event variable
equals "yes", and similarly for sales. By calculating correlation on this subset, we see if the
relationship holds for specific groups.
Key Finding from Case Study: While overall correlation is strong (0.925), the correlation on event
days drops to 0.55, which is substantially weaker. This reveals an important insight:
Business Interpretation: The kiosk is doing a good job matching ordering to sales on regular days,
but performs poorly on event days. Events are unpredictable, and the current ordering strategy
doesn't adequately account for the higher and more variable demand on these days. This specific
insight drives the recommendation to revise ordering quantities specifically for event days, rather
than making global changes.
Analysis Pattern: This technique of calculating statistics for overall data and then for specific
subgroups is fundamental in analytics. Global statistics can hide problems in specific segments.
Always look for variation across meaningful categories (customer types, time periods, geographic
regions, etc.).
9. Data Visualization
plot(OQ, sales)
Explanation (100 words): The plot() function creates a scatter plot when given two numeric
vectors. Each point represents one observation, with its x-coordinate from the first variable (OQ)
and y-coordinate from the second (sales). Scatter plots are essential for visualizing relationships
between two quantitative variables. They help you see:
Scatter plots complement correlation by providing visual confirmation and revealing patterns that
single numbers cannot capture.
Color
# Red points
Explanation: The col parameter changes point color. R recognizes many color names ("red", "blue",
"green", "purple", etc.) as well as hex codes for precise color control.
Explanation (80 words): The lwd parameter (line width) makes points more prominent by
increasing their size. While it's called "line" width, it also affects point symbols. Higher values
make points bolder. The professor used lwd = 2 to make the visualization "more catchy" and easier
to see during presentation. Visual clarity is important for effective communication of results.
Compare lwd = 1 (default) with lwd = 2 to see how subtle changes improve readability, especially
when presenting to audiences.
Axis Labels
ylab = "Sales")
Explanation (90 words): The xlab and ylab parameters customize axis labels. Default labels use
variable names from your code (like "OQ"), which might not be clear to audiences. Professional
visualizations should have descriptive labels that anyone can understand without seeing the code.
"Ordering Quantity" is more informative than "OQ". Good axis labels include units when relevant
(e.g., "Sales (units)" or "Revenue ($)"). Clear labeling is essential for presentations and reports
where viewers need to understand graphs independently. Taking time to add proper labels
distinguishes professional analysis from quick exploratory work.
plot(OQ, sales,
col = "red",
lwd = 2,
The tapply() function performs calculations on a numeric variable separately for each level of a
categorical variable. Think of it as creating a pivot table in Excel.
Output Example:
no yes
91.0 127.0
This command calculates the average sales separately for event days (yes) and non-event days
(no). The result is a named vector showing mean sales for each category.
Business Insight: Average sales jump from 91 units on regular days to 127 units on event days - a
40% increase. This substantial difference confirms that events drive significantly higher demand,
and ordering quantities should account for this pattern.
tapply() Versatility: You can use any function in the third argument: mean, median, sd, min, max,
length (to count observations), etc. This makes tapply() extremely powerful for exploratory
analysis across different segments.
Explanation (120 words): When you provide list(variable1, variable2) as the second argument,
tapply() creates a cross-tabulation (like a two-way pivot table). This calculates statistics for every
combination of the two factors. For example, you'd see mean sales for:
Monday non-events
Monday events
Tuesday non-events
Tuesday events
This multi-dimensional analysis reveals whether certain day-event combinations have particularly
high or low sales. Perhaps Saturday events are different from Tuesday events. This granular
understanding is crucial for developing sophisticated ordering strategies that account for multiple
factors simultaneously. The case study emphasizes examining regular days, event days, and
holidays separately because each type behaves differently.
Case Study Finding: Like events, holidays show different sales patterns. The professor found that
correlation between ordering and sales is weaker on holidays, similar to event days. This suggests
the ordering strategy doesn't adequately account for holiday demand patterns.
Context: A food kiosk operates daily and faces a critical inventory problem. Food is perishable and
must be ordered in advance of each day's sales.
The Challenge:
Order too much: Excess food spoils → waste → loss of food cost
Order too little: Run out of stock → lost sales → missed profit opportunities
High variation: Sales fluctuate significantly from day to day, making ordering decisions
difficult
Business Impact: High sales variability increases cost (frequent excess) and reduces revenue
(frequent stockouts). Better prediction of sales would enable optimal ordering and improve
profitability.
Management's Claim: They assert they're already doing a good job with ordering and don't need
changes.
Objective: Use descriptive analytics to determine if the current ordering strategy is optimal, and if
not, how it should be revised.
Variables:
Key Constraint: Sales cannot exceed ordering quantity (you can't sell what you didn't order).
Missing Values
Treatment: Rows with missing values were removed using [Link]() to ensure clean
analysis
Upper Outliers:
Diagnosis: Data entry errors where sales were recorded higher than available inventory
Treatment: Replaced with ordering quantities (110 and 130 respectively), assuming full
sellout on high-demand days
Lower Outliers:
Overall Correlation
Interpretation: Strong correlation suggests generally good alignment between ordering and sales.
Summary Statistics
summary(sales)
Interpretation: Wide range (18 to 160) confirms high variability. Standard deviation is substantial
relative to the mean, indicating significant uncertainty in daily demand.
Segmented Analysis
By Event:
# no yes
# 91.0 127.0
By Day of Week:
By Holiday:
2. Event Days: Higher demand, but poor ordering alignment (weak correlation) → needs
revision
The Problem: While overall correlation appears strong (0.925), this hides poor performance on
event days and holidays. The strong overall correlation is driven by the many regular days, masking
problems in important subgroups.
2. Revise ordering for event days: Increase quantities, but also improve prediction
Calculate separate average sales for each day type (regular, event, holiday)
Build predictive models to forecast sales based on day type, day of week, events, and
holidays
Submit as homework/assignment
This progression from description → prediction → prescription is the core of the predictive
analytics course.
2. Data Structures: Vectors, matrices, data frames, and when to use each
Analytical Concepts
1. Data Quality First: Always check for NAs, outliers, and inconsistencies before analysis
2. Context Matters: Not all outliers are errors; understand the business before correcting
3. Segmented Analysis: Overall statistics can hide problems in subgroups - always drill down
5. From Description to Action: Descriptive analytics should lead to business insights and
recommendations
R Best Practices
1. Explore Before Analyzing: Always use str(), summary(), and head() on new data
2. Document Your Work: Use comments (#) to explain what code does
3. Check Your Results: View data after transformations to confirm they worked correctly
4. Use Meaningful Names: Clear variable and file names improve code readability
5. Visualization Matters: Plots often reveal patterns that numbers alone miss
dim(d) # Dimensions
Missing Values
Outliers
Descriptive Statistics
mean(sales) # Average
Relationships
cor(x, y) # Correlation
Grouped Analysis
tapply(sales, event, mean) # Mean by group
Data Manipulation
1. Build a model predicting sales from day type, events, holidays, etc.
4. Submit as assignment
1. Practice the code: Spend 30-45 minutes running all the commands from this session on
your own computer
2. Understand, don't memorize: Focus on what each function does and why, not just syntax
3. Think about the case: How would you revise ordering quantities based on descriptive
analysis?
Professor's Advice
On Coding:
"Coding is the easiest part" - Don't worry too much about syntax
On Learning:
Without hands-on practice, "this is going to look more and more difficult"
On Assignments:
Additional Notes
R vs Python
While not discussed extensively in class, students sometimes ask about the difference:
For this course, R is chosen because it's the standard in academic statistics
1. Forgetting parentheses: Functions need () even with no arguments (e.g., summary() not
summary)
4. Not checking data after import: Always use str() and head() after reading files
5. Ignoring data quality: Missing values and outliers will break your analysis if not handled
Conclusion
This session provided a solid foundation in R programming and descriptive analytics. The core
message is that before any sophisticated modeling, you must:
These fundamentals apply to every data analysis project, regardless of complexity. Master these
basics, and advanced techniques become much more accessible.
The kiosk case study demonstrates that even simple descriptive analysis can generate valuable
business insights. We discovered that ordering strategies need to differ for regular days, event
days, and holidays - a finding that can directly improve profitability.
In the next session, we'll build on this foundation by learning regression analysis, which will allow
us to make quantitative predictions and optimize business decisions.
End of Session 2 Lecture Notes
Total Word Count: ~12,000 words Generated from: September 14, 2025 class recording Case Study:
Kiosk Food Sales Optimization