#load the required library
library(readxl)
#load the data file into rstudio
lesson_completion <- read_excel("Lesson completion.xlsx")
pupil_attendance <- read_excel("Pupil attendance.xlsx")
pupil_scores <- read_excel("Pupil scores.xlsx")
school_information <- read_excel("School_information.xlsx")
#preview lesson_completion
head(lesson_completion,10)
str(lesson_completion)
## tibble [552 × 4] (S3: tbl_df/tbl/data.frame)
## $ school_id : num [1:552] 416 416 416 416 416 792 792 792 792 792 ...
## $ teacher_id : num [1:552] 505 202 124 516 145 545 201 669 258 259 ...
## $ grade : chr [1:552] "Grade 1" "Grade 2" "Grade 3" "Grade 4" ...
## $ lesson_completion_rate: num [1:552] 0.568 0.681 0.25 0.359 0.397 ...
summary(lesson_completion)
## school_id teacher_id grade lesson_completion_rate
## Min. : 416 Min. : 1.0 Length:552 Min. :0.0000
## 1st Qu.: 49698 1st Qu.:191.8 Class :character 1st Qu.:0.4420
## Median :223941 Median :374.5 Mode :character Median :0.6408
## Mean :283530 Mean :377.7 Mean :0.6001
## 3rd Qu.:421680 3rd Qu.:561.5 3rd Qu.:0.7722
## Max. :991980 Max. :763.0 Max. :1.0000
#preview pupil_attendance
head(pupil_attendance,10)
str(pupil_attendance)
## tibble [12,701 × 5] (S3: tbl_df/tbl/data.frame)
## $ school_id : num [1:12701] 35175 40580 9342 858450 792 ...
## $ pupil_id : num [1:12701] 1 7 8 10 13 14 16 18 27 34 ...
## $ grade : chr [1:12701] "Grade 1" "Grade 2" "Grade 5" "Grade 5" ...
## $ attendance_records: num [1:12701] 91 92 43 86 104 90 81 90 97 85 ...
## $ present_records : num [1:12701] 69 86 39 62 81 67 65 80 77 59 ...
summary(pupil_attendance)
## school_id pupil_id grade attendance_records
## Min. : 416 Min. : 1 Length:12701 Min. : 1.00
## 1st Qu.: 49404 1st Qu.: 6695 Class :character 1st Qu.: 74.00
## Median :223941 Median :13500 Mode :character Median : 90.00
## Mean :276782 Mean :13524 Mean : 82.29
## 3rd Qu.:406350 3rd Qu.:20277 3rd Qu.: 98.00
## Max. :991980 Max. :27063 Max. :109.00
## present_records
## Min. : 0.00
## 1st Qu.: 46.00
## Median : 66.00
## Mean : 62.36
## 3rd Qu.: 80.00
## Max. :107.00
# preview pupil_scores
head(pupil_scores,10)
str(pupil_scores)
## tibble [37,947 × 5] (S3: tbl_df/tbl/data.frame)
## $ school_id: num [1:37947] 35175 35175 35175 40580 40580 ...
## $ pupil_id : num [1:37947] 1 1 1 7 7 7 8 8 8 10 ...
## $ grade : chr [1:37947] "Grade 1" "Grade 1" "Grade 1" "Grade 2" ...
## $ subject : chr [1:37947] "Fluency" "Kiswahili" "Math" "Math" ...
## $ score : num [1:37947] 65 0.943 1 0.933 0.943 ...
summary(pupil_scores)
## school_id pupil_id grade subject
## Min. : 416 Min. : 1 Length:37947 Length:37947
## 1st Qu.: 49404 1st Qu.: 6698 Class :character Class :character
## Median :226128 Median :13506 Mode :character Mode :character
## Mean :277151 Mean :13528
## 3rd Qu.:406350 3rd Qu.:20282
## Max. :991980 Max. :27063
##
## score
## Min. : 0.0000
## 1st Qu.: 0.6857
## Median : 0.9249
## Mean : 38.1947
## 3rd Qu.: 56.0000
## Max. :383.0000
## NA's :1783
# preview pupil_information
head(school_information,10)
str(school_information)
## tibble [111 × 4] (S3: tbl_df/tbl/data.frame)
## $ region : chr [1:111] "Mombasa" "Kilifi" "Mombasa" "Eastern" ...
## $ province : chr [1:111] "Coast" "Coast" "Coast" "Eastern" ...
## $ school_id : num [1:111] 136992 687400 609982 223941 34092 ...
## $ tutoring_program: chr [1:111] "No" "Yes" "Yes" "No" ...
summary(school_information)
## region province school_id tutoring_program
## Length:111 Length:111 Min. : 416 Length:111
## Class :character Class :character 1st Qu.: 49551 Class :character
## Mode :character Mode :character Median :223941 Mode :character
## Mean :282162
## 3rd Qu.:420508
## Max. :991980
# Working on the base file
# load the required library
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.1 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
# reshape pupil_scores
pupil_scores_reshaped <- pupil_scores %>%
pivot_wider(
id_cols = c(school_id, pupil_id, grade),
names_from = subject,
values_from = score
)
head(pupil_scores_reshaped)
R code reshaped the pupil_scores data frame from long to wide format using the pivot_wider() function from the tidyverse package
#the data file (pupil_scores_reshaped) is renamed as base_file and merged with other files
#(pupil_attendance, lesson_completion and school_information)
base_file <- pupil_scores_reshaped
base_file <- merge(base_file, pupil_attendance, by = c("school_id", "pupil_id", "grade"), all.x = TRUE)
base_file <- merge(base_file, school_information, by = "school_id", all.x = TRUE)
base_file <- merge(base_file, lesson_completion, by = c("school_id", "grade"), all.x = TRUE)
# remove missing values
base_file <- base_file %>% na.omit()
head(base_file)
View(base_file)
#save the merged table (base file)
write.csv(base_file, file = "base_file.csv")
# making sure that required vales (present_records and attendance_records) are numeric
base_file <- mutate(base_file,
present_records = as.numeric(present_records),
attendance_records = as.numeric(attendance_records))
# Calculating KPI (Percentage Pupils Present) for each pupils in 2 decimal points
base_file <- mutate(base_file,
percent_present = round((present_records / attendance_records)*100,2))
# Calculating network-level average Percent Pupils Present (all_pupils_kpi)
all_pupils_kpi <- mean(base_file$present_records/base_file$attendance_records) * 100
all_pupils_kpi
## [1] 77.43928
#Express average Percent Pupils Present in two decimal points
cat("Average Percent Pupils Present:", round(all_pupils_kpi, 2), "% \n")
## Average Percent Pupils Present: 77.44 %
# Calculate average percent present per school rounded to 2 decimal points
school_avg_present <- base_file %>%
group_by(school_id) %>%
summarize(avg_percent_present = round(mean(percent_present, na.rm = TRUE),2))
head(school_avg_present)
# Calculate average percentage present at the school-level.
school_level_avg_present <- mean(school_avg_present$avg_percent_present, na.rm = TRUE)
cat("Average Percent Pupils Present at the school-level.:", round(school_level_avg_present, 2), "% \n")
## Average Percent Pupils Present at the school-level.: 77.37 %
Network Level KPI helps in understanding the overall attendance pattern across the entire system. While the school level approach allows us to identify schools with poor or good attendance rates. In this case change between the two KPI does not matter. It matters when a very large number of schools are involved.
# load the library for creating visualizations
library(ggplot2)
# Making sure fluency scores are numeric
base_file <- mutate(base_file, Fluency = as.numeric(Fluency))
# Obtaining Average fluency scores for each grade
average_fluency <- base_file %>%
group_by(grade) %>%
summarise(avg_fluency = mean(Fluency))
head(average_fluency)
# Plotting average fluency scores
ggplot(average_fluency, aes(x = grade, y = avg_fluency)) +
geom_bar(stat = "identity", fill = "skyblue") +
labs(title = "Average Fluency Scores by Grade",
x = "Grade",
y = "Average Fluency Score")
### Task 2
#Checking for Regions with Lowest and Highest Average Fluency across all grades.
region_fluency_stats <- base_file %>%
group_by(region) %>%
summarize(avg_fluency = mean(Fluency, na.rm = TRUE)) %>%
arrange(avg_fluency)
head(region_fluency_stats)
# Lowest
print(paste0("Region with Lowest Average Fluency:", region_fluency_stats$region[1]))
## [1] "Region with Lowest Average Fluency:Kirinyaga"
# Highest
print(paste0("Region with Highest Average Fluency:", region_fluency_stats$region[nrow(region_fluency_stats)]))
## [1] "Region with Highest Average Fluency:Machakos"
The Regions with Lowest and Highest Average Fluency across all grades are Kirinyaga and Machakos respectively.
# Share of Pupils Scoring Under 10 by Grade (Bar Chart)
low_fluency <- mutate(base_file,
low_score = ifelse(Fluency <= 10, 1, 0))
low_fluency_grade <- low_fluency %>%
group_by(grade) %>%
summarize(share_low = mean(low_score))
ggplot(low_fluency_grade, aes(x = grade, y = share_low)) +
geom_bar(stat = "identity", fill = "skyblue") +
labs(title = "Share of Pupils Scoring Under 10 by Grade",
x = "Grade",
y = "Share")
#School with highest share of pupils scoring under threshold in grade 3
grade_3_low <- low_fluency %>%
filter(grade == "Grade 3") # Filter for grade 3 only
school_highest_low <- grade_3_low %>%
group_by(school_id) %>%
summarize(share_low = mean(low_score)) %>%
arrange(desc(share_low)) # Arrange by share in descending order
head(school_highest_low)
print(paste0("School with Highest Share of Pupils Scoring Under 10 (Grade 3):",
school_highest_low$school_id[1]))
## [1] "School with Highest Share of Pupils Scoring Under 10 (Grade 3):223941"
#Assessing effects of tutoring program on test scores and attendance
# Calculate means for test scores and attendance by tutoring program
effect_analysis <- base_file %>%
group_by(tutoring_program) %>%
summarise(
avg_kiswahili_score = mean(Kiswahili),
avg_fluency_score = mean(Fluency),
avg_attendance = mean(present_records / attendance_records)
)
print(effect_analysis)
## # A tibble: 2 × 4
## tutoring_program avg_kiswahili_score avg_fluency_score avg_attendance
## <chr> <dbl> <dbl> <dbl>
## 1 No 0.680 97.4 0.763
## 2 Yes 0.807 130. 0.786
#Assessing potential confounding effect of lesson completion rate
# Correlation analysis
correlation_matrix <- cor(base_file[, c("Math", "Kiswahili", "Fluency", "attendance_records", "lesson_completion_rate")])
correlation_matrix
## Math Kiswahili Fluency attendance_records
## Math 1.00000000 0.386378923 0.11785393 0.098487938
## Kiswahili 0.38637892 1.000000000 0.44155119 -0.002326412
## Fluency 0.11785393 0.441551188 1.00000000 -0.132538341
## attendance_records 0.09848794 -0.002326412 -0.13253834 1.000000000
## lesson_completion_rate 0.12461801 0.045426761 -0.09511312 0.413709571
## lesson_completion_rate
## Math 0.12461801
## Kiswahili 0.04542676
## Fluency -0.09511312
## attendance_records 0.41370957
## lesson_completion_rate 1.00000000
Overall, this correlation matrix provides insights into the relationships between different variables in the dataset. The correlation between lesson completion rate and Math/Kiswahili/Fluency is weak, indicating a limited association between lesson completion rate and academic performance.