NC High School Performance Analysis

ECI 586 Final Project

Author

Bouchra Elgaou

Published

December 4, 2025

STEP 0: SETUP

  1. Prepare

Introduction

The “Career and College Readiness” (CCC) indicator serves as a critical metric for evaluating the effectiveness of North Carolina’s public high schools. This measure assesses whether students have attained the necessary skills for post-secondary success through benchmarks such as the ACT, ACT WorkKeys, or proficiency in advanced mathematics courses.

While statewide averages provide a general overview of performance, they often conceal underlying disparities between student populations. This project analyzes accountability data from the 2023-2024 academic year to investigate these potential inequities. By disaggregating performance data by race, gender, and socioeconomic status, this report seeks to identify specific achievement gaps that require targeted educational interventions.

Research Question

How does performance on the Career and College Readiness indicator vary across distinct demographic subgroups in North Carolina?

This analysis specifically investigates:

1- The magnitude of the performance gap between historically marginalized subgroups and their peers.

2- The impact of economic disadvantage on readiness outcomes compared to other demographic factors.

Data Source

The dataset for this analysis, rcd_161.xlsx, was obtained from the North Carolina Department of Public Instruction (NCDPI) Accountability Data Sets.

  • Scope: The data represents school-level performance for the 2023-24 school year.

Key Variables:

  • agency_code: The unique identifier for each school unit.

  • subgroup: The demographic category (e.g., Black, Hispanic, Economically Disadvantaged).

  • ccc_pct: The percentage of students within a subgroup designated as “College and Career Ready.”

Methodological Note: To protect student privacy, NCDPI masks data for small subgroups (e.g., reporting “<5%”). For the purpose of this statistical analysis, these masked values were converted to numeric approximations.

  1. Wrangle

In this section, I load the rcd_161.xlsx file and clean the variable names.

# STEP 1: LOAD AND INSPECT

# Load the Excel file

# NOTE: Ensure the file is named exactly 'rcd_161.xlsx' in your Files pane

raw_data <- read_excel("rcd_161.xlsx") |>

clean_names() # This makes all column names lowercase and replaces spaces with underscores

# DIAGNOSTIC STEP: If the code crashes at the "select" step below, look at the table printed here to find the correct column names for your specific file.

head(raw_data)
# A tibble: 6 × 6
   year agency_code status subgroup ccc_count ccc_pct
  <dbl> <chr>       <chr>  <chr>        <dbl>   <dbl>
1  2009 010303      COMP1Y AM7             NA    NA  
2  2009 010303      COMP1Y AS7             NA    NA  
3  2009 010303      COMP1Y ALL              7    43.8
4  2009 010303      COMP1Y BL7             NA    50  
5  2009 010303      COMP1Y EDS             NA    60  
6  2009 010303      COMP1Y FEM             NA    36.4
# STEP 2: CLEANING

# Helper function to fix NC DPI "Masked" values
fix_dpi_numbers <- function(x) {
  x |>
    as.character() |>              
    str_replace_all("<5%", "2.5") |>   
    str_replace_all(">95%", "97.5") |> 
    str_remove_all("%") |>             
    as.numeric()                       
}

clean_data <- raw_data |>
  # 1. Select relevant variables
  select(
    year,
    school_code = agency_code,
    subgroup_code = subgroup,
    performance_score = ccc_pct 
  ) |>
  
  # 2. Clean numbers
  mutate(
    performance_score = fix_dpi_numbers(performance_score)
  ) |>
  
  # 3. FIX THE LABELS (Rename codes to real names)
  mutate(demographic = case_match(subgroup_code,
    "ALL" ~ "All Students",
    "FEM" ~ "Female",
    "MALE" ~ "Male",
    "AM7" ~ "American Indian",
    "AS7" ~ "Asian",
    "BL7" ~ "Black",
    "HI7" ~ "Hispanic",
    "MU7" ~ "Multiracial",
    "WH7" ~ "White",
    "EDS" ~ "Economically Disadvantaged",
    "SWD" ~ "Students w/ Disabilities",
    "ELS" ~ "English Learners",
    .default = subgroup_code 
  )) |>

  # 4. Filter out empty scores
  filter(!is.na(performance_score))

