See your data: Understanding patterns and relationships
Exploratory Data Analysis (EDA) is your first step after cleaning. GOAL: Understand data before analysis
EXPLORATORY VS CONFIRMATORY:
WORKFLOW:
WHY VISUALIZATION? "The simple graph has brought more information to the data analyst's mind than any other device" - John Tukey Visualizations:
GGPLOT2: Industry-standard visualization package
THIS WEEK YOU'LL LEARN: ✓ Univariate analysis (distribution, summary stats) ✓ Bivariate analysis (relationships) ✓ Multivariate analysis (complex patterns) ✓ ggplot2 syntax and layers ✓ Common plot types ✓ Customization and themes ✓ Communicating with visualizations
UNIVARIATE ANALYSIS - ONE VARIABLE AT A TIME:
NUMERIC VARIABLES:
library(dplyr) df <- tibble( age = c(25, 28, 30, 125, 32, 29, 26, 31, 27, 28), salary = c(50000, 55000, 60000, 200000, 58000, 52000, 51000, 62000, 54000, 57000) ) # Central tendency mean(df$age) # [1] 29.6 median(df$age) # [1] 28.5 mode(df$age) # Most frequent (if exists) # Spread sd(df$age) # Standard deviation var(df$age) # Variance IQR(df$age) # Interquartile range (Q3-Q1) # Range min(df$age) # [1] 25 max(df$age) # [1] 125 range(df$age) # [1] 25 125 # Quantiles quantile(df$age) # 0%, 25%, 50%, 75%, 100% quantile(df$age, c(0.1, 0.9)) # Custom quantiles # Complete summary summary(df$age) # Min. 1st Qu. Median Mean 3rd Qu. Max. # 25.0 27.8 28.5 29.6 30.8 125.0 # Skewness and Kurtosis library(moments) skewness(df$age) # [-2, 2] normal, <-2 left-skewed, >2 right-skewed kurtosis(df$age) # >0 more peaked, <0 flatter than normal # Professional summary df |> summarize( n = n(), mean = mean(age), median = median(age), sd = sd(age), min = min(age), max = max(age), missing = sum(is.na(age)) )
CATEGORICAL VARIABLES:
df <- tibble( department = c("Sales", "IT", "Sales", "HR", "IT", "Sales", "HR", "Sales", "IT", "Sales"), level = c("Junior", "Senior", "Mid", "Mid", "Junior", "Mid", "Senior", "Junior", "Senior", "Mid") ) # Frequency tables table(df$department) # HR IT Sales # 2 3 5 # Proportions table(df$department) / nrow(df) # HR IT Sales # 0.20 0.30 0.50 # Cross-tabulation (two variables) table(df$department, df$level) # Junior Mid Senior # HR 0 1 1 # IT 1 0 2 # Sales 2 2 1 # With dplyr df |> group_by(department) |> summarize(count = n(), percent = n() / nrow(df))
BIVARIATE ANALYSIS - TWO VARIABLES:
NUMERIC vs NUMERIC:
# Correlation cor(df$age, df$salary) # [1] 0.95 (strong positive) cor(df$age, df$salary, method="spearman") # Rank correlation # Correlation matrix cor(df[, c("age", "salary")]) # Covariance cov(df$age, df$salary) # More robust correlation (if outliers) library(MASS) huber(df$age, df$salary)
NUMERIC vs CATEGORICAL:
df <- tibble( salary = c(50000, 55000, 60000, 200000, 58000, 52000, 51000, 62000, 54000, 57000), department = c("Sales", "IT", "Sales", "IT", "Sales", "HR", "Sales", "IT", "HR", "Sales") ) # Compare groups df |> group_by(department) |> summarize( n = n(), mean_salary = mean(salary), median_salary = median(salary), sd_salary = sd(salary), min_salary = min(salary), max_salary = max(salary) ) # Output: # department n mean_salary median_salary sd_salary min_salary max_salary # HR 2 56500 56500 7778. 51000 62000 # IT 3 105667 200000 82789 55000 200000 # Sales 5 55000 54000 4243. 50000 60000 # Statistical test (covered in Week 6) t.test(salary ~ department, df)
CATEGORICAL vs CATEGORICAL:
df <- tibble( product = c("A", "A", "B", "B", "C", "A", "B", "C", "A", "B"), purchase = c("Yes", "Yes", "No", "Yes", "Yes", "No", "Yes", "No", "Yes", "Yes") ) # Contingency table table(df$product, df$purchase) # No Yes # A 1 3 # B 1 3 # C 1 1 # Proportions by row prop.table(table(df$product, df$purchase), margin=1) # Shows: Of product A, 75% purchased (3/4)
GGPLOT2 - GRAMMAR OF GRAPHICS:
Philosophy: Build plot layer by layer
BASIC SYNTAX:
ggplot(data, aes(x = var1, y = var2)) + geom_type() + labs(title = "...", x = "...", y = "...") + theme_minimal()
LAYERS:
EXAMPLE:
library(ggplot2) df <- tibble( x = 1:10, y = c(2, 3, 5, 7, 11, 13, 17, 19, 23, 29) ) # Basic scatter plot ggplot(df, aes(x = x, y = y)) + geom_point() # Add title and labels ggplot(df, aes(x = x, y = y)) + geom_point() + labs(title = "My First ggplot", x = "X Variable", y = "Y Variable") # Change point size and color ggplot(df, aes(x = x, y = y)) + geom_point(size = 3, color = "blue") # Add line ggplot(df, aes(x = x, y = y)) + geom_point(size = 3) + geom_line(color = "blue") # Add smooth curve (trend line) ggplot(df, aes(x = x, y = y)) + geom_point() + geom_smooth(method = "lm", se = FALSE) # se=FALSE removes confidence band
COMMON PLOT TYPES:
HISTOGRAM (Distribution of numeric):
ggplot(df, aes(x = age)) + geom_histogram(bins = 20, fill = "steelblue") + labs(title = "Age Distribution", x = "Age", y = "Count")
BOX PLOT (Comparing groups):
ggplot(df, aes(x = department, y = salary)) + geom_boxplot(fill = "lightblue") + labs(title = "Salary by Department", x = "Department", y = "Salary")
SCATTER PLOT (Two numeric variables):
ggplot(df, aes(x = age, y = salary)) +
geom_point(size = 3, color = "blue") +
labs(title = "Age vs Salary")BAR PLOT (Categorical counts):
df |> count(department) |> ggplot(aes(x = department, y = n)) + geom_bar(stat = "identity", fill = "coral") + labs(title = "Count by Department", x = "Department", y = "Count")
COLOR AND AESTHETICS:
# Color by group ggplot(df, aes(x = age, y = salary, color = department)) + geom_point(size = 3) # Size by variable ggplot(df, aes(x = age, y = salary, size = years_employed)) + geom_point(color = "blue") # Facet (small multiples) - separate panels ggplot(df, aes(x = age, y = salary)) + geom_point() + facet_wrap(~department) # One panel per department
THEMES AND CUSTOMIZATION:
# Built-in themes theme_minimal() # Clean, minimal theme_classic() # Classic with axes theme_bw() # Black and white theme_dark() # Dark background # Apply theme ggplot(df, aes(x = age, y = salary)) + geom_point() + theme_minimal() + theme(text = element_text(size = 12)) # Full customization ggplot(df, aes(x = age, y = salary, color = department)) + geom_point(size = 3) + labs(title = "Professional Scatter Plot", x = "Age (years)", y = "Annual Salary ($)", color = "Department") + theme_minimal() + theme( plot.title = element_text(size = 14, face = "bold"), axis.text = element_text(size = 10), legend.position = "right" )