Introduction

This analysis examines preventable death rates across Texas largest county jails (Bexar, Dalls, Harris, Travis) from 2015-2025

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.0     ✔ readr     2.1.6
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ ggplot2   4.0.2     ✔ tibble    3.3.1
## ✔ lubridate 1.9.5     ✔ tidyr     1.3.2
## ✔ purrr     1.2.1     
## ── 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
library(readxl)
library(psych)
## 
## Attaching package: 'psych'
## 
## The following objects are masked from 'package:ggplot2':
## 
##     %+%, alpha
countyjail_data <- read_excel(
  "~/Desktop/capstone bexar county jail/excel work sheets and r code/TXJail_DeathsCounties2015_2025 Capstone analysis.xlsx",
  sheet = "All_Data")

Data Import

head(countyjail_data)
## # A tibble: 6 × 35
##   record_id  agency_county death_year death_date preventable_death
##   <chr>      <chr>              <dbl> <chr>                  <dbl>
## 1 23-1091-CJ BEXAR               2023 2023-08-15                 0
## 2 23-1219-CJ TRAVIS              2023 2023-09-13                 0
## 3 23-1079-CJ BEXAR               2023 2023-08-06                 0
## 4 23-1103-CJ DALLAS              2023 2023-08-07                 0
## 5 23-1783-CJ BEXAR               2023 2023-08-27                 0
## 6 23-1593-CJ BEXAR               2023 2023-09-29                 0
## # ℹ 30 more variables: age_at_time_of_death <dbl>, age_group <chr>, sex <chr>,
## #   race <chr>, sex_male <dbl>, race_white <dbl>, race_black <dbl>,
## #   race_hispanic <dbl>, age_26_35 <dbl>, age_36_45 <dbl>, age_46_55 <dbl>,
## #   manner_of_death <chr>, specific_type_of_custody_facility <chr>,
## #   housing_type <chr>, days_from_custody_to_death <dbl>,
## #   timing_category <chr>, exhibit_any_mental_health_problems <chr>,
## #   make_suicidal_statements <chr>, housing_single_cell <dbl>, …
summary(countyjail_data)
##   record_id         agency_county        death_year    death_date       
##  Length:390         Length:390         Min.   :2015   Length:390        
##  Class :character   Class :character   1st Qu.:2018   Class :character  
##  Mode  :character   Mode  :character   Median :2021   Mode  :character  
##                                        Mean   :2020                     
##                                        3rd Qu.:2023                     
##                                        Max.   :2025                     
##  preventable_death age_at_time_of_death  age_group             sex           
##  Min.   :0.0000    Min.   :18.00        Length:390         Length:390        
##  1st Qu.:0.0000    1st Qu.:34.25        Class :character   Class :character  
##  Median :0.0000    Median :47.00        Mode  :character   Mode  :character  
##  Mean   :0.1641    Mean   :46.92                                             
##  3rd Qu.:0.0000    3rd Qu.:58.00                                             
##  Max.   :1.0000    Max.   :89.00                                             
##      race              sex_male        race_white       race_black    
##  Length:390         Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
##  Class :character   1st Qu.:1.0000   1st Qu.:0.0000   1st Qu.:0.0000  
##  Mode  :character   Median :1.0000   Median :0.0000   Median :0.0000  
##                     Mean   :0.8872   Mean   :0.3385   Mean   :0.3974  
##                     3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:1.0000  
##                     Max.   :1.0000   Max.   :1.0000   Max.   :1.0000  
##  race_hispanic      age_26_35        age_36_45        age_46_55     
##  Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
##  1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000  
##  Median :0.0000   Median :0.0000   Median :0.0000   Median :0.0000  
##  Mean   :0.2179   Mean   :0.1974   Mean   :0.1846   Mean   :0.2436  
##  3rd Qu.:0.0000   3rd Qu.:0.0000   3rd Qu.:0.0000   3rd Qu.:0.0000  
##  Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.0000  
##  manner_of_death    specific_type_of_custody_facility housing_type      
##  Length:390         Length:390                        Length:390        
##  Class :character   Class :character                  Class :character  
##  Mode  :character   Mode  :character                  Mode  :character  
##                                                                         
##                                                                         
##                                                                         
##  days_from_custody_to_death timing_category   
##  Min.   :   0.0             Length:390        
##  1st Qu.:   5.0             Class :character  
##  Median :  36.0             Mode  :character  
##  Mean   : 120.3                               
##  3rd Qu.: 155.8                               
##  Max.   :1277.0                               
##  exhibit_any_mental_health_problems make_suicidal_statements
##  Length:390                         Length:390              
##  Class :character                   Class :character        
##  Mode  :character                   Mode  :character        
##                                                             
##                                                             
##                                                             
##  housing_single_cell housing_multiple   mh_unknown         mh_yes      
##  Min.   :0.0000      Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
##  1st Qu.:0.0000      1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000  
##  Median :0.0000      Median :0.0000   Median :0.0000   Median :0.0000  
##  Mean   :0.2538      Mean   :0.3821   Mean   :0.4333   Mean   :0.1795  
##  3rd Qu.:1.0000      3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:0.0000  
##  Max.   :1.0000      Max.   :1.0000   Max.   :1.0000   Max.   :1.0000  
##   suicidal_yes     county_dallas    county_harris    county_travis   
##  Min.   :0.00000   Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
##  1st Qu.:0.00000   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000  
##  Median :0.00000   Median :0.0000   Median :0.0000   Median :0.0000  
##  Mean   :0.07179   Mean   :0.1974   Mean   :0.3872   Mean   :0.1103  
##  3rd Qu.:0.00000   3rd Qu.:0.0000   3rd Qu.:1.0000   3rd Qu.:0.0000  
##  Max.   :1.00000   Max.   :1.0000   Max.   :1.0000   Max.   :1.0000  
##  death_from_pre_existing_medical_condition type_of_offense   
##  Length:390                                Length:390        
##  Class :character                          Class :character  
##  Mode  :character                          Mode  :character  
##                                                              
##                                                              
##                                                              
##   offense_1         were_the_charges  
##  Length:390         Length:390        
##  Class :character   Class :character  
##  Mode  :character   Mode  :character  
##                                       
##                                       
## 

#Convert variables to factors

# Convert categorical variables to factors
countyjail_data <- countyjail_data %>%
  mutate(
    # Main categorical variables
    agency_county = factor(agency_county),
    sex = factor(sex),
    race = factor(race),
    age_group = factor(age_group, levels = c("18-25", "26-35", "36-45", "46-55", "56-65", "66+")),
    manner_of_death = factor(manner_of_death),
    housing_type = factor(housing_type),
    timing_category = factor(timing_category),
    exhibit_any_mental_health_problems = factor(exhibit_any_mental_health_problems),
    make_suicidal_statements = factor(make_suicidal_statements),
    death_from_pre_existing_medical_condition = factor(death_from_pre_existing_medical_condition),
    type_of_offense = factor(type_of_offense),
    were_the_charges = factor(were_the_charges),
    
    # Convert death_date to actual date format
    death_date = as.Date(death_date)
  )

