0% found this document useful (0 votes)
5 views27 pages

CS1B R Exam Notes

This document provides exam notes for R programming in the context of actuarial statistics, covering data import, descriptive statistics, plotting, probability distributions, and statistical inference. It includes code snippets for common tasks, best practices for data handling, and essential statistical methods. Key sections are marked for priority, and the notes emphasize exam readiness and reproducibility in simulations.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views27 pages

CS1B R Exam Notes

This document provides exam notes for R programming in the context of actuarial statistics, covering data import, descriptive statistics, plotting, probability distributions, and statistical inference. It includes code snippets for common tasks, best practices for data handling, and essential statistical methods. Key sections are marked for priority, and the notes emphasize exam readiness and reproducibility in simulations.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

CS1B — R Programming

Exam Notes Based on Past Paper Analysis


IAI Actuarial Statistics · Papers 2019–2024

📌 HOW TO USE: Read top-to-bottom. Every code block is exam-ready — copy the pattern, swap
the variable/dataset names. Focus on sections marked ★★★ first.
MODULE 1 — Data Import & Environment Setup
★★★ ALWAYS FIRST: Every paper gives a dataset. Load it correctly before anything else.

1.1 Loading Different File Types


CSV files (most common in CS1B)
# Method 1: Basic (uses working directory)
df <- [Link]("[Link]")

# Method 2: With full path (safer in exam)


df <- [Link]("C:/Users/admin/Desktop/CS1B/[Link]")

# Method 3: With options (use when CSV has issues)


df <- [Link]("[Link]", header=TRUE, stringsAsFactors=FALSE)

# Method 4: Tab-separated .txt files


df <- [Link]("[Link]", header=TRUE, sep="\t")

# Method 5: Space-separated .txt files


df <- [Link]("[Link]", header=TRUE)

.Rdata / .RData files


# Loads all objects saved in that session directly into environment
load("[Link]") # Objects appear by their saved names
ls() # See what was loaded

Vectors / matrices given inline in question


# When data is given directly in the question:
x <- c(23, 45, 12, 67, 34, 89, 56) # numeric vector
y <- c('A','B','A','C','B','A') # character vector
mat <- matrix(c(1,2,3,4,5,6), nrow=2, ncol=3)

1.2 Always Inspect Data First (Mandatory habit)


str(df) # Structure: column names, types, preview
head(df) # First 6 rows
head(df, 10) # First 10 rows
tail(df) # Last 6 rows
dim(df) # (rows, cols)
nrow(df) # number of rows
ncol(df) # number of columns
names(df) # column names
colnames(df) # same as names()
summary(df) # min/max/mean/quartiles for each column

1.3 Accessing Columns & Subsetting


# Python equiv: df['col'] or [Link]
df$ColumnName # Access one column (returns vector)
df[["ColumnName"]] # Same, double bracket
df[, 2] # Access by column index
df[1:5, ] # First 5 rows, all columns
df[df$Age > 30, ] # Filter rows (like df[[Link] > 30] in pandas)
df[df$Sex == 'M', 'Age'] # Filter rows AND select column

# Useful: which() gives indices


which(df$Score > 90) # Row numbers where condition is TRUE
df[which(df$Score > 90), ] # Same as above but explicit

# Table of a categorical column


table(df$Category) # Frequency table
[Link](table(df$Cat)) # Proportion table (sums to 1)

1.4 Creating & Modifying Data


# Add new column (like df['new_col'] = ... in pandas)
df$LogClaim <- log(df$ClaimAmount)
df$Category <- ifelse(df$Return > 0, "Positive", "Negative")

# Remove a column
df$unwanted <- NULL

# Rename: colnames is a vector you can assign to


colnames(df)[3] <- "NewName"
MODULE 2 — Descriptive Statistics & Data Summarisation ★★★

2.1 Basic Summary Statistics


x <- df$ClaimAmount # Work with a vector

mean(x) # Arithmetic mean


median(x) # Median
var(x) # Sample variance (divides by n-1)
sd(x) # Standard deviation = sqrt(var(x))
min(x); max(x) # Range endpoints
range(x) # c(min, max) vector
sum(x) # Sum
length(x) # Count of elements (= n)

# Quantiles
quantile(x) # 0%, 25%, 50%, 75%, 100%
quantile(x, 0.9) # 90th percentile
quantile(x, c(0.25, 0.75)) # Q1 and Q3
IQR(x) # Interquartile range = Q3 - Q1

