Introduction

Mandatory Minimums

A mandatory minimum is “a minimum punishment that must be imposed by a court when a person is convicted of a specific offense.” 1

slices <- c(162, 64)
pct <- c((162/224)*100, (64/224)*100)
pct <- round(pct)
labels <- c("Felonies", "Misdemeanors")
labels <- paste(labels, pct)
labels <- paste(labels,"%",sep="")
pie(slices, labels = labels, main = "Mandatory Minimum Offenses in VA")

Rationales

tab <- matrix(c("Deterrence", "Uniformity", "Incapacitation", "Cooperation", "Ineffective", "Inequity", "Manipulation", "Trial Tax"), ncol=2, nrow = 4)
colnames(tab) <- c('Proponents','Opponents')
rownames(tab) <- c('1','2','3','4')
tab <- as.table(tab)

kbl(tab) %>% 
   kable_styling(bootstrap_options = c("striped")) %>% 
  column_spec(1, color = "green"
              ) %>% 
  column_spec(2, color = "red"
              )
Proponents Opponents
Deterrence Ineffective
Uniformity Inequity
Incapacitation Manipulation
Cooperation Trial Tax

Literature Findings

  1. Minoritized groups systemtically receive disproportionately high sentences

  2. At least some of this disparity can be explained by prosecutors charging minoritized people with mandatory minimums at a rate higher than white people

  3. In the court system, judicial discretion may generally reduce racial disparity caused by prosecutorial decision-making 2

Research Questions

Based on what we found in the literature and the current conversation in Virginia about abolishing mandatory minimums because of their disparate racial effects, we were interested in looking at:
1. If there is a racial disparity in assault charges
2. If there is a racial disparity in guilty verdicts
3. If there is a racial disparity in sentencing

For each of these, we are interested in whether or not there is evidence that mandatory minimums exacerbate those disparities.

Data and Variable Definition

  • We have ten years of data at the state level.
  • We limited our data to just look at assault charges.
  • Simple assault has no mandatory minimum charge, while assault against law enforcement officers, school principals/teachers, fire/EMT, public service officers, or with a firearm is subject to a mandatory minimum sentence of 180 days.
  • We generated a variable to indicate whether a defendant was charged with a crime that had a mandatory minimum sentence. We were concerned at first that 104 mandatory minimum charges had sentence times below 180 days. Upon further investigation, however, we found that 101 of those charges had been amended.

Number of mandatory minimum charges with sentences below 180 days:

cc_assault_2010_2020 %>% filter(mand_min==1 & SentenceTime < 180) %>% count()
## # A tibble: 1 × 1
##       n
##   <int>
## 1   104
cc_assault_2010_2020 <- cc_assault_2010_2020 %>% 
  mutate(charge_amended = ifelse(AmendedCharge=="NA",0,1))
cc_assault_2010_2020 %>% 
  filter(SentenceTime!="NA") %>% 
  filter(mand_min==1 & SentenceTime < 180) %>% 
  mutate(ncases = n()) %>% 
  filter(charge_amended==1) %>% 
  summarize(n_cases = ncases,
            n_amended = n(),
            pct_amended = n_amended/n_cases)
## # A tibble: 101 × 3
##    n_cases n_amended pct_amended
##      <int>     <int>       <dbl>
##  1     104       101       0.971
##  2     104       101       0.971
##  3     104       101       0.971
##  4     104       101       0.971
##  5     104       101       0.971
##  6     104       101       0.971
##  7     104       101       0.971
##  8     104       101       0.971
##  9     104       101       0.971
## 10     104       101       0.971
## # … with 91 more rows
  • We decided to code the race variable as a binary variable indicating whether the defendant is from a minoritized group or not. We defined white, non-hispanic individuals as non-minoritized, and all other categorizations as minoritized.

Number of Cases from 2010-2020

library (stringr)

#Both of these charges have followed the same relative trend over the last decade.