# Verify the changes
str(countyjail_data)
## tibble [390 × 35] (S3: tbl_df/tbl/data.frame)
##  $ record_id                                : chr [1:390] "23-1091-CJ" "23-1219-CJ" "23-1079-CJ" "23-1103-CJ" ...
##  $ agency_county                            : Factor w/ 4 levels "BEXAR","DALLAS",..: 1 4 1 2 1 1 1 1 1 2 ...
##  $ death_year                               : num [1:390] 2023 2023 2023 2023 2023 ...
##  $ death_date                               : Date[1:390], format: "2023-08-15" "2023-09-13" ...
##  $ preventable_death                        : num [1:390] 0 0 0 0 0 0 1 0 1 0 ...
##  $ age_at_time_of_death                     : num [1:390] 67 21 54 66 37 33 31 44 22 82 ...
##  $ age_group                                : Factor w/ 6 levels "18-25","26-35",..: 6 1 4 6 3 2 2 3 1 6 ...
##  $ sex                                      : Factor w/ 2 levels "FEMALE","MALE": 2 2 2 2 2 2 2 2 2 2 ...
##  $ race                                     : Factor w/ 4 levels "BLACK","HISPANIC",..: 2 1 4 1 2 4 3 2 1 4 ...
##  $ sex_male                                 : num [1:390] 1 1 1 1 1 1 1 1 1 1 ...
##  $ race_white                               : num [1:390] 0 0 1 0 0 1 0 0 0 1 ...
##  $ race_black                               : num [1:390] 0 1 0 1 0 0 0 0 1 0 ...
##  $ race_hispanic                            : num [1:390] 1 0 0 0 1 0 0 1 0 0 ...
##  $ age_26_35                                : num [1:390] 0 0 0 0 0 1 1 0 0 0 ...
##  $ age_36_45                                : num [1:390] 0 0 0 0 1 0 0 1 0 0 ...
##  $ age_46_55                                : num [1:390] 0 0 1 0 0 0 0 0 0 0 ...
##  $ manner_of_death                          : Factor w/ 6 levels "ACCIDENTAL","ALCOHOL/DRUG INTOXICATION",..: 4 5 4 4 3 4 6 3 6 4 ...
##  $ specific_type_of_custody_facility        : chr [1:390] "HOSPITAL/INFIRMARY" "HOSPITAL/INFIRMARY" "HOSPITAL/INFIRMARY" "HOSPITAL/INFIRMARY" ...
##  $ housing_type                             : Factor w/ 7 levels "Day Room/Recreation",..: 4 4 4 4 6 5 7 4 4 4 ...
##  $ days_from_custody_to_death               : num [1:390] 274 10 29 47 0 4 6 24 1 261 ...
##  $ timing_category                          : Factor w/ 6 levels "<24 hours",">90 days",..: 2 6 4 4 1 5 5 4 3 2 ...
##  $ exhibit_any_mental_health_problems       : Factor w/ 3 levels "NO","UNKNOWN",..: 1 3 1 2 2 2 1 2 2 2 ...
##  $ make_suicidal_statements                 : Factor w/ 3 levels "NO","UNKNOWN",..: 1 3 1 2 1 1 1 2 2 2 ...
##  $ housing_single_cell                      : num [1:390] 0 0 0 0 0 0 1 0 0 0 ...
##  $ housing_multiple                         : num [1:390] 0 0 0 0 0 1 0 0 0 0 ...
##  $ mh_unknown                               : num [1:390] 0 0 0 1 1 1 0 1 1 1 ...
##  $ mh_yes                                   : num [1:390] 0 1 0 0 0 0 0 0 0 0 ...
##  $ suicidal_yes                             : num [1:390] 0 1 0 0 0 0 0 0 0 0 ...
##  $ county_dallas                            : num [1:390] 0 0 0 1 0 0 0 0 0 1 ...
##  $ county_harris                            : num [1:390] 0 0 0 0 0 0 0 0 0 0 ...
##  $ county_travis                            : num [1:390] 0 1 0 0 0 0 0 0 0 0 ...
##  $ death_from_pre_existing_medical_condition: Factor w/ 4 levels "DEVELOPED CONDITION AFTER ADMISSION",..: 4 3 4 4 3 3 2 2 2 3 ...
##  $ type_of_offense                          : Factor w/ 12 levels "ALCOHOL / DRUG OFFENSE",..: 10 5 8 10 1 10 12 10 10 10 ...
##  $ offense_1                                : chr [1:390] "CONTINUOUS SEX ABUSE" "BURGLARY OF VEHICLE" "CRUELTY-NONLIESTOCK" "ASSAULT CAUSES BODILY INJURY FAMILY VIOLENCE" ...
##  $ were_the_charges                         : Factor w/ 4 levels "CONVICTED","FILED",..: 2 2 2 4 3 2 2 2 2 2 ...
# Verify the changes
str(countyjail_data)
## tibble [390 × 35] (S3: tbl_df/tbl/data.frame)
##  $ record_id                                : chr [1:390] "23-1091-CJ" "23-1219-CJ" "23-1079-CJ" "23-1103-CJ" ...
##  $ agency_county                            : Factor w/ 4 levels "BEXAR","DALLAS",..: 1 4 1 2 1 1 1 1 1 2 ...
##  $ death_year                               : num [1:390] 2023 2023 2023 2023 2023 ...
##  $ death_date                               : Date[1:390], format: "2023-08-15" "2023-09-13" ...
##  $ preventable_death                        : num [1:390] 0 0 0 0 0 0 1 0 1 0 ...
##  $ age_at_time_of_death                     : num [1:390] 67 21 54 66 37 33 31 44 22 82 ...
##  $ age_group                                : Factor w/ 6 levels "18-25","26-35",..: 6 1 4 6 3 2 2 3 1 6 ...
##  $ sex                                      : Factor w/ 2 levels "FEMALE","MALE": 2 2 2 2 2 2 2 2 2 2 ...
##  $ race                                     : Factor w/ 4 levels "BLACK","HISPANIC",..: 2 1 4 1 2 4 3 2 1 4 ...
##  $ sex_male                                 : num [1:390] 1 1 1 1 1 1 1 1 1 1 ...
##  $ race_white                               : num [1:390] 0 0 1 0 0 1 0 0 0 1 ...
##  $ race_black                               : num [1:390] 0 1 0 1 0 0 0 0 1 0 ...
##  $ race_hispanic                            : num [1:390] 1 0 0 0 1 0 0 1 0 0 ...
##  $ age_26_35                                : num [1:390] 0 0 0 0 0 1 1 0 0 0 ...
##  $ age_36_45                                : num [1:390] 0 0 0 0 1 0 0 1 0 0 ...
##  $ age_46_55                                : num [1:390] 0 0 1 0 0 0 0 0 0 0 ...
##  $ manner_of_death                          : Factor w/ 6 levels "ACCIDENTAL","ALCOHOL/DRUG INTOXICATION",..: 4 5 4 4 3 4 6 3 6 4 ...
##  $ specific_type_of_custody_facility        : chr [1:390] "HOSPITAL/INFIRMARY" "HOSPITAL/INFIRMARY" "HOSPITAL/INFIRMARY" "HOSPITAL/INFIRMARY" ...
##  $ housing_type                             : Factor w/ 7 levels "Day Room/Recreation",..: 4 4 4 4 6 5 7 4 4 4 ...
##  $ days_from_custody_to_death               : num [1:390] 274 10 29 47 0 4 6 24 1 261 ...
##  $ timing_category                          : Factor w/ 6 levels "<24 hours",">90 days",..: 2 6 4 4 1 5 5 4 3 2 ...
##  $ exhibit_any_mental_health_problems       : Factor w/ 3 levels "NO","UNKNOWN",..: 1 3 1 2 2 2 1 2 2 2 ...
##  $ make_suicidal_statements                 : Factor w/ 3 levels "NO","UNKNOWN",..: 1 3 1 2 1 1 1 2 2 2 ...
##  $ housing_single_cell                      : num [1:390] 0 0 0 0 0 0 1 0 0 0 ...
##  $ housing_multiple                         : num [1:390] 0 0 0 0 0 1 0 0 0 0 ...
##  $ mh_unknown                               : num [1:390] 0 0 0 1 1 1 0 1 1 1 ...
##  $ mh_yes                                   : num [1:390] 0 1 0 0 0 0 0 0 0 0 ...
##  $ suicidal_yes                             : num [1:390] 0 1 0 0 0 0 0 0 0 0 ...
##  $ county_dallas                            : num [1:390] 0 0 0 1 0 0 0 0 0 1 ...
##  $ county_harris                            : num [1:390] 0 0 0 0 0 0 0 0 0 0 ...
##  $ county_travis                            : num [1:390] 0 1 0 0 0 0 0 0 0 0 ...
##  $ death_from_pre_existing_medical_condition: Factor w/ 4 levels "DEVELOPED CONDITION AFTER ADMISSION",..: 4 3 4 4 3 3 2 2 2 3 ...
##  $ type_of_offense                          : Factor w/ 12 levels "ALCOHOL / DRUG OFFENSE",..: 10 5 8 10 1 10 12 10 10 10 ...
##  $ offense_1                                : chr [1:390] "CONTINUOUS SEX ABUSE" "BURGLARY OF VEHICLE" "CRUELTY-NONLIESTOCK" "ASSAULT CAUSES BODILY INJURY FAMILY VIOLENCE" ...
##  $ were_the_charges                         : Factor w/ 4 levels "CONVICTED","FILED",..: 2 2 2 4 3 2 2 2 2 2 ...
# Load packages if not already loaded
library(tidyverse)
library(psych)

