# ##########################################################
# R Foundations — full course R scripts
# https://rverseanalytics.com/courses/r-foundations
# ##########################################################



# ----------------------------------------------------------
# R Basics
# ----------------------------------------------------------

# R Basics - run real R, no install
# 1. R is a calculator
2 + 2
10 * 5
100 / 7
2 ^ 10
# 2. Store values in variables with  <-
price <- 20
quantity <- 3
price * quantity
# 3. Call a function: name(input)
sqrt(144)
round(3.14159, 2)
toupper("hello r")
# 4. Comments start with #  - R ignores them
radius <- 5
area <- pi * radius ^ 2
area
# 5. Your turn: Celsius to Fahrenheit
celsius <- 25
celsius * 9 / 5 + 32


# ----------------------------------------------------------
# Vectors in R
# ----------------------------------------------------------

# Vectors in R - the building block
# 1. Combine values with c()
ages <- c(23, 35, 41, 29, 52)
ages
names <- c("Ada", "Bo", "Cy")
names
# 2. Maths runs on every element at once
prices <- c(10, 20, 30)
prices * 1.2
prices - 5
# 3. Pick elements with [ ]   R counts from 1
ages[1]
ages[c(1, 3)]
ages[ages > 30]
# 4. Quick ways to build vectors
1:10
seq(0, 1, by = 0.25)
rep("x", 4)
# 5. Summarise a vector
scores <- c(88, 92, 79, 95, 84, 90)
length(scores)
mean(scores)
max(scores)


# ----------------------------------------------------------
# Data Types in R
# ----------------------------------------------------------

# Data types in R
x <- 42L          # integer
y <- 3.14         # double (numeric)
name <- "Rverse"  # character
ok <- TRUE        # logical
class(x); class(y); class(name); class(ok)
# Check a type, or convert (coerce) it
is.numeric(y)
is.character(name)
as.integer("10") + 5
as.numeric("3.5") * 2
# Logicals are numbers underneath
sum(c(TRUE, FALSE, TRUE, TRUE))    # counts the TRUEs
mean(c(TRUE, FALSE, TRUE, TRUE))   # proportion that are TRUE
# A factor stores categories with a fixed set of levels
grp <- factor(c("low", "high", "low", "mid"), levels = c("low", "mid", "high"))
grp
as.integer(grp)   # each category is stored as a code


# ----------------------------------------------------------
# Subsetting & Indexing
# ----------------------------------------------------------

# Pick elements out of a vector with [ ]
v <- c(10, 20, 30, 40, 50)
v[2]          # the second element
v[c(1, 3)]    # first and third
v[-1]         # everything except the first
v[v > 25]     # keep the ones that pass a test
# Name the elements, then pull by name
scores <- c(ali = 90, vera = 82, sam = 77)
scores["vera"]
# A data frame is indexed as [rows, columns]
head(mtcars[, c("mpg", "hp")])
mtcars[mtcars$mpg > 30, c("mpg", "cyl")]
# $ and [[ ]] pull a single column out
mtcars$mpg[1:5]
mtcars[["hp"]][1:5]


# ----------------------------------------------------------
# Logical Conditions & if/else
# ----------------------------------------------------------

# Comparisons return TRUE or FALSE
5 > 3
5 == 5
"a" != "b"
c(1, 5, 9) >= 5
# Combine tests: & (and), | (or), ! (not), %in%
x <- 7
x > 0 & x < 10
x < 0 | x > 5
5 %in% c(1, 3, 5, 7)
# if / else runs different code for one condition
temp <- 28
if (temp > 25) {
  print("warm")
} else {
  print("cool")
}
# ifelse() applies the test to a whole vector at once
temps <- c(18, 24, 31, 27)
ifelse(temps > 25, "warm", "cool")


# ----------------------------------------------------------
# Data Frames in R
# ----------------------------------------------------------

# Data Frames - R's spreadsheet
people <- data.frame(name = c("Ada", "Bo", "Cy"), age = c(35, 41, 29))
people
# 2. Pull a column with $
people$age
mean(people$age)
# 3. A built-in dataset: mtcars (32 cars)
head(mtcars[, 1:4])
nrow(mtcars)
# 4. Filter rows:  [rows, columns]
mtcars[mtcars$mpg > 25, 1:4]
# 5. A grouped summary: mpg by gearbox
aggregate(mpg ~ am, data = mtcars, FUN = mean)


# ----------------------------------------------------------
# Factors: Categorical Data
# ----------------------------------------------------------

# Categorical data is stored as a factor
class(iris$Species)
levels(iris$Species)
table(iris$Species)
# Build a factor with a meaningful order
sz <- factor(c("S", "L", "M", "S", "L"), levels = c("S", "M", "L"))
sz
as.integer(sz)   # the codes follow the level order
# Factors drive grouping in plots and models
boxplot(Sepal.Length ~ Species, data = iris,
        col = c("#17a2b8", "#2f6fed", "#5aa0ff"))
# Choose which level is the reference (baseline)
sp <- relevel(iris$Species, ref = "versicolor")
levels(sp)


# ----------------------------------------------------------
# Missing Values (NA)
# ----------------------------------------------------------