cc_allassaultsovertime <- cc_allassault_2010_2020
cc_allassaultsovertime %>%
  mutate(minoritized2 = recode(minoritized, 
                               "1" = "Minoritized",
                               "0" = "Non-Minoritized")) %>% 
  mutate(mand_min2 = recode(mand_min,
                            "1" = "Mandatory Minimum",
                            "0" = "No Mandatory Minimum")) %>%
  ggplot(aes(Filed)) + 
  geom_freqpoly(binwidths = 7) +
  facet_wrap(~ minoritized2 + mand_min2) +
  scale_x_date(name = "Filing Year",
  )

Disparities in Charging

Percent of Minoritized People Charged

# add pop data and do rate of minoritized/white over time
library(tidycensus)
library(lubridate)

# Add population estimates from census
popvars <- c(total = "B02001_001",
            white = "B02001_002")
census_api_key(key = "55fdb905b160933490e981b1c694bd3df806ff80", overwrite = TRUE, install = TRUE)
readRenviron("~/.Renviron")

pop_state <-
  map_df(2019:2010,
         ~ get_acs(
           year = .x,
           geography = "state",
           state = "VA",
           variables =  popvars,
           survey = "acs1", 
           output = "wide",
           cache = TRUE
         ) %>%
           mutate(year = .x)
  )

# 2020 census used instead
pop_state_2020 <- get_decennial(
  geography = "state",
  state = "51",
  variables = c(totalE = "P1_001N",
                whiteE = "P1_003N"),
  output = "wide",
  year = 2020
) %>% 
  mutate(year = 2020)

# bind these and create minoritized count,
pop_state <- bind_rows(pop_state, pop_state_2020)

pop_state <- pop_state %>% 
  mutate(minoritizedE = totalE-whiteE,
    percent_white = (whiteE/totalE)*100,
         percent_minoritized = 100-percent_white)

library (readr)
pop_state <-pop_state

write_csv(x = pop_state, "pop_state.csv")
# note the jump from the census count (versus estimation from ACS survey) in 2020!
ggplot(pop_state, aes(x = year, y = percent_minoritized)) +
  geom_line(color="black") +
  expand_limits(y = c(0,50)) +
  labs(title="Percent Minoritized People Charged", x="Year", y="Percent Minoritized")

Charges Per 100,000 People

# first create cases by year/minoritized and join to pop by year
assault_year <- cc_allassault_2010_2020 %>% 
  filter(!is.na(minoritized)) %>% 
  mutate(filed_year = year(Filed),
         minoritized = ifelse(minoritized == 1, "minoritized", "nonminoritized"),
         mand_min = ifelse(mand_min == 1, "minimum", "nonminimum")) %>% 
  group_by(filed_year, minoritized, mand_min) %>% 
  summarize(cases = n()) %>% 
  pivot_wider(id_cols = filed_year, names_from = c(minoritized, mand_min), values_from = cases)

# then join population to above yearly counts
assault_year <- left_join(assault_year, pop_state, by = c("filed_year" = "year"))

# And create rates
assault_year <- assault_year %>% 
  mutate(min_mandmin_rate = (minoritized_minimum/minoritizedE)*100000,
         min_nomandmin_rate = (minoritized_nonminimum/minoritizedE)*100000,
         majority_mandmin_rate = (nonminoritized_minimum/whiteE)*100000,
         majority_nomandmin_rate = (nonminoritized_nonminimum/whiteE)*100000)

                               
# and graph or table or use in other ways
# to graph, reshape to long
assault_year_long <- assault_year %>% 
  select(filed_year, min_mandmin_rate:majority_nomandmin_rate) %>% 
  pivot_longer(cols = -filed_year, names_to = "type", values_to = "rate")

assault_year_long$type <- factor(assault_year_long$type,
                               labels = c("Non-minoritized mandatory min", "Non-minoritized simple assault", "Minoritized mandatory min", "Minoritized simple assault"))

library (stringr)
assault_year_long$type2 = str_sub(assault_year_long$type, -3)

assault_year_long%>%
mutate(assault_type = recode(type2,
                            "min" = "Mandatory Minimum",
                            "ult" = "No Mandatory Minimum")) %>%
ggplot(aes(x = filed_year, y = rate, color = type)) + 
  geom_line() +
  labs(title="Individuals charged per 100,000 residents", x="Year", y="Number per 100,000") + 
  facet_wrap(~assault_type) +
  scale_color_manual(values = c('Purple', 'Purple','Blue', 'Blue'))