##Descriptive Statistics

# Overall sample size
nrow(countyjail_data)
## [1] 390
# Preventable death frequency and percentage
table(countyjail_data$preventable_death)
## 
##   0   1 
## 326  64
prop.table(table(countyjail_data$preventable_death)) * 100
## 
##        0        1 
## 83.58974 16.41026
# Age statistics
summary(countyjail_data$age_at_time_of_death)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   18.00   34.25   47.00   46.92   58.00   89.00
sd(countyjail_data$age_at_time_of_death, na.rm = TRUE)
## [1] 14.88874
# Demographics
table(countyjail_data$sex)
## 
## FEMALE   MALE 
##     44    346
prop.table(table(countyjail_data$sex)) * 100
## 
##   FEMALE     MALE 
## 11.28205 88.71795
table(countyjail_data$race)
## 
##    BLACK HISPANIC    OTHER    WHITE 
##      155       85       18      132
prop.table(table(countyjail_data$race)) * 100
## 
##     BLACK  HISPANIC     OTHER     WHITE 
## 39.743590 21.794872  4.615385 33.846154
# Mental health problems
table(countyjail_data$exhibit_any_mental_health_problems)
## 
##      NO UNKNOWN     YES 
##      86     169      70
prop.table(table(countyjail_data$exhibit_any_mental_health_problems)) * 100
## 
##       NO  UNKNOWN      YES 
## 26.46154 52.00000 21.53846
# Suicidal statements
table(countyjail_data$make_suicidal_statements)
## 
##      NO UNKNOWN     YES 
##     134     163      28
prop.table(table(countyjail_data$make_suicidal_statements)) * 100
## 
##        NO   UNKNOWN       YES 
## 41.230769 50.153846  8.615385
# Days in custody
summary(countyjail_data$days_from_custody_to_death)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##     0.0     5.0    36.0   120.3   155.8  1277.0
sd(countyjail_data$days_from_custody_to_death, na.rm = TRUE)
## [1] 198.9063

##Four County Comparison # Preventable death rate by county

county_summary <- countyjail_data %>%
  group_by(agency_county) %>%
  summarise(
    total_deaths = n(),
    preventable_deaths = sum(preventable_death == 1),
    preventable_rate = mean(preventable_death) * 100,
    .groups = 'drop'
  ) %>%
  arrange(desc(preventable_rate))

print(county_summary)
## # A tibble: 4 × 4
##   agency_county total_deaths preventable_deaths preventable_rate
##   <fct>                <int>              <int>            <dbl>
## 1 TRAVIS                  43                 12            27.9 
## 2 BEXAR                  119                 33            27.7 
## 3 HARRIS                 151                 13             8.61
## 4 DALLAS                  77                  6             7.79

#Four County Comparison

four_county_summary <- countyjail_data %>%
  filter(agency_county %in% c("BEXAR", "DALLAS", "HARRIS", "TRAVIS")) %>%
  group_by(agency_county) %>%
  summarise(
    total_deaths = n(),
    preventable_deaths = sum(preventable_death == 1),
    preventable_rate = mean(preventable_death) * 100,
    .groups = 'drop'
  )

print(four_county_summary)
## # A tibble: 4 × 4
##   agency_county total_deaths preventable_deaths preventable_rate
##   <fct>                <int>              <int>            <dbl>
## 1 BEXAR                  119                 33            27.7 
## 2 DALLAS                  77                  6             7.79
## 3 HARRIS                 151                 13             8.61
## 4 TRAVIS                  43                 12            27.9
# Comprehensive county comparison
county_characteristics <- countyjail_data %>%
  filter(agency_county %in% c("BEXAR", "DALLAS", "HARRIS", "TRAVIS")) %>%
  group_by(agency_county) %>%
  summarise(
    n = n(),
    preventable_rate = mean(preventable_death) * 100,
    
    # Demographics
    avg_age = mean(age_at_time_of_death, na.rm = TRUE),
    male_pct = mean(sex_male) * 100,
    white_pct = mean(race_white) * 100,
    black_pct = mean(race_black) * 100,
    hispanic_pct = mean(race_hispanic) * 100,
    
    # Mental health
    mh_yes_pct = mean(mh_yes) * 100,
    mh_unknown_pct = mean(mh_unknown) * 100,
    suicidal_pct = mean(suicidal_yes) * 100,
    
    # Custody characteristics
    avg_days_in_custody = mean(days_from_custody_to_death, na.rm = TRUE),
    single_cell_pct = mean(housing_single_cell) * 100,
    
    .groups = 'drop'
  )

