1 Learning Objectives

  • Create and manipulate matrices
  • Create and access elements of lists
  • Build, inspect, and subset data frames — R’s most important structure for real data
  • Create and use factors for categorical data
  • Choose the right structure for a given problem

2 Matrices

A matrix is a 2-dimensional structure where every element is the same data type (like a vector, but with rows and columns).

m <- matrix(1:12, nrow = 3, ncol = 4)
m
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
dim(m)      # dimensions: rows, columns
## [1] 3 4
nrow(m)
## [1] 3
ncol(m)
## [1] 4

2.1 Indexing Matrices [row, column]

m[2, 3]       # element in row 2, column 3
## [1] 8
m[1, ]        # entire first row
## [1]  1  4  7 10
m[, 2]        # entire second column
## [1] 4 5 6
m[1:2, 3:4]   # sub-matrix
##      [,1] [,2]
## [1,]    7   10
## [2,]    8   11

2.2 Matrix Arithmetic

a <- matrix(1:4, nrow = 2)
b <- matrix(5:8, nrow = 2)

a + b            # element-wise addition
##      [,1] [,2]
## [1,]    6   10
## [2,]    8   12
a * b            # element-wise multiplication
##      [,1] [,2]
## [1,]    5   21
## [2,]   12   32
a %*% b          # TRUE matrix multiplication
##      [,1] [,2]
## [1,]   23   31
## [2,]   34   46
t(a)             # transpose
##      [,1] [,2]
## [1,]    1    2
## [2,]    3    4

3 Lists

A list can hold different data types, even other lists, vectors, or data frames — extremely flexible.

student <- list(
  name = "Aisha Ali",
  age = 22,
  scores = c(88, 91, 76),
  is_graduating = TRUE
)

student
## $name
## [1] "Aisha Ali"
## 
## $age
## [1] 22
## 
## $scores
## [1] 88 91 76
## 
## $is_graduating
## [1] TRUE

3.1 Accessing List Elements

student$name           # by name, using $
## [1] "Aisha Ali"
student[["scores"]]    # by name, using [[ ]]
## [1] 88 91 76
student[[3]]            # by position
## [1] 88 91 76
student["age"]          # single bracket -> returns a LIST (sub-list)
## $age
## [1] 22
student[["age"]]        # double bracket -> returns the VALUE itself
## [1] 22

Key distinction: [ ] always returns the same type of object (a smaller list); [[ ]] extracts the actual element/value inside.

3.2 Modifying Lists

student$age <- 23                 # update
student$university <- "UoB"       # add a new element
student
## $name
## [1] "Aisha Ali"
## 
## $age
## [1] 23
## 
## $scores
## [1] 88 91 76
## 
## $is_graduating
## [1] TRUE
## 
## $university
## [1] "UoB"

4 Data Frames

A data frame is the structure you will use constantly in real data analysis: a table where each column is a vector (all one type), but different columns can hold different types — just like a spreadsheet.

students_df <- data.frame(
  name = c("Amina", "Hodan", "Yusuf", "Deka"),
  age = c(21, 23, 19, 22),
  score = c(88, 92, 65, 79),
  passed = c(TRUE, TRUE, TRUE, TRUE)
)

students_df
##    name age score passed
## 1 Amina  21    88   TRUE
## 2 Hodan  23    92   TRUE
## 3 Yusuf  19    65   TRUE
## 4  Deka  22    79   TRUE

4.1 Inspecting a Data Frame

str(students_df)     # structure: types and preview of each column
## 'data.frame':    4 obs. of  4 variables:
##  $ name  : chr  "Amina" "Hodan" "Yusuf" "Deka"
##  $ age   : num  21 23 19 22
##  $ score : num  88 92 65 79
##  $ passed: logi  TRUE TRUE TRUE TRUE
summary(students_df) # summary statistics for each column
##      name                age            score       passed       
##  Length:4           Min.   :19.00   Min.   :65.0   Mode:logical  
##  Class :character   1st Qu.:20.50   1st Qu.:75.5   TRUE:4        
##  Mode  :character   Median :21.50   Median :83.5                 
##                     Mean   :21.25   Mean   :81.0                 
##                     3rd Qu.:22.25   3rd Qu.:89.0                 
##                     Max.   :23.00   Max.   :92.0
nrow(students_df)
## [1] 4
ncol(students_df)
## [1] 4
names(students_df)   # column names
## [1] "name"   "age"    "score"  "passed"
head(students_df, 2) # first 2 rows
##    name age score passed
## 1 Amina  21    88   TRUE
## 2 Hodan  23    92   TRUE

4.2 Subsetting Data Frames