# Round output (exam often asks to n decimal places)


round(mean(x), 3) # Round to 3 decimal places
round(mean(x), 0) # Round to integer

2.2 Correlation
# Pearson (default) — measures linear association
cor(x, y) # Pearson correlation
cor(x, y, method='pearson') # Explicit

# Spearman — rank-based, robust to outliers


cor(x, y, method='spearman')

# Kendall's tau
cor(x, y, method='kendall')

# Full correlation matrix for data frame


cor(df[ , c('col1','col2','col3')])
round(cor(df[ , 2:5]), 3) # Round all to 3 dp

# Test if correlation is significant


[Link](x, y) # H0: true correlation = 0
[Link](x, y, method='spearman')
# Read: t-stat, df, p-value, 95% CI, estimate
2.3 Contingency Tables (appears every exam)
# Build from two categorical columns
tbl <- table(df$Sector1, df$Sector2) # rows x cols
tbl # Print table

# Proportions
[Link](tbl) # Cell proportions (sum = 1)
[Link](tbl, 1) # Row proportions
[Link](tbl, 2) # Column proportions

# Chi-squared test on the table


[Link](tbl)
# Output: X-squared, df, p-value
MODULE 3 — Plotting & Visualisation ★★★
EXAM TIP: Plotting questions almost always ask you to add labels, titles, and sometimes lines.
Always use xlab, ylab, main.

3.1 Histogram
# Basic histogram
hist(x)

# Exam-standard histogram with all options


hist(x,
breaks = 20, # Number of bins (or try "FD" for auto)
freq = FALSE, # freq=FALSE → y-axis is DENSITY (needed to
overlay curve)
col = "lightblue", # Fill colour
border = "black", # Bar border colour
main = "Histogram of Claim Amounts",
xlab = "Claim Amount (£)",
ylab = "Density")

# Add theoretical density curve on top (after freq=FALSE)


curve(dnorm(x, mean=mean(data), sd=sd(data)), add=TRUE, col='red', lwd=2)

# Add empirical density (kernel density estimate)


lines(density(x), col='blue', lwd=2)

3.2 Q-Q Plot (Normality Check) ★★★


COMMON QUESTION: "Plot a Q-Q plot and comment on normality." — appears in nearly every
past paper.

# Q-Q plot with reference line


qqnorm(x, main='Normal Q-Q Plot of Returns')
qqline(x, col='red', lwd=2) # Adds the reference line

# HOW TO INTERPRET (write in answer):


# Points close to red line → data is approximately normal
# Heavy tails (points bow away at ends) → heavier than normal
# S-shape → skewed distribution
# Systematic curve → non-normal

3.3 Boxplot
# Simple boxplot
boxplot(x, main='Boxplot of Returns', ylab='Monthly Return (%)')
# Grouped boxplot (by category) — very common in exam
boxplot(Return ~ Sector, data=df,
main = "Returns by Sector",
xlab = "Sector",
ylab = "Return (%)",
col = c("lightblue","lightgreen","lightyellow"),
las = 1) # las=1: horizontal y-axis labels

# Interpreting boxplot (write in answer):


# Middle line = median
# Box = IQR (Q1 to Q3)
# Whiskers = 1.5 * IQR beyond box
# Points beyond whiskers = potential outliers

3.4 Scatter Plot


# Basic scatter plot
plot(x, y)

# Full options
plot(df$Age, df$ClaimAmount,
main = "Claim Amount vs Age",
xlab = "Age",
ylab = "Claim Amount",
pch = 16, # point type: 16=filled circle, 1=hollow, 4=cross
col = "navy",
cex = 0.8) # point size scaling

# Add regression line on scatter plot


abline(lm(y ~ x), col='red', lwd=2)

# Add any line: abline(intercept, slope)


abline(0, 1, col='green', lty=2) # y = x reference line
abline(h=0, col='gray') # Horizontal line at y=0
abline(v=mean(x), col='blue', lty=3)# Vertical line at mean

3.5 Bar Chart


counts <- table(df$Category)

# barplot takes a named vector or table


barplot(counts,
main = "Frequency by Category",
xlab = "Category",
ylab = "Frequency",
col = "steelblue",
las = 1,
horiz = FALSE) # horiz=TRUE for horizontal bars
3.6 Multiple Plots in One Window
# 2 plots side by side
par(mfrow = c(1, 2)) # 1 row, 2 columns
hist(x, main='Histogram')
qqnorm(x, main='Q-Q Plot'); qqline(x, col='red')