print(county_characteristics)
## # A tibble: 4 × 13
##   agency_county     n preventable_rate avg_age male_pct white_pct black_pct
##   <fct>         <int>            <dbl>   <dbl>    <dbl>     <dbl>     <dbl>
## 1 BEXAR           119            27.7     45.7     85.7      36.1      22.7
## 2 DALLAS           77             7.79    49.5     90.9      31.2      46.8
## 3 HARRIS          151             8.61    48.2     91.4      30.5      54.3
## 4 TRAVIS           43            27.9     41.5     83.7      44.2      23.3
## # ℹ 6 more variables: hispanic_pct <dbl>, mh_yes_pct <dbl>,
## #   mh_unknown_pct <dbl>, suicidal_pct <dbl>, avg_days_in_custody <dbl>,
## #   single_cell_pct <dbl>
# Compare characteristics by preventable death status
preventable_comparison <- countyjail_data %>%
  group_by(preventable_death) %>%
  summarise(
    n = n(),
    avg_age = mean(age_at_time_of_death, na.rm = TRUE),
    male_pct = mean(sex_male) * 100,
    white_pct = mean(race_white) * 100,
    black_pct = mean(race_black) * 100,
    hispanic_pct = mean(race_hispanic) * 100,
    mh_yes_pct = mean(mh_yes) * 100,
    suicidal_pct = mean(suicidal_yes) * 100,
    avg_days_custody = mean(days_from_custody_to_death, na.rm = TRUE),
    .groups = 'drop'
  )

print(preventable_comparison)
## # A tibble: 2 × 10
##   preventable_death     n avg_age male_pct white_pct black_pct hispanic_pct
##               <dbl> <int>   <dbl>    <dbl>     <dbl>     <dbl>        <dbl>
## 1                 0   326    48.9     89.3      30.7      43.9         20.2
## 2                 1    64    36.6     85.9      50        18.8         29.7
## # ℹ 3 more variables: mh_yes_pct <dbl>, suicidal_pct <dbl>,
## #   avg_days_custody <dbl>
# Table 1: Sample Characteristics
table1 <- countyjail_data %>%
  summarise(
    `Total Deaths` = n(),
    `Preventable Deaths (n)` = sum(preventable_death == 1),
    `Preventable Deaths (%)` = mean(preventable_death) * 100,
    `Mean Age (SD)` = paste0(round(mean(age_at_time_of_death), 1), " (", 
                            round(sd(age_at_time_of_death), 1), ")"),
    `Male (%)` = mean(sex_male) * 100,
    `Mental Health Issues (%)` = mean(mh_yes) * 100,
    `Mean Days in Custody (SD)` = paste0(round(mean(days_from_custody_to_death), 1), " (", 
                                        round(sd(days_from_custody_to_death), 1), ")")
  )

print(table1)
## # A tibble: 1 × 7
##   `Total Deaths` `Preventable Deaths (n)` Preventable Deaths (…¹ `Mean Age (SD)`
##            <int>                    <int>                  <dbl> <chr>          
## 1            390                       64                   16.4 46.9 (14.9)    
## # ℹ abbreviated name: ¹​`Preventable Deaths (%)`
## # ℹ 3 more variables: `Male (%)` <dbl>, `Mental Health Issues (%)` <dbl>,
## #   `Mean Days in Custody (SD)` <chr>

##Visualizations

write.csv(county_summary, "county_preventable_rates.csv", row.names = FALSE)
write.csv(county_characteristics, "county_characteristics.csv", row.names = FALSE)
# Bar chart: Preventable death rates by county
ggplot(four_county_summary, aes(x = reorder(agency_county, -preventable_rate), 
                                 y = preventable_rate)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  geom_text(aes(label = paste0(round(preventable_rate, 1), "%")), 
            vjust = -0.5, size = 4) +
  labs(title = "Preventable Death Rates in Texas County Jails (2015-2025)",
       subtitle = "Bexar, Dallas, Harris, and Travis Counties",
       x = "County",
       y = "Preventable Death Rate (%)") +
  theme_minimal() +
  theme(text = element_text(size = 12))

# Age distribution by preventable death
ggplot(countyjail_data, aes(x = factor(preventable_death), 
                             y = age_at_time_of_death)) +
  geom_boxplot(fill = "lightblue") +
  labs(title = "Age Distribution by Preventable Death Status",
       x = "Preventable Death (0 = No, 1 = Yes)",
       y = "Age at Death") +
  theme_minimal()

#Bivarte Analysis : Unadjusted Associations ##Age and Preventable Death (t-test)

cat("T-test: Age by Preventable Death\n")
## T-test: Age by Preventable Death
t_test_age <- t.test(age_at_time_of_death ~ preventable_death, 
                     data = countyjail_data)
print(t_test_age)
## 
##  Welch Two Sample t-test
## 
## data:  age_at_time_of_death by preventable_death
## t = 8.0366, df = 120.46, p-value = 7.136e-13
## alternative hypothesis: true difference in means between group 0 and group 1 is not equal to 0
## 95 percent confidence interval:
##   9.266044 15.323872
## sample estimates:
## mean in group 0 mean in group 1 
##        48.93558        36.64062
# Mean ages
age_summary <- countyjail_data %>%
  group_by(preventable_death) %>%
  summarise(
    n = n(),
    mean_age = mean(age_at_time_of_death, na.rm = TRUE),
    sd_age = sd(age_at_time_of_death, na.rm = TRUE)
  )
knitr::kable(age_summary, digits = 2, 
      caption = "Age by Preventable Death Status")
Age by Preventable Death Status
preventable_death n mean_age sd_age
0 326 48.94 14.82
1 64 36.64 10.33
### Days in Custody and Preventable Death (t-test)
cat("\n\nT-test: Days in Custody by Preventable Death\n")
## 
## 
## T-test: Days in Custody by Preventable Death
t_test_days <- t.test(days_from_custody_to_death ~ preventable_death, 
                      data = countyjail_data)
print(t_test_days)
## 
##  Welch Two Sample t-test
## 
## data:  days_from_custody_to_death by preventable_death
## t = 0.68259, df = 80.006, p-value = 0.4968
## alternative hypothesis: true difference in means between group 0 and group 1 is not equal to 0
## 95 percent confidence interval:
##  -40.96204  83.73179
## sample estimates:
## mean in group 0 mean in group 1 
##        123.8067        102.4219
### Mental Health and Preventable Death (Chi-square)
cat("\n\nChi-square: Mental Health by Preventable Death\n")
## 
## 
## Chi-square: Mental Health by Preventable Death
mh_table <- table(countyjail_data$exhibit_any_mental_health_problems, 
                  countyjail_data$preventable_death)
print(mh_table)
##          
##             0   1
##   NO       67  19
##   UNKNOWN 150  19
##   YES      57  13
chisq_mh <- chisq.test(mh_table)
print(chisq_mh)
## 
##  Pearson's Chi-squared test
## 
## data:  mh_table
## X-squared = 5.631, df = 2, p-value = 0.05987
# Percentages
prop.table(mh_table, 1) * 100
##          
##                  0        1
##   NO      77.90698 22.09302
##   UNKNOWN 88.75740 11.24260
##   YES     81.42857 18.57143
### County and Preventable Death (Chi-square)
cat("\n\nChi-square: County by Preventable Death\n")
## 
## 
## Chi-square: County by Preventable Death
county_table <- table(countyjail_data$agency_county, 
                      countyjail_data$preventable_death)
chisq_county <- chisq.test(county_table)
print(chisq_county)
## 
##  Pearson's Chi-squared test
## 
## data:  county_table
## X-squared = 26.13, df = 3, p-value = 8.96e-06
### Race and Preventable Death (Chi-square)
cat("\n\nChi-square: Race by Preventable Death\n")
## 
## 
## Chi-square: Race by Preventable Death
race_table <- table(countyjail_data$race, 
                    countyjail_data$preventable_death)
chisq_race <- chisq.test(race_table)
## Warning in chisq.test(race_table): Chi-squared approximation may be incorrect
print(chisq_race)
## 
##  Pearson's Chi-squared test
## 
## data:  race_table
## X-squared = 18.128, df = 3, p-value = 0.0004139
library(tidyverse)
library(readxl)
library(psych)
library(knitr)

##ANOVA : County Differences

##Age across counties
anova_age <- aov(age_at_time_of_death ~ agency_county, 
                 data = countyjail_data %>% 
                   filter(agency_county %in% c("BEXAR", "DALLAS", "HARRIS", "TRAVIS")))
summary(anova_age)
##                Df Sum Sq Mean Sq F value Pr(>F)  
## agency_county   3   2193   731.0   3.358 0.0189 *
## Residuals     386  84038   217.7                 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Post-hoc test
TukeyHSD(anova_age)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = age_at_time_of_death ~ agency_county, data = countyjail_data %>% filter(agency_county %in% c("BEXAR", "DALLAS", "HARRIS", "TRAVIS")))
## 
## $agency_county
##                    diff        lwr         upr     p adj
## DALLAS-BEXAR   3.825057  -1.743174  9.39328810 0.2882031
## HARRIS-BEXAR   2.496856  -2.170039  7.16374999 0.5123687
## TRAVIS-BEXAR  -4.167090 -10.941287  2.60710711 0.3871057
## HARRIS-DALLAS -1.328202  -6.659606  4.00320277 0.9180113
## TRAVIS-DALLAS -7.992147 -15.240162 -0.74413263 0.0240764
## TRAVIS-HARRIS -6.663946 -13.244860 -0.08303202 0.0458887
### Days in custody across counties
anova_days <- aov(days_from_custody_to_death ~ agency_county, 
                  data = countyjail_data %>% 
                    filter(agency_county %in% c("BEXAR", "DALLAS", "HARRIS", "TRAVIS")))