# Preview clean data
head(clean_data) |> kable()
year school_code subgroup_code performance_score demographic
2009 010303 ALL 43.75 All Students
2009 010303 BL7 50.00 Black
2009 010303 EDS 60.00 Economically Disadvantaged
2009 010303 FEM 36.36 Female
2009 010303 MALE 60.00 Male
2009 010303 WH7 41.66 White

Wrangle Summary:

To prepare the data for analysis, I performed three necessary cleaning steps: 1. Renaming Variables: The original column headers (e.g., WH7, BL7) were cryptic codes. I renamed these to human-readable labels (e.g., “White”, “Black”) to ensure the final visualizations were interpretable by the audience. 2. Handling Masked Data: NCDPI masks sensitive data to protect student privacy (e.g., reporting scores as “<5%”). I converted these character strings into numeric approximations (e.g., 2.5%). This transformation was strictly necessary; without it, R cannot calculate means or generate plots. 3. Filtering: I removed rows with missing data (NA) to prevent calculation errors in the descriptive statistics.

  1. Analyze

3.1 Descriptive Statistics

First, I examine the summary statistics to understand the distribution of school performance and teacher experience across the state.

summary_stats <- clean_data |>
  group_by(demographic) |>
  summarize(
    avg_score = mean(performance_score, na.rm = TRUE),
    count = n()
  )

kable(summary_stats, caption = "Average Career Readiness by Subgroup")
Average Career Readiness by Subgroup
demographic avg_score count
All Students 44.54580 5960
American Indian 63.98781 656
Asian 73.93561 1311
Black 34.17061 4091
Economically Disadvantaged 29.94031 5015
English Learners 70.93068 980
Female 36.79245 5804
Hispanic 55.46169 1875
Male 33.37666 5668
Multiracial 66.45962 1327
PI7 33.33333 1
Students w/ Disabilities 48.71240 1415
White 40.47676 5400

3.2 Visualizing the Achievement Gap

I will visualize the difference in performance scores between White, Black, and Hispanic subgroups.

# 3.2 VISUALIZATION
# Filter for major groups to compare
plot_data <- clean_data |>
  filter(demographic %in% c("White", "Black", "Hispanic", "Asian", "Economically Disadvantaged"))

ggplot(plot_data, aes(x = reorder(demographic, performance_score), y = performance_score, fill = demographic)) +
  geom_boxplot(alpha = 0.7) +
  coord_flip() + 
  scale_fill_brewer(palette = "Set2") +
  labs(
    title = "Career & College Readiness Gaps",
    subtitle = "Comparison of major student subgroups",
    x = "Student Subgroup",
    y = "Readiness Percentage (%)"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

  1. Communicate

Key Findings

Based on the analysis of the College & Career Readiness dataset:

  • Achievement Gaps: The data reveals significant disparities in readiness. Asian students consistently show the highest readiness percentages (avg ~73.9%), followed by White students (avg ~40.5%).

  • Racial Disparities: There is a concerning gap between White students and their Black (avg ~34.2%) and Hispanic peers.

  • Economic Impact: Students classified as Economically Disadvantaged (EDS) show the lowest average readiness scores (~29.9%). This suggests that poverty is a stronger predictor of low career readiness than race alone.

Recommendations

  • Targeted Support: Schools need to implement specific support structures (tutoring, career counseling) for Economically Disadvantaged students, as they face the largest readiness gap.

  • Equity Audits: Districts should conduct equity audits to identify why Black and Hispanic students are accessing career readiness pathways at lower rates than their White and Asian peers.

Limitations

  • Data Masking: Privacy masking (values like <5%) required estimation, which slightly reduces the precision of the averages.

  • Limited Scope: This dataset only measures readiness scores (ccc_pct) and does not explain why the gaps exist (e.g., it lacks data on school funding or teacher quality).