# 2x2 grid (4 plots)


par(mfrow = c(2, 2))
plot(model) # regression diagnostic: uses all 4 slots

# Reset to single plot


par(mfrow = c(1, 1))

3.7 Scree Plot (Principal Components)


NOTE: The Nov 2019 IAI paper specifically asked for a scree plot using PCA. Know this.

# Run PCA
pca_result <- prcomp(df_numeric, scale.=TRUE)

# Scree plot
plot(pca_result, # or:
type="l", # type="b" for both points and lines
main="Scree Plot")

# Manual scree plot using variance


variance <- pca_result$sdev^2
prop_var <- variance / sum(variance)
plot(prop_var, type="b",
xlab="Principal Component",
ylab="Proportion of Variance",
main="Scree Plot")

# Pairwise correlation among PCs (they should be 0)


pca_scores <- pca_result$x # n x p matrix of scores
round(cor(pca_scores), 3) # Should be identity matrix

3.8 Plotting Theoretical Distributions


# Plot Normal PDF
x_range <- seq(-4, 4, by=0.01)
plot(x_range, dnorm(x_range, mean=0, sd=1), type="l",
main="Standard Normal PDF", xlab="x", ylab="f(x)", col="blue")

# Add Poisson PMF as bar chart


k <- 0:15
plot(k, dpois(k, lambda=3), type="h", # type="h" = vertical lines
(histogram-like)
lwd=3, col="darkgreen",
main="Poisson(3) PMF", xlab="k", ylab="P(X=k)")

# Plot CDF
plot(x_range, pnorm(x_range), type="l",
main="Normal CDF", xlab="x", ylab="F(x)")
MODULE 4 — Probability Distributions ★★★

PATTERN: d=density/PMF, p=CDF, q=quantile/inverse-CDF, r=random sample. Same for ALL


distributions.

4.1 The d/p/q/r Pattern


# NORMAL — most tested
dnorm(x, mean=mu, sd=sigma) # f(x) — height of PDF at x
pnorm(x, mean=mu, sd=sigma) # F(x) — P(X <= x)
qnorm(p, mean=mu, sd=sigma) # x s.t. P(X<=x)=p (inverse CDF)
rnorm(n, mean=mu, sd=sigma) # Generate n random values

# Upper tail: P(X > x)


1 - pnorm(x, mean, sd)
pnorm(x, mean, sd, [Link]=FALSE) # Equivalent

# POISSON
dpois(k, lambda) # P(X = k)
ppois(k, lambda) # P(X <= k)
qpois(p, lambda) # Smallest k s.t. P(X<=k) >= p
rpois(n, lambda) # Simulate

# BINOMIAL
dbinom(k, size=n, prob=p) # P(X = k)
pbinom(k, size=n, prob=p) # P(X <= k)
qbinom(p, size=n, prob=p) # Quantile
rbinom(n, size=n, prob=p) # Simulate

# EXPONENTIAL
dexp(x, rate=lambda) # rate = 1/mean
pexp(x, rate=lambda)
qexp(p, rate=lambda)
rexp(n, rate=lambda)

# GAMMA
dgamma(x, shape=alpha, rate=beta) # rate = 1/scale
pgamma(x, shape=alpha, rate=beta)

# CHI-SQUARED
dchisq(x, df=k)
pchisq(x, df=k)
qchisq(p, df=k) # Critical value for chi-sq test

# t-DISTRIBUTION
dt(x, df=n)
qt(p, df=n) # Critical value for t-test
pt(t_stat, df=n) # p-value from t-statistic
# F-DISTRIBUTION
qf(p, df1, df2) # F critical value
pf(F_stat, df1, df2)# p-value

# NEGATIVE BINOMIAL
dnbinom(k, size=r, prob=p) # P(X=k) where X = failures before r
successes

# BETA
dbeta(x, shape1=a, shape2=b) # x in [0,1]

# UNIFORM
dunif(x, min=a, max=b)
punif(x, min=a, max=b)

4.2 Simulation (appears in EVERY paper)


# ALWAYS set seed first — exam checks reproducibility
[Link](42) # Or whatever number question specifies

# Simulate and compute statistics