summary(anova_days)
##                Df   Sum Sq Mean Sq F value Pr(>F)
## agency_county   3   109969   36656   0.926  0.428
## Residuals     386 15280323   39586

##Logistic Regression Models

#Filter to 4 main counties
four_counties <- countyjail_data %>%
  filter(agency_county %in% c("BEXAR", "DALLAS", "HARRIS", "TRAVIS"))

### Model 1: Demographic factors only
model1 <- glm(preventable_death ~ age_at_time_of_death + sex_male + 
              race_black + race_hispanic,
              data = four_counties,
              family = binomial)

cat("Model 1: Demographics Only\n")
## Model 1: Demographics Only
summary(model1)
## 
## Call:
## glm(formula = preventable_death ~ age_at_time_of_death + sex_male + 
##     race_black + race_hispanic, family = binomial, data = four_counties)
## 
## Coefficients:
##                      Estimate Std. Error z value Pr(>|z|)    
## (Intercept)           2.21355    0.67731   3.268  0.00108 ** 
## age_at_time_of_death -0.07489    0.01256  -5.961 2.51e-09 ***
## sex_male             -0.15009    0.44079  -0.341  0.73347    
## race_black           -1.59295    0.39056  -4.079 4.53e-05 ***
## race_hispanic        -0.22262    0.35661  -0.624  0.53245    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 348.20  on 389  degrees of freedom
## Residual deviance: 286.98  on 385  degrees of freedom
## AIC: 296.98
## 
## Number of Fisher Scoring iterations: 5
# Odds ratios
model1_or <- data.frame(
  Variable = names(coef(model1)),
  Odds_Ratio = exp(coef(model1)),
  CI_Lower = exp(confint(model1))[,1],
  CI_Upper = exp(confint(model1))[,2],
  P_Value = summary(model1)$coefficients[,4]
)
## Waiting for profiling to be done...
## Waiting for profiling to be done...
kable(model1_or, digits = 3, caption = "Model 1: Odds Ratios (Demographics)")
Model 1: Odds Ratios (Demographics)
Variable Odds_Ratio CI_Lower CI_Upper P_Value
(Intercept) (Intercept) 9.148 2.456 35.526 0.001
age_at_time_of_death age_at_time_of_death 0.928 0.904 0.950 0.000
sex_male sex_male 0.861 0.374 2.140 0.733
race_black race_black 0.203 0.091 0.425 0.000
race_hispanic race_hispanic 0.800 0.392 1.595 0.532
### Model 2: Add mental health and custody factors
model2 <- glm(preventable_death ~ age_at_time_of_death + sex_male + 
              race_black + race_hispanic + mh_yes + suicidal_yes +
              days_from_custody_to_death,
              data = four_counties,
              family = binomial)

