R
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Data Structures
-
Section 4: Data Manipulation
-
Section 5: Visualization and Statistics
-
Section 6: Advanced R
-
Section 7: Practical Projects
-
Section 8: Interview Practice
-
Section 9: More Practice Exercises
-
Section 10: Shiny Apps in Depth
-
Section 11: More Data Wrangling
-
Section 12: Tidyverse Deep Dive
-
Section 13: Statistical Modeling Deep Dive
-
Section 14: Machine Learning in R
-
Section 15: R Visualization Deep Dive
-
Section 16: R Package Development Deep Dive
-
Section 17: R for Reproducible Research
-
Section 18: R and Databases
-
Section 19: R Performance Optimization
-
Section 20: Bioinformatics and Specialized R
-
Section 21: More Shiny Practice
-
Section 22: More Practice Exercises
-
Section 23: R Data Structures Deep Dive
-
Section 24: More Interview and Review
-
Section 25: R for Business Analytics
-
Section 26: R Text Mining and NLP
-
Section 27: R Spatial Data Analysis
-
Section 28: R Deep Learning
-
Section 29: Advanced Statistical Techniques
-
Section 30: R Object Systems Deep Dive
-
Section 31: R Environments and Metaprogramming
-
Section 32: R for Finance
-
Section 33: R for Clinical and Health Data
-
Section 34: More Shiny Advanced Practice
-
Section 35: R Data Cleaning Deep Dive
-
Section 36: R Reporting Automation
-
Section 37: More Practical Projects Round 2
-
Section 38: R Ecosystem and Career
-
Section 39: More Visualization Practice
-
Section 40: R for Experimentation
-
Section 41: R for Genomics and Bioinformatics Deep Dive
-
Section 42: R for Marketing Analytics
-
Section 43: R Data Import/Export Deep Dive
-
Section 44: R String Processing Deep Dive
-
Section 45: R for Actuarial and Insurance Analytics
-
Section 46: R Testing and Quality Assurance Deep Dive
-
Section 47: R Version Control and Collaboration
-
Section 48: R Advanced Functional Programming
-
Section 49: R for Supply Chain and Operations
-
Section 50: More Practice Exercises Round 3
-
Section 51: R Dashboards and BI Integration
-
Section 52: R Data Governance and Ethics
-
Section 53: More Modeling Practice
-
Section 54: R Final Capstone Projects
-
Section 55: R for Sports Analytics
-
Section 56: More Interview Practice Round 2
-
Section 57: R Networking and APIs
-
Section 58: R for Environmental Science
-
Section 59: R Notebook and Documentation Practices
-
Section 60: More Data Wrangling Mastery
-
Section 61: R for A/B Testing at Scale
-
Section 62: R Package Ecosystem Deep Dive
54: Generalized Linear Models in R
Imagine you're trying to predict how many bugs will be found in a new software release. You might start with a standard linear regression, but you'll quickly run into a problem: linear regression assumes your output can be any number, including negative ones. But you can't have -3 bugs in a release. That just doesn't happen in the real world.
Linear regression is like a rigid ruler. It's great for measuring things that grow in a straight line, but it fails when the data "bends" or is restricted to specific types of values (like whole numbers or yes/no answers). A Generalized Linear Model (GLM) is more like a flexible measuring tape. It allows us to keep the "linear" part of the math—the relationship between your inputs and your output—but it adds a "translator" (which we call a link function) to make sure the final prediction actually makes sense for the data you're dealing with.
Here is how that maps to the actual concepts in R:
- The Linear Predictor: This is the "rigid ruler" part. It's the weighted sum of your variables (
beta0 + beta1*x). - The Link Function: This is the "translator." It takes that linear result and maps it to the scale of your data. For counts, we often use a "log link" so the result is always positive.
- The Error Distribution: This is the "shape" of your data. Instead of assuming a Bell Curve (Normal distribution), we might assume a Poisson distribution for counts or a Binomial distribution for binary outcomes.
When to stop using lm() and start using glm()
You've used lm() in previous lessons for standard linear regression. But the moment your dependent variable isn't a continuous, normally distributed number, lm() is the wrong tool. I've seen a lot of engineers try to force lm() to predict binary outcomes (0 or 1), and while it technically runs, the predictions often end up being 1.2 or -0.4, which is useless for a "yes/no" question.
If you're predicting a count (e.g., "How many tickets will this user open?"), use family = poisson. If you're predicting a probability (e.g., "Will this build fail?"), use family = binomial.
Fitting a Poisson Model for Bug Counts
Let's look at a concrete example. Suppose we have a dataset where bugs is the number of defects found and kloc is the thousands of lines of code changed. Since bug counts are discrete and non-negative, a Poisson GLM is the way to go.
# Let's create a quick dummy dataset
dev_data <- data.frame(
kloc = c(10, 20, 30, 40, 50, 60, 70, 80),
bugs = c(2, 5, 8, 12, 15, 22, 28, 35)
)
# We use glm() instead of lm()
# Note the 'family' argument—this is the most important part!
bug_model <- glm(bugs ~ kloc, data = dev_data, family = poisson(link = "log"))
summary(bug_model)
I want to point out that link = "log" is actually the default for the Poisson family, so you can just write family = poisson. But being explicit about it helps you remember that R is taking the log of your expected count to make the linear math work behind the scenes.
Dealing with the Output
When you run summary(bug_model), you'll notice it looks a lot like lm(), but the coefficients are on the scale of the link function, not the original data. Since we used a log link, the coefficients are logarithmic.
To get a prediction that actually looks like a number of bugs, you can't just use predict(bug_model). By default, that gives you the result in "log-space." To get it back to the original scale, you specify type = "response":
# Predict bugs for a change of 45 kloc
new_code <- data.frame(kloc = 45)
predict(bug_model, newdata = new_code, type = "response")
If you forget type = "response", you'll get a number like 2.4, which represents the log of the bugs. You'd then have to manually exponentiate it (exp(2.4)) to get the actual count. Just save yourself the headache and use the argument.
📋 Practical Task
Predicting Server Downtime Incidents
You have been handed a dataset containing server metrics from the last year. Your goal is to predict the number of downtime incidents per month based on the average CPU load and the age of the hardware (in years). Since downtime incidents are counts, you must use a Generalized Linear Model.
Dataset:
server_stats <- data.frame(
incidents = c(0, 1, 0, 2, 1, 4, 3, 5, 2, 6),
cpu_load = c(20, 35, 25, 50, 40, 70, 65, 85, 55, 90),
age = c(1, 2, 1, 3, 2, 5, 4, 6, 3, 7)
)
Your Task:
- Fit a GLM to predict
incidentsusingcpu_loadandageas predictors. Ensure you use the correctfamilyfor count data. - Extract the summary of the model to see which variable (CPU load or age) has a more significant impact on downtime.
- Predict the expected number of incidents for a server with a
cpu_loadof 75 and anageof 4 years. Make sure your result is in the original scale (the actual number of incidents), not the log scale.
There are no comments for now.