sim <- rnorm(10000, mean=100, sd=15)
mean(sim) # Should be close to 100
var(sim) # Should be close to 225

# Simulate and compute probability


[Link](100)
claims <- rexp(10000, rate=1/500) # mean=500
mean(claims > 700) # Estimated P(X > 700)

# Simulate sum of random variables


[Link](1)
n_sim <- 100000
S <- replicate(n_sim, sum(rexp(10, rate=0.5))) # Sum of 10 Exp(0.5)
hist(S, freq=FALSE, main='Distribution of S')

# Using for-loop for simulation


[Link](42)
results <- numeric(10000) # Pre-allocate (faster than append)
for(i in 1:10000) {
sample_vals <- rnorm(30, mean=50, sd=10)
results[i] <- mean(sample_vals)
}
mean(results); var(results)
MODULE 5 — Statistical Inference ★★★

5.1 Hypothesis Tests for Proportions


PAST PAPER: Nov 2019 paper asked: test if proportion of negative Sensex months < 50%. This
exact pattern repeats.

# Exact binomial test


[Link](x=40, n=100, p=0.5, # x=successes, n=trials, p=H0
value
alternative="less", # "less","greater","[Link]"
[Link]=0.95)
# Read: p-value, 95% CI, estimate

# Proportions test (large sample, approximate)


[Link](x=40, n=100, p=0.5,
alternative="less",
correct=FALSE) # correct=TRUE for Yates continuity correction

# Two-sample proportion test


[Link](x=c(x1, x2), n=c(n1, n2))

5.2 t-Tests
# One-sample t-test: H0: mu = mu0
[Link](x, mu=0) # Test if mean = 0
[Link](x, mu=100, alternative='greater') # H1: mu > 100

# Two-sample t-test: H0: mu1 = mu2


[Link](x, y, [Link]=TRUE) # Assumes equal variances
[Link](x, y, [Link]=FALSE) # Welch test (default)
[Link](x, y, paired=TRUE) # Paired t-test

# Extract components programmatically


result <- [Link](x, mu=0)
result$statistic # t-statistic
result$[Link] # p-value
result$[Link] # 95% confidence interval
result$estimate # sample mean

5.3 Chi-Squared Tests


# Chi-squared goodness of fit
observed <- c(25, 30, 45) # Observed counts
expected_probs <- c(1/3, 1/3, 1/3) # H0 probabilities
[Link](observed, p=expected_probs)
# Chi-squared test of independence (from contingency table)
tbl <- table(df$Var1, df$Var2)
[Link](tbl)
[Link](tbl)$expected # Check expected counts (need >= 5)

# F-test for equality of variances


[Link](x, y) # H0: var(x) = var(y)
[Link](x, y)$[Link]

5.4 Non-Parametric Tests


# Wilcoxon signed-rank test (non-param equivalent of one-sample t)
[Link](x, mu=0)

# Wilcoxon rank-sum test (non-param equivalent of two-sample t)


[Link](x, y)

# Kolmogorov-Smirnov test (tests if data follows a distribution)


[Link](x, 'pnorm', mean=mean(x), sd=sd(x)) # Test normality
[Link](x, y) # Two-sample KS test

5.5 Maximum Likelihood Estimation (MLE) with optim()


# Poisson MLE example
data <- c(2, 3, 1, 4, 2, 5, 3, 2, 1, 4)

neg_log_lik <- function(lambda, data) {


-sum(dpois(data, lambda, log=TRUE))
}

result <- optim(par=2, fn=neg_log_lik, data=data, method='Brent',


lower=0.001, upper=100)
result$par # MLE of lambda

# Note: For Poisson, MLE = mean(data) analytically


# Use optim() only when no closed-form exists

# Normal MLE (both mu and sigma)


neg_ll_normal <- function(params, data) {
mu <- params[1]
sigma <- params[2]
if(sigma <= 0) return(Inf)
-sum(dnorm(data, mean=mu, sd=sigma, log=TRUE))
}
result2 <- optim(par=c(mean(x), sd(x)), fn=neg_ll_normal, data=x)
result2$par # c(mu_hat, sigma_hat)
5.6 Confidence Intervals
# From [Link] output
[Link](x)$[Link] # 95% CI for mean
[Link](x, [Link]=0.99)$[Link] # 99% CI

# Manual 95% CI for mean (large sample)


n <- length(x)
se <- sd(x) / sqrt(n)
ci <- c(mean(x) - 1.96*se, mean(x) + 1.96*se)