cat("\n\nModel 2: Demographics + Mental Health + Custody Time\n")
## 
## 
## Model 2: Demographics + Mental Health + Custody Time
summary(model2)
## 
## Call:
## glm(formula = preventable_death ~ age_at_time_of_death + sex_male + 
##     race_black + race_hispanic + mh_yes + suicidal_yes + days_from_custody_to_death, 
##     family = binomial, data = four_counties)
## 
## Coefficients:
##                              Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                 2.335e+00  6.960e-01   3.355 0.000793 ***
## age_at_time_of_death       -7.801e-02  1.288e-02  -6.058 1.38e-09 ***
## sex_male                   -2.530e-01  4.485e-01  -0.564 0.572647    
## race_black                 -1.661e+00  4.011e-01  -4.142 3.44e-05 ***
## race_hispanic              -2.050e-01  3.627e-01  -0.565 0.571903    
## mh_yes                     -2.854e-01  4.698e-01  -0.607 0.543523    
## suicidal_yes                1.648e+00  6.054e-01   2.722 0.006493 ** 
## days_from_custody_to_death  7.565e-05  8.169e-04   0.093 0.926215    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 348.20  on 389  degrees of freedom
## Residual deviance: 278.95  on 382  degrees of freedom
## AIC: 294.95
## 
## Number of Fisher Scoring iterations: 5
model2_or <- data.frame(
  Variable = names(coef(model2)),
  Odds_Ratio = exp(coef(model2)),
  CI_Lower = exp(confint(model2))[,1],
  CI_Upper = exp(confint(model2))[,2],
  P_Value = summary(model2)$coefficients[,4]
)
## Waiting for profiling to be done...
## Waiting for profiling to be done...
kable(model2_or, digits = 3, caption = "Model 2: Odds Ratios (+ Mental Health)")
Model 2: Odds Ratios (+ Mental Health)
Variable Odds_Ratio CI_Lower CI_Upper P_Value
(Intercept) (Intercept) 10.330 2.683 41.805 0.001
age_at_time_of_death age_at_time_of_death 0.925 0.901 0.948 0.000
sex_male sex_male 0.776 0.332 1.954 0.573
race_black race_black 0.190 0.083 0.405 0.000
race_hispanic race_hispanic 0.815 0.394 1.644 0.572
mh_yes mh_yes 0.752 0.282 1.811 0.544
suicidal_yes suicidal_yes 5.195 1.592 17.464 0.006
days_from_custody_to_death days_from_custody_to_death 1.000 0.998 1.002 0.926
### Model 3: Add county (main model)
model3 <- glm(preventable_death ~ age_at_time_of_death + sex_male + 
              race_black + race_hispanic + mh_yes + suicidal_yes +
              days_from_custody_to_death + agency_county,
              data = four_counties,
              family = binomial)

cat("\n\nModel 3: Full Model with County\n")
## 
## 
## Model 3: Full Model with County
summary(model3)
## 
## Call:
## glm(formula = preventable_death ~ age_at_time_of_death + sex_male + 
##     race_black + race_hispanic + mh_yes + suicidal_yes + days_from_custody_to_death + 
##     agency_county, family = binomial, data = four_counties)
## 
## Coefficients:
##                              Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                 2.7576094  0.7389734   3.732 0.000190 ***
## age_at_time_of_death       -0.0761146  0.0131995  -5.766 8.09e-09 ***
## sex_male                   -0.1598480  0.4669244  -0.342 0.732093    
## race_black                 -1.4740555  0.4152225  -3.550 0.000385 ***
## race_hispanic              -0.4468179  0.3855439  -1.159 0.246485    
## mh_yes                     -0.0766539  0.5012327  -0.153 0.878453    
## suicidal_yes                1.7043545  0.6184724   2.756 0.005856 ** 
## days_from_custody_to_death  0.0003156  0.0007943   0.397 0.691178    
## agency_countyDALLAS        -1.5638428  0.5500578  -2.843 0.004468 ** 
## agency_countyHARRIS        -1.1498989  0.4120464  -2.791 0.005259 ** 
## agency_countyTRAVIS        -0.4172569  0.4828710  -0.864 0.387524    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 348.20  on 389  degrees of freedom
## Residual deviance: 265.31  on 379  degrees of freedom
## AIC: 287.31
## 
## Number of Fisher Scoring iterations: 6
model3_or <- data.frame(
  Variable = names(coef(model3)),
  Odds_Ratio = exp(coef(model3)),
  CI_Lower = exp(confint(model3))[,1],
  CI_Upper = exp(confint(model3))[,2],
  P_Value = summary(model3)$coefficients[,4]
)
## Waiting for profiling to be done...
## Waiting for profiling to be done...
kable(model3_or, digits = 3, caption = "Model 3: Full Model with County Effects")
Model 3: Full Model with County Effects
Variable Odds_Ratio CI_Lower CI_Upper P_Value
(Intercept) (Intercept) 15.762 3.811 70.349 0.000
age_at_time_of_death age_at_time_of_death 0.927 0.902 0.950 0.000
sex_male sex_male 0.852 0.352 2.226 0.732
race_black race_black 0.229 0.098 0.503 0.000
race_hispanic race_hispanic 0.640 0.296 1.349 0.246
mh_yes mh_yes 0.926 0.330 2.391 0.878
suicidal_yes suicidal_yes 5.498 1.651 19.064 0.006
days_from_custody_to_death days_from_custody_to_death 1.000 0.999 1.002 0.691
agency_countyDALLAS agency_countyDALLAS 0.209 0.065 0.577 0.004
agency_countyHARRIS agency_countyHARRIS 0.317 0.138 0.700 0.005
agency_countyTRAVIS agency_countyTRAVIS 0.659 0.248 1.662 0.388
# Model fit statistics
cat("\n\nModel Fit Statistics:\n")
## 
## 
## Model Fit Statistics:
cat("Model 1 AIC:", AIC(model1), "\n")
## Model 1 AIC: 296.981
cat("Model 2 AIC:", AIC(model2), "\n")
## Model 2 AIC: 294.9452
cat("Model 3 AIC:", AIC(model3), "\n")
## Model 3 AIC: 287.3051
# Pseudo R-squared
cat("\nMcFadden's Pseudo R-squared:\n")
## 
## McFadden's Pseudo R-squared:
cat("Model 1:", 1 - (model1$deviance / model1$null.deviance), "\n")
## Model 1: 0.1758164
cat("Model 2:", 1 - (model2$deviance / model2$null.deviance), "\n")
## Model 2: 0.1988944
cat("Model 3:", 1 - (model3$deviance / model3$null.deviance), "\n")
## Model 3: 0.2380675

#Interaction Analysis: Does Mental Health Effect Vary by County?

model_interaction <- glm(preventable_death ~ age_at_time_of_death + sex_male +
                        race_black + race_hispanic + 
                        mh_yes * agency_county,  # Interaction term
                        data = four_counties,
                        family = binomial)

summary(model_interaction)
## 
## Call:
## glm(formula = preventable_death ~ age_at_time_of_death + sex_male + 
##     race_black + race_hispanic + mh_yes * agency_county, family = binomial, 
##     data = four_counties)
## 
## Coefficients:
##                            Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                 2.72855    0.73696   3.702 0.000214 ***
## age_at_time_of_death       -0.07855    0.01349  -5.821 5.86e-09 ***
## sex_male                    0.15723    0.46992   0.335 0.737940    
## race_black                 -1.43054    0.41633  -3.436 0.000590 ***
## race_hispanic              -0.47787    0.38640  -1.237 0.216188    
## mh_yes                     -0.84308    1.19269  -0.707 0.479646    
## agency_countyDALLAS        -1.06785    0.55840  -1.912 0.055833 .  
## agency_countyHARRIS        -1.70431    0.47499  -3.588 0.000333 ***
## agency_countyTRAVIS        -0.34601    0.56269  -0.615 0.538609    
## mh_yes:agency_countyDALLAS -0.28190    1.67930  -0.168 0.866686    
## mh_yes:agency_countyHARRIS  3.36686    1.39265   2.418 0.015623 *  
## mh_yes:agency_countyTRAVIS  0.95917    1.40777   0.681 0.495656    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 348.20  on 389  degrees of freedom
## Residual deviance: 261.59  on 378  degrees of freedom
## AIC: 285.59
## 
## Number of Fisher Scoring iterations: 6
interaction_or <- data.frame(
  Variable = names(coef(model_interaction)),
  Odds_Ratio = exp(coef(model_interaction)),
  CI_Lower = exp(confint(model_interaction))[,1],
  CI_Upper = exp(confint(model_interaction))[,2],
  P_Value = summary(model_interaction)$coefficients[,4]
)
## Waiting for profiling to be done...
## Waiting for profiling to be done...
kable(interaction_or, digits = 3, 
      caption = "Interaction Model: Mental Health × County")
