library(readxl) # import excel data set
library(tidyverse) # load core packages for data visualisation (dplyr:for data manipulation, tidyr:for data tidying, readr:for data import, purrr:for functional programming, tibble:for tibbles, a modern re-imagining of data frames, stringr:for strings, forcats:for factors)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.4.2 ✔ purrr 1.0.1
## ✔ tibble 3.2.1 ✔ dplyr 1.1.2
## ✔ tidyr 1.3.0 ✔ stringr 1.5.0
## ✔ readr 2.1.4 ✔ forcats 1.0.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
library(moonBook) # For Donuts Chart
library(webr) # For Donuts Chart
library(plyr)
## ------------------------------------------------------------------------------
## You have loaded plyr after dplyr - this is likely to cause problems.
## If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
## library(plyr); library(dplyr)
## ------------------------------------------------------------------------------
##
## Attaching package: 'plyr'
##
## The following objects are masked from 'package:dplyr':
##
## arrange, count, desc, failwith, id, mutate, rename, summarise,
## summarize
##
## The following object is masked from 'package:purrr':
##
## compact
library(plotly)
##
## Attaching package: 'plotly'
##
## The following objects are masked from 'package:plyr':
##
## arrange, mutate, rename, summarise
##
## The following object is masked from 'package:ggplot2':
##
## last_plot
##
## The following object is masked from 'package:stats':
##
## filter
##
## The following object is masked from 'package:graphics':
##
## layout
library(lubridate)
##
## Attaching package: 'lubridate'
##
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
library(ggplot2)
library(kableExtra)
## Warning in !is.null(rmarkdown::metadata$output) && rmarkdown::metadata$output
## %in% : 'length(x) = 2 > 1' in coercion to 'logical(1)'
##
## Attaching package: 'kableExtra'
##
## The following object is masked from 'package:dplyr':
##
## group_rows
library(reshape2)
##
## Attaching package: 'reshape2'
##
## The following object is masked from 'package:tidyr':
##
## smiths
library(rmdformats)
library(igraph)
##
## Attaching package: 'igraph'
##
## The following objects are masked from 'package:lubridate':
##
## %--%, union
##
## The following object is masked from 'package:plotly':
##
## groups
##
## The following objects are masked from 'package:dplyr':
##
## as_data_frame, groups, union
##
## The following objects are masked from 'package:purrr':
##
## compose, simplify
##
## The following object is masked from 'package:tidyr':
##
## crossing
##
## The following object is masked from 'package:tibble':
##
## as_data_frame
##
## The following objects are masked from 'package:stats':
##
## decompose, spectrum
##
## The following object is masked from 'package:base':
##
## union
library(treemap)
library(chatgpt)
library(httr)
##
## Attaching package: 'httr'
##
## The following object is masked from 'package:plotly':
##
## config
library(stringr)
Using an equity lens, assess student performance based on 2022 and 2023 WIDA ACCESS Scores and make recommendations on allocating support.
#Total Negative
total_neg_growth_grade <- Equity_Data_Negative %>%
group_by(Grade, Growth) %>%
summarise(
num_grade = n(), # Calculate the number of applications
percentage_of_grade = num_grade / nrow(Equity_Data) * 100 # Calculate the percentage
)
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
total_neg_growth_grade_level <- Equity_Data_Negative %>%
group_by(Grade_Level, Growth) %>%
summarise(
num_grade = n(), # Calculate the number of applications
percentage_of_grade = num_grade / nrow(Equity_Data) * 100 # Calculate the percentage
)
## `summarise()` has grouped output by 'Grade_Level'. You can override using the
## `.groups` argument.
total_neg_growth_race <- Equity_Data_Negative %>%
group_by(Race, Growth) %>%
summarise(
num_race = n(), # Calculate the number of applications
percentage_of_race = num_race / nrow(Equity_Data) * 100 # Calculate the percentage
)
## `summarise()` has grouped output by 'Race'. You can override using the
## `.groups` argument.
total_neg_growth_program <- Equity_Data_Negative %>%
group_by(Program, Growth) %>%
summarise(
num_program = n(), # Calculate the number of applications
percentage_of_program = num_program / nrow(Equity_Data) * 100 # Calculate the percentage
)
## `summarise()` has grouped output by 'Program'. You can override using the
## `.groups` argument.
total_neg_growth_lang <- Equity_Data_Negative %>%
group_by(First_Lang, Growth) %>%
summarise(
num_lang = n(), # Calculate the number of applications
percentage_of_lang = num_lang / nrow(Equity_Data) * 100 # Calculate the percentage
)
## `summarise()` has grouped output by 'First_Lang'. You can override using the
## `.groups` argument.
total_neg_growth_sn <- Equity_Data_Negative %>%
group_by(SN, Growth) %>%
summarise(
num_sn = n(), # Calculate the number of applications
percentage_of_sn = num_sn / nrow(Equity_Data) * 100 # Calculate the percentage
)
## `summarise()` has grouped output by 'SN'. You can override using the `.groups`
## argument.
# Calculate the average negative score by School
explore_school <- Equity_Data %>%
filter(Growth == "Negative") %>%
group_by(School) %>%
summarise(average_negative = mean(Difference))
explore_school_10 <- explore_school %>%
top_n(10)
## Selecting by average_negative
# Calculate the average negative score by Program
explore_program <- Equity_Data %>%
filter(Growth == "Negative") %>%
group_by(Program) %>%
summarise(average_negative = mean(Difference))
explore_program_10 <- explore_program %>%
top_n(10)
## Selecting by average_negative
# Calculate the average negative score by First_Lang
explore_first_lang <- Equity_Data %>%
filter(Growth == "Negative") %>%
group_by(First_Lang) %>%
summarise(average_negative = mean(Difference))
explore_first_lang_10 <- explore_first_lang %>%
top_n(10)
## Selecting by average_negative
# Calculate the average negative score by Grade
explore_grade <- Equity_Data %>%
filter(Growth == "Negative") %>%
group_by(Grade) %>%
summarise(average_negative = mean(Difference))
explore_grade_10 <- explore_grade %>%
top_n(10)
## Selecting by average_negative
# Calculate the average negative score by Race
explore_race <- Equity_Data %>%
filter(Growth == "Negative") %>%
group_by(Race) %>%
summarise(average_negative = mean(Difference))
Boston Public Schools Equity Data set contains:
Over 1/2 of the students population is in Elementary School
plot_ly(total_grade, labels = ~Grade_Level, values = ~num_grade, type = "pie") %>%
layout(title = "Grade Level Distribution")
Hispanic students account for 68% of the data set.
plot_ly(total_race, labels = ~Race, values = ~num_race, type = "pie") %>%
layout(title = "Race Distribution")
Large majority of data set is students in General Education, 76%. R1 ‘0-90 minutes of service provided in full or partial inclusion setting’ is the largest Special Needs code in the data set.
plot_ly(total_sn, labels = ~SN, values = ~num_sn, type = "pie") %>%
layout(title = "Special Needs Distribution")
Almost 1/2 of the students are in General Education, while the second and third largest Program are ‘SEI - Spanish’ & ‘SEI - Multilingual’.
plot_ly(total_program, labels = ~Program, values = ~num_program, type = "pie") %>%
layout(title = "Program Distribution")
Spanish is the largest First Language in this data set, followed by English and Cape Verdean.
plot_ly(total_lang, labels = ~First_Lang, values = ~num_lang, type = "pie") %>%
layout(title = "First Language Distribution")
Equity means ensuring that every student has access to the necessary resources and support to reach their full potential, regardless of their race, language background, or educational program. It involves recognizing and addressing systemic inequalities to create an inclusive and fair educational environment for all students. The Equity Lens I used was to examine students who had negative growth and compare them general education students vs our special education students, looking for disparities when exploring Program, Race and First Language.
Majority of Growth has been positive.
plot_ly(total_growth_grade, x = ~Grade, y = ~num_grade, color = ~Growth, type = "bar") %>%
layout(
title = "Growth by Grade",
xaxis = list(title = "Grade"),
yaxis = list(title = "Number of Students"),
barmode = "group"
)
Equity Lens focuses on students who had Negative or No growth from SY22 to SY23
plot_ly(total_neg_growth_grade, labels = ~Grade, values = ~num_grade, type = "pie") %>%
layout(title = "Grade Level Distribution of Negative Scores")
plot_ly(total_neg_growth_race, labels = ~Race, values = ~num_race, type = "pie") %>%
layout(title = "Race Distribution of Negative Scores")
plot_ly(total_neg_growth_program, labels = ~Program, values = ~num_program, type = "pie") %>%
layout(title = "Program Distribution of Negative Scores")
plot_ly(total_neg_growth_lang, labels = ~First_Lang, values = ~num_lang, type = "pie") %>%
layout(title = "First Language Distribution of Negative Scores")
## Special Needs
plot_ly(total_neg_growth_sn, labels = ~SN, values = ~num_sn, type = "pie") %>%
layout(title = "Special Needs Distribution of Negative Scores")
# Divide the dataset by General Education and Special Needs
gen_ed <- Equity_Data %>%
filter(Growth == "Negative") %>%
filter(SN == "General Education")
special_needs <- Equity_Data %>%
filter(Growth == "Negative") %>%
filter(SN != "General Education")
# Explore General Education with by School
explore_gen_ed <- gen_ed %>%
group_by(Grade_Level, School) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade_Level'. You can override using the
## `.groups` argument.
explore_gen_ed_10 <- explore_gen_ed %>%
top_n(10)
## Selecting by average_negative
total_gen_ed_school <- gen_ed %>%
group_by(Grade_Level, School) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade_Level'. You can override using the
## `.groups` argument.
data_subset <- subset(total_gen_ed_school, rank(-average_negative, ties.method = "min") <= 10)
# Explore Special Needs
explore_special_needs <- special_needs %>%
group_by(Grade_Level, School) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade_Level'. You can override using the
## `.groups` argument.
explore_special_needs_10 <- explore_special_needs %>%
top_n(10)
## Selecting by average_negative
total_special_needs_school <- special_needs %>%
group_by(Grade_Level, School) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade_Level'. You can override using the
## `.groups` argument.
data_subset_sn <- subset(total_special_needs_school, rank(-average_negative, ties.method = "min") <= 10)
# Divide General Education by Grade_Level
gen_ed_elementary <- gen_ed %>%
filter(Grade_Level == "Elementary") %>%
group_by(Grade) %>%
summarise(average_negative = mean(Difference))
gen_ed_elementary_10 <- gen_ed_elementary %>%
top_n(10)
## Selecting by average_negative
gen_ed_middle <- gen_ed %>%
filter(Grade_Level == "Middle") %>%
group_by(Grade) %>%
summarise(average_negative = mean(Difference))
gen_ed_middle_10 <- gen_ed_middle %>%
top_n(10)
## Selecting by average_negative
gen_ed_high <- gen_ed %>%
filter(Grade_Level == "High") %>%
group_by(Grade) %>%
summarise(average_negative = mean(Difference))
gen_ed_high_10 <- gen_ed_high %>%
top_n(10)
## Selecting by average_negative
# Divide Special Needs by Grade_Level
special_needs_elementary <- special_needs %>%
filter(Grade_Level == "Elementary") %>%
group_by(Grade) %>%
summarise(average_negative = mean(Difference))
special_needs_elementary_10 <- special_needs_elementary %>%
top_n(10)
## Selecting by average_negative
special_needs_elementary_race <- special_needs %>%
filter(Grade_Level == "Elementary") %>%
group_by(Grade, Race) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
special_needs_elementary_program <- special_needs %>%
filter(Grade_Level == "Elementary") %>%
group_by(Grade, Program) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
special_needs_elementary_sn <- special_needs %>%
filter(Grade_Level == "Elementary") %>%
group_by(Grade, SN) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
special_needs_elementary_lang <- special_needs %>%
filter(Grade_Level == "Elementary") %>%
group_by(Grade, First_Lang) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
special_needs_middle <- special_needs %>%
filter(Grade_Level == "Middle") %>%
group_by(Grade) %>%
summarise(average_negative = mean(Difference))
special_needs_middle_10 <- special_needs_middle %>%
top_n(10)
## Selecting by average_negative
special_needs_middle_race <- special_needs %>%
filter(Grade_Level == "Middle") %>%
group_by(Grade, Race) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
special_needs_middle_program <- special_needs %>%
filter(Grade_Level == "Middle") %>%
group_by(Grade, Program) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
special_needs_middle_sn <- special_needs %>%
filter(Grade_Level == "Middle") %>%
group_by(Grade, SN) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
special_needs_middle_lang <- special_needs %>%
filter(Grade_Level == "Middle") %>%
group_by(Grade, First_Lang) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
special_needs_high <- special_needs %>%
filter(Grade_Level == "High") %>%
group_by(Grade) %>%
summarise(average_negative = mean(Difference))
special_needs_high_10 <- special_needs_high %>%
top_n(10)
## Selecting by average_negative
special_needs_high_race <- special_needs %>%
filter(Grade_Level == "High") %>%
group_by(Grade, Race) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
special_needs_high_program <- special_needs %>%
filter(Grade_Level == "High") %>%
group_by(Grade, Program) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
special_needs_high_sn <- special_needs %>%
filter(Grade_Level == "High") %>%
group_by(Grade, SN) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
special_needs_high_lang <- special_needs %>%
filter(Grade_Level == "High") %>%
group_by(Grade, First_Lang) %>%
summarise(average_negative = mean(Difference))
## `summarise()` has grouped output by 'Grade'. You can override using the
## `.groups` argument.
special_needs_high <- special_needs %>%
filter(Grade_Level == "High") %>%
group_by(Grade) %>%
summarise(average_negative = mean(Difference))
ge1 <- plot_ly(data_subset, x = ~Grade_Level, y = ~average_negative, color = ~School, type = "bar") %>%
layout(
title = "Schools With Highest Neagtive Growth",
xaxis = list(title = "Grade Level"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
sn1 <- plot_ly(data_subset_sn, x = ~Grade_Level, y = ~average_negative, color = ~School, type = "bar") %>%
layout(
title = "Schools With Highest Neagtive Growth",
xaxis = list(title = "Grade Level"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
p <- subplot(ge1, sn1, nrows = 1)
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
p
Special Needs
# Grade
special_needs_elementary_plot <- plot_ly(special_needs_elementary, x = ~Grade, y = ~average_negative, color = ~Grade, type = "bar") %>%
layout(
title = "Average Neagtive Growth by Grade",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
# Race
special_needs_elementary_race_plot <- plot_ly(special_needs_elementary_race, x = ~Grade, y = ~average_negative, color = ~Race, type = "bar") %>%
layout(
title = "Average Neagtive Growth by Race",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
# Program
special_needs_elementary_program_plot <- plot_ly(special_needs_elementary_program, x = ~Grade, y = ~average_negative, color = ~Program, type = "bar") %>%
layout(
title = "Average Neagtive Growth by Program",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
# SN
special_needs_elementary_sn_plot <- plot_ly(special_needs_elementary_sn, x = ~Grade, y = ~average_negative, color = ~SN, type = "bar") %>%
layout(
title = "Average Neagtive Growth by SN",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
# First Lang
special_needs_elementary_lang_plot <- plot_ly(special_needs_elementary_lang, x = ~Grade, y = ~average_negative, color = ~First_Lang, type = "bar") %>%
layout(
title = "Average Neagtive Growth by First Language",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
Elem_plots <- subplot(special_needs_elementary_plot, special_needs_elementary_race_plot,special_needs_elementary_program_plot, special_needs_elementary_lang_plot, nrows = 4)
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
Elem_plots
# Grade
special_needs_middle_plot <- plot_ly(special_needs_middle, x = ~Grade, y = ~average_negative, color = ~Grade, type = "bar") %>%
layout(
title = "Average Neagtive Growth by Grade",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
# Race
special_needs_middle_race_plot <- plot_ly(special_needs_middle_race, x = ~Grade, y = ~average_negative, color = ~Race, type = "bar") %>%
layout(
title = "Average Neagtive Growth by Race",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
# Program
special_needs_middle_program_plot <- plot_ly(special_needs_middle_program, x = ~Grade, y = ~average_negative, color = ~Program, type = "bar") %>%
layout(
title = "Average Neagtive Growth by Program",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
# SN
special_needs_middle_sn_plot <- plot_ly(special_needs_middle_sn, x = ~Grade, y = ~average_negative, color = ~SN, type = "bar") %>%
layout(
title = "Average Neagtive Growth by SN",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
# First Lang
special_needs_middle_lang_plot <- plot_ly(special_needs_middle_lang, x = ~Grade, y = ~average_negative, color = ~First_Lang, type = "bar") %>%
layout(
title = "Average Neagtive Growth by First Language",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
Mid_plots <- subplot(special_needs_middle_plot, special_needs_middle_race_plot,special_needs_middle_program_plot, special_needs_middle_lang_plot, nrows = 4)
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
Mid_plots
# Grade
special_needs_high_plot <- plot_ly(special_needs_high, x = ~Grade, y = ~average_negative, color = ~Grade, type = "bar") %>%
layout(
title = "Average Neagtive Growth by Grade",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
# Race
special_needs_high_race_plot <- plot_ly(special_needs_high_race, x = ~Grade, y = ~average_negative, color = ~Race, type = "bar") %>%
layout(
title = "Average Neagtive Growth by Race",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
# Program
special_needs_high_program_plot <- plot_ly(special_needs_high_program, x = ~Grade, y = ~average_negative, color = ~Program, type = "bar") %>%
layout(
title = "Average Neagtive Growth by Program",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
# SN
special_needs_high_sn_plot <- plot_ly(special_needs_high_sn, x = ~Grade, y = ~average_negative, color = ~SN, type = "bar") %>%
layout(
title = "Average Neagtive Growth by SN",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
# First Lang
special_needs_high_lang_plot <- plot_ly(special_needs_high_lang, x = ~Grade, y = ~average_negative, color = ~First_Lang, type = "bar") %>%
layout(
title = "Average Neagtive Growth by First Language",
xaxis = list(title = "Grade"),
yaxis = list(title = "Average Growth"),
barmode = "group"
)
High_plots <- subplot(special_needs_high_plot, special_needs_high_race_plot,special_needs_high_program_plot, special_needs_high_lang_plot, nrows = 4)
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
## Warning in RColorBrewer::brewer.pal(N, "Set2"): n too large, allowed maximum for palette Set2 is 8
## Returning the palette you asked for with that many colors
High_plots
Increase targeted language support for students in grades 1, 6 & 9, as they demonstrated lower average scores compared to other grades.
Provide additional resources and interventions for students in the BLM, BLC, and BLH programs, as they showed lower average scores compared to students in other programs.
Develop individualized support plans for students with disabilities to ensure their specific language needs are met.