# Manual CI using t critical value (small sample)


t_crit <- qt(0.975, df=n-1) # 97.5th percentile of t(n-1)
ci <- c(mean(x) - t_crit*se, mean(x) + t_crit*se)

# CI for proportion
[Link](x=40, n=100)$[Link]
MODULE 6 — Linear Regression ★★★ (30% of paper)

6.1 Fitting & Reading Output


MOST IMPORTANT: Always know how to read summary(lm_model) fully. Every component gets
asked.

# Fit model
model <- lm(y ~ x, data=df) # Simple: y = b0 + b1*x
model <- lm(y ~ x1 + x2, data=df) # Multiple regression

# Full output — MEMORISE what each bit means


summary(model)
# Output breakdown:
# Residuals: min/Q1/median/Q3/max of residuals
# Coefficients:
# (Intercept) Est [Link] t-value Pr(>|t|) ***
# x Est [Link] t-value Pr(>|t|) ***
# Residual std error = sigma_hat (on df=n-p-1)
# R-squared: proportion of variance explained
# Adjusted R-sq: penalises for extra predictors
# F-statistic: overall model significance

# Individual extractors
coef(model) # Coefficients vector
coef(model)[1] # Intercept only
coef(model)[2] # Slope (first predictor)
confint(model) # 95% CI for each coefficient
confint(model, level=0.99)
residuals(model) # Raw residuals (y - y_hat)
fitted(model) # Fitted values y_hat
sigma(model) # Residual standard error
AIC(model) # Akaike information criterion
BIC(model) # Bayesian information criterion
logLik(model) # Log-likelihood

6.2 Multiple Regression & Model Building


# Full model
full_model <- lm(y ~ x1 + x2 + x3 + x4, data=df)

# Add interactions
model_int <- lm(y ~ x1 * x2, data=df) # x1 + x2 + x1:x2
model_int <- lm(y ~ x1 + x2 + x1:x2, data=df) # Same

# Categorical predictors (factors)


df$Sector <- [Link](df$Sector) # Convert to factor first
model_cat <- lm(y ~ x + Sector, data=df) # Sector creates dummy vars
# R auto-creates k-1 dummies; baseline = first alphabetic level

# Polynomial regression
model_poly <- lm(y ~ x + I(x^2), data=df) # I() protects ^ from formula
rules

# Log transformation
model_log <- lm(log(y) ~ x, data=df)
model_log <- lm(y ~ log(x), data=df)

# Stepwise model selection (backward by default)


step(full_model) # AIC-based selection
step(full_model, direction='backward')
step(null_model, scope=list(upper=full_model), direction='forward')

6.3 Prediction
# Point prediction
new_data <- [Link](x1=25, x2=3.5) # Must use SAME column names as
training
predict(model, newdata=new_data)

# Confidence interval for MEAN response (narrower)


predict(model, newdata=new_data, interval='confidence', level=0.95)
# Output: fit, lwr, upr

# Prediction interval for NEW individual observation (wider)


predict(model, newdata=new_data, interval='prediction', level=0.95)

# Key difference:
# Confidence interval = interval for E[Y|x]
# Prediction interval = interval for individual Y|x (always wider)

6.4 Residual Diagnostics ★★★


EXAM PATTERN: Every regression question ends with: 'Plot residuals and comment on model
adequacy.'

# 4-panel diagnostic plot (standard in every exam)


par(mfrow=c(2,2))
plot(model)
par(mfrow=c(1,1))

# Panel 1 — Residuals vs Fitted:


# Good: random scatter around y=0
# Bad: curved pattern (nonlinearity), funnel shape (heteroscedasticity)

# Panel 2 — Normal Q-Q of residuals:


# Good: points on diagonal line
# Bad: S-shape (skewed), heavy tails (thick tails)

# Panel 3 — Scale-Location (sqrt(|residuals|) vs fitted):


# Good: horizontal line, constant spread
# Bad: upward trend (variance increases with fitted values)

# Panel 4 — Cook's Distance / Leverage:


# Points beyond dashed line = influential observations

# Individual residual plots


plot(fitted(model), residuals(model), main='Residuals vs Fitted')
abline(h=0, col='red', lty=2)
qqnorm(residuals(model)); qqline(residuals(model), col='red')

# Standardised residuals
rstandard(model) # Standardised
rstudent(model) # Studentised (deletes each obs)