Interaction Model: Mental Health × County
Variable Odds_Ratio CI_Lower CI_Upper P_Value
(Intercept) (Intercept) 15.311 3.707 67.908 0.000
age_at_time_of_death age_at_time_of_death 0.924 0.899 0.948 0.000
sex_male sex_male 1.170 0.481 3.076 0.738
race_black race_black 0.239 0.102 0.527 0.001
race_hispanic race_hispanic 0.620 0.286 1.310 0.216
mh_yes mh_yes 0.430 0.020 3.235 0.480
agency_countyDALLAS agency_countyDALLAS 0.344 0.104 0.962 0.056
agency_countyHARRIS agency_countyHARRIS 0.182 0.068 0.445 0.000
agency_countyTRAVIS agency_countyTRAVIS 0.708 0.219 2.050 0.539
mh_yes:agency_countyDALLAS mh_yes:agency_countyDALLAS 0.754 0.021 27.896 0.867
mh_yes:agency_countyHARRIS mh_yes:agency_countyHARRIS 28.987 2.401 794.779 0.016
mh_yes:agency_countyTRAVIS mh_yes:agency_countyTRAVIS 2.610 0.206 72.421 0.496

#Additional Visulizations

###1. Age Distribution by Preventable Death
ggplot(countyjail_data, aes(x = factor(preventable_death), 
                             y = age_at_time_of_death,
                             fill = factor(preventable_death))) +
  geom_boxplot() +
  scale_fill_manual(values = c("lightblue", "coral")) +
  labs(title = "Age Distribution by Preventable Death Status",
       x = "Preventable Death (0 = No, 1 = Yes)",
       y = "Age at Death",
       fill = "Preventable") +
  theme_minimal() +
  theme(legend.position = "none")

### 2. Mental Health by County and Preventable Death
mh_county_plot <- four_counties %>%
  group_by(agency_county, preventable_death) %>%
  summarise(mh_pct = mean(mh_yes) * 100, .groups = 'drop')

ggplot(mh_county_plot, aes(x = agency_county, y = mh_pct, 
                           fill = factor(preventable_death))) +
  geom_bar(stat = "identity", position = "dodge") +
  scale_fill_manual(values = c("steelblue", "coral"),
                    labels = c("Non-Preventable", "Preventable")) +
  labs(title = "Mental Health Documentation by County and Preventable Death",
       x = "County",
       y = "% with Mental Health Issues",
       fill = "Death Type") +
  theme_minimal()

### 3. Days in Custody by County
ggplot(four_counties, aes(x = agency_county, 
                          y = days_from_custody_to_death,
                          fill = agency_county)) +
  geom_boxplot() +
  labs(title = "Days from Custody to Death by County",
       x = "County",
       y = "Days in Custody") +
  theme_minimal() +
  theme(legend.position = "none")

### 4. Preventable Death Rate by Mental Health Status
mh_prev_plot <- countyjail_data %>%
  group_by(exhibit_any_mental_health_problems) %>%
  summarise(
    n = n(),
    preventable_rate = mean(preventable_death) * 100,
    .groups = 'drop'
  ) %>%
  filter(exhibit_any_mental_health_problems != "UNKNOWN")

ggplot(mh_prev_plot, aes(x = exhibit_any_mental_health_problems, 
                         y = preventable_rate,
                         fill = exhibit_any_mental_health_problems)) +
  geom_bar(stat = "identity") +
  geom_text(aes(label = paste0(round(preventable_rate, 1), "%")), 
            vjust = -0.5, size = 5) +
  labs(title = "Preventable Death Rate by Mental Health Status",
       x = "Mental Health Problems Documented",
       y = "Preventable Death Rate (%)") +
  theme_minimal() +
  theme(legend.position = "none")

### 5. Race Distribution by County
race_county <- four_counties %>%
  count(agency_county, race) %>%
  group_by(agency_county) %>%
  mutate(pct = n / sum(n) * 100)

ggplot(race_county, aes(x = agency_county, y = pct, fill = race)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Racial Composition of Deaths by County",
       x = "County",
       y = "Percentage",
       fill = "Race") +
  theme_minimal()

### 6. Timing of Death by County
timing_county <- four_counties %>%
  count(agency_county, timing_category) %>%
  group_by(agency_county) %>%
  mutate(pct = n / sum(n) * 100)

ggplot(timing_county, aes(x = agency_county, y = pct, fill = timing_category)) +
  geom_bar(stat = "identity") +
  labs(title = "Timing of Death by County",
       x = "County",
       y = "Percentage",
       fill = "Time in Custody") +
  theme_minimal()

#Conclusion The Evidence Is Clear: Preventable Deaths Are Preventable This analysis of 390 custodial deaths across Texas’s four largest county jail systems between 2015 and 2025 reveals a troubling truth. The likelihood of experiencing a preventable death in custody depends more on which county jail you’re in than on individual risk factors. The data demonstrates a 3.6-fold variation in preventable death rates from Travis County’s 27.9% to Dallas County’s 7.8%, that cannot be attributed to demographics, facility size, or chance. Travis and Bexar counties each classify more than 1 in 4 deaths as preventable, while Dallas and Harris counties prevent the vast majority of deaths that could be avoided, with rates below 9%.

What the Numbers Mean

These are not abstract statistics. Behind Travis County’s 27.9% rate are 12 individuals who died preventable deaths. Behind Bexar County’s 27.7% rate are 33 people, including my brother Francisco Bazan and 32 others whose lives could have been saved with proper institutional safeguards. Together, Travis and Bexar counties account for 45 of the 64 preventable deaths (70%) in this four- county sample, despite representing only 42% of total deaths. If these two counties had achieved Dallas County’s preventable death rate, an estimated 32 lives would have been saved over this decade.

Institutional Factors Trump Individual Risk

The near-identical preventable death rates in Travis (27.9%) and Bexar (27.7%), two counties with different facility sizes and populations point to shared institutional deficiencies rather than individual level factors. The similarity suggests systemic problems in:

Medical screening and assessment protocols Mental health crisis intervention Staff training and emergency response Monitoring of at-risk individuals Continuity of care for chronic conditions