# Real data has gaps, marked NA
head(airquality$Ozone, 10)
sum(is.na(airquality$Ozone))   # how many are missing?
# NA spreads: one gap makes the answer NA
mean(airquality$Ozone)               # NA
mean(airquality$Ozone, na.rm = TRUE) # ignore the gaps
# Keep only the complete rows
nrow(airquality)
nrow(na.omit(airquality))
sum(complete.cases(airquality))
# Or fill the gaps (here: with the median)
oz <- airquality$Ozone
oz[is.na(oz)] <- median(oz, na.rm = TRUE)
sum(is.na(oz))


# ----------------------------------------------------------
# Reading Data into R
# ----------------------------------------------------------

# R reads files relative to the working directory
getwd()
# Write a CSV, then read it back in
write.csv(mtcars, "cars.csv", row.names = FALSE)
cars <- read.csv("cars.csv")
# Always inspect a data frame right after importing
str(cars)
head(cars)
# Real files: give the path (or use readr for speed)
# cars <- read.csv("data/cars.csv")
# library(readr); cars <- read_csv("data/cars.csv")
dim(cars)


# ----------------------------------------------------------
# Writing Your Own Functions
# ----------------------------------------------------------

# Write your own function
celsius_to_f <- function(c) {
  c * 9/5 + 32
}
celsius_to_f(25)
celsius_to_f(c(0, 20, 37))
# Arguments can have default values
greet <- function(name, greeting = "Hello") {
  paste0(greeting, ", ", name, "!")
}
greet("Bartu")
greet("Bartu", "Hi")
# Do several steps, then return a result
describe <- function(x) {
  m <- mean(x)
  s <- sd(x)
  return(c(mean = m, sd = s))
}
describe(c(4, 8, 15, 16, 23, 42))
# Apply your function across many values
square <- function(x) x^2
sapply(1:5, square)


# ----------------------------------------------------------
# Installing & Loading Packages
# ----------------------------------------------------------

# R ships with base packages; thousands more live on CRAN.
# Install a package ONCE (in your own R):
# install.packages("dplyr")
# Load a package each session to use its functions.
# MASS ships with R, so we can load it right away:
library(MASS)
head(Boston[, c("medv", "rm", "age")])   # a dataset from MASS
# Now MASS's datasets and functions are available
hist(Boston$medv, col = "#2f6fed",
     xlab = "Median home value ($1000s)", main = "Boston housing")
# Use one function without attaching the whole package: pkg::fun
MASS::fractions(0.75)
(.packages())   # which packages are attached now


# ----------------------------------------------------------
# Your First Plot in R
# ----------------------------------------------------------

# Your First Plot in R - base graphics
# 1. A histogram: the shape of one variable
hist(mtcars$mpg, col = "#2f6fed", main = "Fuel efficiency", xlab = "Miles per gallon")
# 2. A scatter plot: two variables
plot(mtcars$wt, mtcars$mpg, pch = 19, col = "#17a2b8", xlab = "Weight (1000 lbs)", ylab = "Miles per gallon")
# 3. Add a regression trend line
plot(mtcars$wt, mtcars$mpg, pch = 19, col = "#17a2b8", xlab = "Weight", ylab = "MPG")
abline(lm(mpg ~ wt, data = mtcars), col = "#b02a37", lwd = 2)
# 4. A boxplot by group
boxplot(mpg ~ cyl, data = mtcars, col = "#2f6fed33", border = "#1b2a4a", xlab = "Cylinders", ylab = "MPG")


# ----------------------------------------------------------
# Basic Statistics in R
# ----------------------------------------------------------

# Basic Statistics in R
# 1. Summary statistics
scores <- c(88, 92, 79, 95, 84, 90, 76, 88)
mean(scores)
sd(scores)
summary(scores)
# 2. A frequency table
table(mtcars$cyl)
# 3. Correlation:  -1 to +1
cor(mtcars$wt, mtcars$mpg)
# 4. Your first t-test: does gearbox affect mpg?
t.test(mpg ~ am, data = mtcars)
# 5. A simple linear model
model <- lm(mpg ~ wt, data = mtcars)
summary(model)


# ----------------------------------------------------------
# Data Wrangling with dplyr
# ----------------------------------------------------------

library(dplyr)
# filter() keeps the rows that pass a test
filter(mtcars, mpg > 30)
# select() keeps the columns you name
head(select(mtcars, mpg, hp, wt))
# mutate() adds a new column
head(mutate(mtcars, kpl = mpg * 0.425)[, c("mpg", "kpl")])
# group_by() + summarise() collapse groups to one row each
summarise(group_by(mtcars, cyl),
          n = n(), avg_mpg = mean(mpg))


# ----------------------------------------------------------
# The Pipe (|>)
# ----------------------------------------------------------

library(dplyr)
# Nested calls read inside-out and are hard to follow
head(arrange(select(mtcars, mpg, hp), desc(mpg)))
# The native pipe |> feeds the left side into the next function
mtcars |> select(mpg, hp) |> arrange(desc(mpg)) |> head()
# A pipeline reads top-to-bottom, like a recipe
mtcars |>
  filter(cyl == 4) |>
  summarise(n = n(), avg_mpg = mean(mpg))
# The pipe works with base R too
c(4, 8, 15, 16, 23, 42) |> mean() |> round(1)