# Leverage and influence


hatvalues(model) # Hat matrix diagonal (leverage)
[Link](model) # Cook's D: overall influence
MODULE 7 — Generalised Linear Models (GLM) ★★

7.1 Fitting GLMs


# General syntax
model <- glm(y ~ x1 + x2, family=FAMILY, data=df)

# ── LOGISTIC REGRESSION (binary outcome y = 0/1) ──


log_model <- glm(y ~ x1 + x2, family=binomial, data=df)
log_model <- glm(y ~ x1 + x2, family=binomial(link='logit'), data=df)

# ── POISSON REGRESSION (count outcome) ──


pois_model <- glm(y ~ x1 + x2, family=poisson, data=df)
pois_model <- glm(y ~ x1 + x2, family=poisson(link='log'), data=df)

# ── GAMMA REGRESSION (positive continuous, right-skewed) ──


gam_model <- glm(y ~ x1 + x2, family=Gamma(link='log'), data=df)

# ── GAUSSIAN = ordinary linear regression ──


glm(y ~ x, family=gaussian) # Same as lm()

# Summary
summary(log_model)
# Output includes: Coefficients (on link scale!), z-values (not t!),
# Null deviance, Residual deviance, AIC

7.2 Interpreting GLM Output


# LOGISTIC: Coefficients are LOG-ODDS
coef(log_model) # Log-odds scale
exp(coef(log_model)) # ODDS RATIOS (more interpretable)
exp(confint(log_model)) # CI for odds ratios

# POISSON: Coefficients are LOG of rate


exp(coef(pois_model)) # Rate ratios / incidence rate ratios

# Deviance (lower = better fit)


deviance(model) # Residual deviance
model$[Link] # Null model deviance (intercept only)
model$deviance # Same as deviance(model)
model$[Link] # Degrees of freedom

# AIC comparison between models


AIC(model1); AIC(model2) # Lower AIC = better

# Deviance test (like F-test for GLMs)


anova(model_small, model_large, test='Chisq')
# Predict on original scale (not link scale)
predict(log_model, type='response') # Probabilities
predict(pois_model, type='response') # Expected counts
predict(log_model, newdata=df_new, type='response')

7.3 GLM Residuals


# Pearson residuals
residuals(model, type='pearson')

# Deviance residuals (default)


residuals(model, type='deviance')
residuals(model) # Same as deviance residuals

# Plot residuals
plot(fitted(model), residuals(model, type='pearson'),
main='Pearson Residuals vs Fitted',
xlab='Fitted Values', ylab='Pearson Residuals')
abline(h=0, col='red', lty=2)
MODULE 8 — Bayesian Statistics in R ★

8.1 Conjugate Prior Updates


# ── BETA-BINOMIAL (most common) ──
# Prior: theta ~ Beta(alpha0, beta0)
# Data: x successes in n trials
# Posterior: theta ~ Beta(alpha0 + x, beta0 + n - x)

alpha0 <- 2; beta0 <- 5 # Prior parameters


x <- 8; n <- 20 # Observed: 8 successes in 20 trials

alpha_post <- alpha0 + x


beta_post <- beta0 + (n - x)

# Posterior mean (Bayes estimator under squared error loss)


post_mean <- alpha_post / (alpha_post + beta_post)

# Posterior mode
post_mode <- (alpha_post - 1) / (alpha_post + beta_post - 2)

# 95% Credible interval


qbeta(c(0.025, 0.975), alpha_post, beta_post)

# ── GAMMA-POISSON ──
# Prior: lambda ~ Gamma(alpha0, beta0)
# Data: total count s = sum(x_i) over n observations
# Posterior: lambda ~ Gamma(alpha0 + s, beta0 + n)

alpha0 <- 3; beta0 <- 1


s <- sum(data); n <- length(data)
alpha_post <- alpha0 + s
beta_post <- beta0 + n
post_mean <- alpha_post / beta_post
qgamma(c(0.025, 0.975), shape=alpha_post, rate=beta_post)

# ── NORMAL-NORMAL ──
# Prior: mu ~ N(mu0, sigma0^2)
# Data: x_bar from n obs, known sigma^2
# Posterior mean:
post_mean <- (mu0/sigma0^2 + n*x_bar/sigma^2) / (1/sigma0^2 + n/sigma^2)

8.2 Credibility Theory