Statistical analysis confirms these institutional failures. Bivariate analyses reveal that younger age (p < 0.001), race (p < 0.001), and suicidal statements are significantly associated with preventable death. Individuals who died preventable deaths were, on average, 12.3 years younger (36.6 vs. 48.9 years, p < 0.001) than those who died non-preventable deaths. Those who made suicidal statements had dramatically elevated risk. However, multivariate logistic regression controlling for age, sex, race, mental health status, suicidal ideation, and time in custody demonstrates that county-level differences remain statistically significant (p < 0.01). Even after accounting for who is in custody and their documented risk factors:

Dallas County inmates have 79% lower odds of preventable death compared to Bexar County (OR = 0.21, 95% CI = 0.07-0.58, p = 0.004) Harris County inmates have 68% lower odds of preventable death compared to Bexar County (OR = 0.32, 95% CI = 0.14-0.70, p = 0.005) Travis County shows no statistical difference from Bexar County (OR = 0.66, 95% CI = 0.25-1.66, p = 0.388), confirming their shared institutional failures

This confirms that institutional practices, not just the characteristics of people in custody—drive mortality outcomes. Travis and Bexar’s identical preventable death rates persist even after controlling for every measurable individual risk factor, proving these are institutional, not individual, failures.

Critical Finding on Suicidal Ideation: Individuals who made suicidal statements had 5.5 times the odds of experiencing a preventable death (OR = 5.50, 95% CI = 1.65-19.06, p = 0.006), even after controlling for all other factors. This suggests that suicidal statements are a major red flag that is not being adequately addressed in jail mental health protocols, particularly in Travis and Bexar counties. Mental Health Systems Matter: Interaction analysis reveals that mental health effects vary dramatically by county. In Harris County, documented mental health problems interact with institutional practices in ways that significantly reduce preventable deaths (p = 0.016). This suggests Harris County has implemented mental health screening and intervention protocols that other counties lack protocols that should be immediately investigated and mandated statewide. Conversely, the consistently low rates in Dallas (7.8%) and Harris (8.6%) demonstrate that proper systems prevent deaths. These counties prove that current conditions in Travis and Bexar are not inevitable, they are institutional failures

Conversely, the consistently low rates in Dallas (7.8%) and Harris (8.6%) demonstrate that proper systems prevent deaths. These counties prove that current conditions in Travis and Bexar are not inevitable, they are institutional failures.

Size Does Not Determine Outcomes

Harris County’s success is particularly instructive. Despite having 151 deaths, the largest sample and nearly 4 times Travis County’ s volume, Harris maintained the second-lowest preventable death rate at 8.6%. This definitively proves that facility size and death volume do not predetermine outcomes. Large jail systems can and do prevent deaths when proper protocols are in place.

The Urgent Need for Reform

These findings demand immediate action on multiple fronts:

  1. Statewide Standards Are Essential The 20.1 percentage point gap between Travis and Dallas counties reveals the absence of uniform standards across Texas jail systems.

The state must mandate:

Standardized medical screening at intake. Mental health assessment and crisis intervention protocos. Regular monitoring of medically and mentally vulnerable individuals. Evidence-based staff training on recognizing and responding to medical emergencies. Transparent reporting and independent investigation of all custodial deaths.

  1. Learn from Success

An urgent priority must be identifying what Dallas and Harris counties are doing differently. Their practices whether superior medical staffing, better training protocols, enhanced monitoring systems, or more robust mental health services—should be documented, validated, and required statewide.

The regression analysis points to specific areas for investigation. Harris County’s success appears particularly linked to how they handle mental health cases statistical modeling shows their mental health protocols significantly reduce preventable deaths in ways not seen in other counties. Dallas County’s success spans multiple factors, achieving lower preventable death rates across all risk categories. Both counties must be managing suicidal ideation more effectively, given that suicidal statements increase preventable death risk by 450% in the overall sample. What screening tools do they use? How quickly do they respond to suicidal statements? What monitoring protocols prevent crises from becoming fatalities? These specific practices must be identified, documented, and required statewide immediately.

  1. Accountability for Failure

Counties with elevated preventable death rates require:

Immediate external audits of death prevention protocols. Enhanced state oversight and intervention. Mandatory corrective action plans. Public transparency in custodial death investigations. Consequences for systemic failures to protect people in custody.

  1. Resources Must Follow Reform

Preventing deaths requires investment. Counties need adequate resources for:

Medical and mental health staffing. Staff training and continuing education. Facility improvements for monitoring and care. Technology and systems for tracking at-risk individuals.

However, resource constraints cannot excuse the current disparities. Harris County manages 151 deaths with an 8.6% preventable rate, demonstrating that effective prevention is achievable even at scale.

Every Preventable Death Is a Policy Failure

The fundamental finding of this research is that preventable deaths in Texas county jails are exactly that, preventable. The existence of counties with 7.8% preventable death rates proves that the 27.9% rate in other counties represents institutional choices, not inevitable outcomes.

Each of the 64 preventable deaths in this sample represents:

A person who entered custody alive. A death that could have been avoided. A family forever changed by loss. A failure of the system to fulfill its duty of care.

For my brother, Francisco Bazan and the 32 other individuals who died preventable deaths in Bexar County, and the 12 in Travis County these numbers represent profound, irreversible loss that proper institutional practices could have prevented.

The Path Forward

The evidence presented here provides a clear roadmap for reform:

Immediately investigate what practices Dallas and Harris counties employ that Travis and Bexar do not. Mandate statewide adoption of evidence-based protocols for medical screening, mental health assessment, and emergency response. Require external oversight of counties with elevated preventable death rates. Ensure transparency through public reporting of custodial deaths and investigation findings. Invest resources in medical and mental health staffing sufficient to prevent deaths. Hold counties accountable for failing to implement life-saving protocols.

Final Thoughts

This analysis began with a simple question: Why do preventable death rates vary so dramatically across Texas county jails? The answer is equally simple but profoundly troubling, some counties have systems that prevent deaths, and others do not. The 3.6-fold difference between Travis and Dallas counties is not a statistical curiosity, it is evidence of preventable institutional failure that has cost dozens of lives over the past decade. The good news is that we know prevention is possible because some counties are already doing it. The tragedy is that this knowledge has not yet translated into statewide action. The moral imperative is clear, Texas must ensure that all county jails adopt the practices that save lives. Every person in custody deserves the same standard of care, the same protection from preventable harm, and the same chance of leaving custody alive. Until Texas achieves that standard, the families of those who died preventable deaths and the communities they came from will continue to bear the cost of institutional failure. The question is no longer whether preventable deaths can be avoided. The data proves they can. The question is whether Texas will act on this evidence to ensure they are.

This analysis is dedicated to my brother, Francisco Bazan and the 63 other individuals whose preventable deaths in Texas county jails between 2015 and 2025. We demand accountability, reform, and a commitment that their lives and deaths will drive meaningful change.