students_df$name                    # single column as a vector
## [1] "Amina" "Hodan" "Yusuf" "Deka"
students_df[, "score"]              # same, using bracket notation
## [1] 88 92 65 79
students_df[1, ]                    # first row (all columns)
##    name age score passed
## 1 Amina  21    88   TRUE
students_df[students_df$score > 80, ]   # rows where score > 80
##    name age score passed
## 1 Amina  21    88   TRUE
## 2 Hodan  23    92   TRUE
students_df[students_df$score > 80, "name"]  # names of top scorers only
## [1] "Amina" "Hodan"

4.3 Adding and Modifying Columns

students_df$grade <- ifelse(students_df$score >= 80, "A", "B")
students_df
##    name age score passed grade
## 1 Amina  21    88   TRUE     A
## 2 Hodan  23    92   TRUE     A
## 3 Yusuf  19    65   TRUE     B
## 4  Deka  22    79   TRUE     B

5 Factors (Categorical Data)

A factor stores categorical variables (like “Male”/“Female” or “Freshman”/“Sophomore”/“Junior”/“Senior”) with a fixed, known set of possible values called levels.

year_level <- factor(c("Junior", "Freshman", "Senior", "Sophomore"),
                      levels = c("Freshman", "Sophomore", "Junior", "Senior"))
year_level
## [1] Junior    Freshman  Senior    Sophomore
## Levels: Freshman Sophomore Junior Senior
levels(year_level)
## [1] "Freshman"  "Sophomore" "Junior"    "Senior"
as.integer(year_level)   # internally stored as integers matching levels
## [1] 3 1 4 2

5.1 Ordered Factors

satisfaction <- factor(c("Medium", "High", "Low"),
                        levels = c("Low", "Medium", "High"),
                        ordered = TRUE)
satisfaction
## [1] Medium High   Low   
## Levels: Low < Medium < High
satisfaction[1] > satisfaction[3]   # "Medium" > "Low" -> TRUE, thanks to ordering
## [1] TRUE

6 Worked Example

Scenario: Building a small student registry from scratch.

registry <- data.frame(
  student_id = 1:5,
  name = c("Ali", "Sara", "Deka", "Omar", "Layla"),
  major = factor(c("ICT", "Business", "ICT", "Medicine", "Business")),
  gpa = c(3.4, 3.8, 2.9, 3.6, 3.1)
)

str(registry)
## 'data.frame':    5 obs. of  4 variables:
##  $ student_id: int  1 2 3 4 5
##  $ name      : chr  "Ali" "Sara" "Deka" "Omar" ...
##  $ major     : Factor w/ 3 levels "Business","ICT",..: 2 1 2 3 1
##  $ gpa       : num  3.4 3.8 2.9 3.6 3.1
# Students majoring in ICT
registry[registry$major == "ICT", ]
##   student_id name major gpa
## 1          1  Ali   ICT 3.4
## 3          3 Deka   ICT 2.9
# Average GPA by simply filtering
cs_avg_gpa <- mean(registry$gpa[registry$major == "ICT"])
cat("Average GPA of ICT students:", round(cs_avg_gpa, 2), "\n")
## Average GPA of ICT students: 3.15

7 Practice Exercises

  1. Create a 3x3 matrix of the numbers 1 through 9 and extract the middle element.
  2. Create a list representing yourself with at least 4 named elements (name, age, hobbies vector, is_student).
  3. Access the “hobbies” element of your list using both $ and [[ ]].
  4. Create a data frame of 5 books with columns: title, author, year, pages.
  5. Filter your books data frame to show only books published after 2000.
  6. Add a new column is_long that is TRUE if pages > 300.
  7. Create a factor for class_year with levels "100 Level" through "400 Level", ordered.
  8. Use str() and summary() on your books data frame and describe what each function tells you.

8 Quiz

Q1. What is the key difference between a matrix and a data frame?

  1. There is no difference
  2. A matrix requires all elements to be the same type; a data frame allows different types per column
  3. A data frame can only hold numbers
  4. A matrix can hold text but a data frame cannot

Q2. Which operator returns the actual value stored inside a list element (not a sub-list)?

  1. [ ]
  2. [[ ]]
  3. ( )
  4. { }

Q3. What R structure is best suited for a categorical variable like “Freshman/Sophomore/Junior/Senior”?

  1. A numeric vector
  2. A matrix
  3. A factor
  4. A list

Q4. What does students_df[students_df$score > 80, ] do?

  1. Selects the column named “score”
  2. Selects all rows where the score column exceeds 80
  3. Deletes rows where score is above 80
  4. Causes an error because of the comma

Q5. What function shows the internal structure (types and preview) of a data frame?

  1. summary()
  2. str()
  3. head()
  4. dim()
Click to reveal Answer Key Q1: b | Q2: b | Q3: c | Q4: b | Q5: b

9 Summary

  • Matrices: 2D, single data type — good for numerical/mathematical operations.
  • Lists: flexible containers holding mixed types, even other lists.
  • Data frames: the workhorse of data analysis — table-like, mixed column types.
  • Factors: represent categorical data efficiently, with optional ordering.

Next Lesson: Importing and Exporting Data (CSV, Excel).