# Credibility premium formula
# P_cred = Z * x_bar + (1 - Z) * mu_prior
# where Z = n / (n + k), k = sigma^2_process / sigma^2_between
n <- 5 # Number of observations/years
k <- 4 # Credibility parameter
Z <- n / (n + k) # Credibility factor

x_bar <- 120 # Observed mean


mu_prior <- 100 # Prior/collective mean

P_cred <- Z * x_bar + (1 - Z) * mu_prior


P_cred
MODULE 9 — Control Flow, Functions & Loops

FOR PYTHON PROGRAMMERS: Syntax is different but concepts are identical. Main gotcha: R
indexing starts at 1, not 0.

9.1 Conditionals & Loops


# if-else (same concept as Python, different syntax)
if (x > 0) {
print("positive")
} else if (x == 0) {
print("zero")
} else {
print("negative")
}

# ifelse() — vectorised (like [Link] in Python)


result <- ifelse(x > 0, "Gain", "Loss") # Works on entire vector

# for loop
for (i in 1:10) {
cat(i, '\n') # cat() is like print() for simple output
}

# Loop over vector elements


for (val in c(2, 5, 8, 11)) {
cat('Square:', val^2, '\n')
}

# while loop
i <- 1
while (i <= 5) {
print(i)
i <- i + 1
}

9.2 Writing Functions


# Basic function (like def in Python)
my_mean <- function(x) {
return(sum(x) / length(x))
}
my_mean(c(1, 2, 3, 4, 5)) # Call it

# Multiple arguments with defaults


conf_interval <- function(x, level=0.95) {
n <- length(x)
se <- sd(x) / sqrt(n)
alph <- 1 - level
t_c <- qt(1 - alph/2, df=n-1)
c(lower = mean(x) - t_c*se,
upper = mean(x) + t_c*se)
}
conf_interval(data) # Uses default 95%
conf_interval(data, 0.99) # 99% CI

9.3 Apply Family (Vectorised Operations)


# apply() — over rows (MARGIN=1) or columns (MARGIN=2) of matrix/df
apply(df_numeric, 2, mean) # Column means (like [Link]() in pandas)
apply(df_numeric, 1, sum) # Row sums
apply(df_numeric, 2, function(x) round(sd(x), 3))

# sapply() — apply function to each element of a vector, returns vector


sapply(1:10, function(x) x^2) # c(1,4,9,16,...,100)
sapply(df, class) # Data type of each column

# lapply() — like sapply but returns list


lapply(df, mean)

# tapply() — apply by group (like groupby in pandas)


tapply(df$Salary, df$Department, mean) # Mean salary per department
tapply(df$Returns, df$Sector, sd) # SD of returns per sector
MODULE 10 — Quick Reference & Exam Patterns

10.1 Recurring Past Paper Patterns

PATTERN A — Nov 2019: Load CSV → basic stats → proportion test → contingency table →
chi-sq test → scree plot from PCA

# Pattern A template
df <- [Link]('Indices_Returns.csv')

# Step 1: Proportion
n_neg <- sum(df$Sensex < 0)
n <- nrow(df)
prop <- n_neg / n

# Step 2: Test proportion


[Link](n_neg, n, p=0.5, alternative='less', [Link]=0.95)
[Link](n_neg, n, p=0.5, alternative='less', [Link]=0.99)

# Step 3: Classify and make contingency table


df$FI_cat <- ifelse(df$FI > 0, 'Positive', 'Negative')
df$IT_cat <- ifelse(df$IT > 0, 'Positive', 'Negative')
tbl <- table(df$FI_cat, df$IT_cat)
[Link](tbl)

# Step 4: PCA
pca <- prcomp(df[ , numeric_cols], scale.=TRUE)
summary(pca)
round(cor(pca$x), 3)
plot(pca, type='l', main='Scree Plot')

PATTERN B — Regression paper: Load data → EDA → fit lm → summary → residual plots →
predict with interval → compare models by AIC

# Pattern B template
df <- [Link]('insurance_data.csv')
str(df); summary(df)

# EDA
par(mfrow=c(1,2))
hist(df$ClaimAmt, freq=FALSE, main='Claim Amounts', xlab='Amount')
qqnorm(df$ClaimAmt); qqline(df$ClaimAmt, col='red')

# Fit models
m1 <- lm(ClaimAmt ~ Age, data=df)
m2 <- lm(ClaimAmt ~ Age + Sex, data=df)
m3 <- lm(ClaimAmt ~ Age + Sex + Age:Sex, data=df)

# Compare
AIC(m1, m2, m3) # Lower is better

# Best model summary + diagnostics


summary(m2)
par(mfrow=c(2,2)); plot(m2); par(mfrow=c(1,1))

# Prediction
new <- [Link](Age=45, Sex='M')
predict(m2, newdata=new, interval='prediction')

PATTERN C — GLM paper: Binary/count outcome → fit glm → interpret coefficients → deviance
→ predict probabilities

# Pattern C template (logistic)


df <- [Link]('claim_occurrence.csv')

# Fit
model <- glm(HasClaim ~ Age + Premium + Region,
family=binomial, data=df)
summary(model)

# Coefficients: log-odds scale


# exp() gives odds ratios
exp(coef(model))
exp(confint(model))

# Deviance test
null_mod <- glm(HasClaim ~ 1, family=binomial, data=df)
anova(null_mod, model, test='Chisq')

# Predict probabilities
pred_probs <- predict(model, type='response')
hist(pred_probs, main='Predicted Probabilities')

10.2 Python → R Translation


What you want Python / pandas R equivalent
Load CSV pd.read_csv('[Link]') [Link]('[Link]')

Shape [Link] dim(df)

Column names [Link] names(df)

First rows [Link]() head(df)

Data types [Link] str(df)

Select column df['col'] or [Link] df$col


Filter rows df[df.x > 2] df[df$x > 2, ]

Mean [Link]() mean(df$col)

Std dev [Link]() sd(df$col)

Group mean [Link]('g') tapply(df$x, df$g, mean)


['x'].mean()
Print print(x) print(x) or cat(x)

Range 1–10 range(1,11) 1:10

List comprehension [f(x) for x in xs] sapply(xs, f)

Null check [Link](x) [Link](x)

Drop NAs [Link]() [Link](df)

String format f'val={v:.3f}' sprintf('val=%.3f', v)

10.3 Key Functions Master List


# ── DATA ────────────────────────────────────────────────────
[Link]() [Link]() load() str() head() summary() dim()
names() table() [Link]() [Link]() [Link]() [Link]()

# ── STATS ───────────────────────────────────────────────────
mean() median() var() sd() quantile() IQR() cor() [Link]()
sum() cumsum() prod() length() which() sort() order()

# ── DISTRIBUTIONS (d/p/q/r) ─────────────────────────────────


dnorm pnorm qnorm rnorm dpois ppois qpois rpois
dbinom pbinom qbinom rbinom dexp pexp qexp rexp
dgamma pgamma dchisq pchisq qchisq dt pt qt

# ── INFERENCE ───────────────────────────────────────────────
[Link]() [Link]() [Link]() [Link]() [Link]()
[Link]() [Link]() [Link]() optim() nlm()

# ── REGRESSION ──────────────────────────────────────────────
lm() glm() summary() coef() confint() predict() residuals()
fitted() AIC() BIC() anova() step() sigma() hatvalues()
rstandard() rstudent() [Link]() deviance()

# ── PLOTTING ────────────────────────────────────────────────
hist() plot() boxplot() barplot() qqnorm() qqline()
lines() points() abline() curve() density() par(mfrow=)

# ── SIMULATION ──────────────────────────────────────────────
[Link]() replicate() sample() runif() rbinom()

# ── UTILITY ─────────────────────────────────────────────────
round() ceiling() floor() abs() sqrt() log() exp()
paste() paste0() sprintf() cat() print() c() seq()
numeric() integer() character() logical() matrix() cbind() rbind()
apply() sapply() lapply() tapply() replicate() Reduce()

10.4 Last-Minute Exam Checklist


• Load data FIRST with [Link]() — do this before writing any other code
• Always [Link](42) before any simulation question
• For regression, always run summary(model) and read ALL parts
• Residual plots: run par(mfrow=c(2,2)); plot(model) — comment on each panel
• GLM coefficients are on the link scale — use exp(coef(model)) for logistic
• For proportion tests: use [Link]() (exact) — specify alternative='less' or 'greater'
• t-test and ALL tests: state H0, H1, p-value, conclusion in plain English
• Confidence interval ≠ Prediction interval — know which one is wider and why
• Bayesian: state prior family → posterior family → compute posterior mean as estimate
• Model comparison: lower AIC = better; lower deviance = better fit

You might also like