Introduction

This analysis revisits C. Richard Hofstetter’s 1969 study on political disengagement following the assassination of Martin Luther King Jr., published in The Public Opinion Quarterly.

The data for this study was collected through a survey project on electoral behavior in Central Ohio. Hofstetter used a probability sample of all adults living in residences in the greater Columbus, Ohio metropolitan area. The sampling frame was based on a recent city directory, from which residences were randomly selected. To ensure representativeness, respondents at specified residences were then systematically selected to provide sex-age distributions that matched the population. The interviewers achieved a completion rate of approximately 80% of attempted interviews.

The assassination of Martin Luther King Jr. on April 4, 1968, at approximately 7:10 PM, occurred midway through the interviewing phase. This created a natural experiment, with respondents interviewed before this time forming a “control” group and those interviewed after forming a “treatment” group exposed to knowledge of the assassination.

The author interpreted the results as following: He saw a clear increase in negative sentiment towards several figures and institutions perceived as representing the white establishment (police, white people, national politicians, Richard Nixon), there was also a simultaneous increase in positive affect towards groups representing Black identity and empowerment (NAACP and Black people as a group). This suggests a process of selective disengagement, where alienation from certain aspects of the political system coincided with a strengthening of ties to others. Hofstetter finds that white respondents were less significantly impacted by the assassination of Martin Luther King Jr. than Black respondents.

The statistical methods available to Hofstetter in 1969 were more limited compared to our modern analysis, but not entirely rudimentary. The chi-squared test, which we used in our initial analysis of changes in positive and negative affect, was indeed a widely known and established statistical method at that time. Hofstetter and his team would have been able to perform chi-squared tests, although the process would have been far more laborious than it is today However, more advanced techniques like the Kolmogorov-Smirnov test, while theoretically known, would have been much more challenging to implement in practice due to computational limitations. The polarization index and distribution analyses I conduct here represent modern approaches that weren’t readily available to researchers in the late 1960s.

In this analysis, I examine the statistical significance of attitude changes towards various political objects before and after the MLK assassination, stratified by race. Using the dataset of affect percentages and sample sizes reported in the article, I perform chi-squared tests on contingency tables to assess significant shifts in positive and negative attitudes for each political object and racial group. The results are presented in tables and visualized through bar charts, highlighting statistically significant changes (p < 0.05). Additionally, I conduct polarization analyses using both variance-based methods (Levene’s test) and more advanced techniques (polarization index, kurtosis, and Kolmogorov-Smirnov tests) to examine changes in the spread and shape of attitude distributions. For significant changes, I create density ridge plots to visualize the shifts in attitude distributions. This approach combines methods available in 1969 with modern techniques to provide a comprehensive view of attitude changes and potential polarization effects following the assassination.

The findings regarding the minimal effect on white respondents are largely aligned with Hofstetter’s article. No statistically significant changes in positive or negative affect were observed among white respondents for any political object. The advanced polarization analysis confirms this, showing no significant changes in the distribution of white attitudes (all KS p-values = 1). For Black respondents, the most notable change was towards the police. This change manifested in multiple ways: a significant increase in negative affect (from 3.7% to 31.0%, p = 0.01), a substantial but not statistically significant decrease in positive affect (from 88.9% to 58.6%, p = 0.274), a significant increase in opinion polarization as measured by variance ratio (2.450, p < 0.01), and a significant change in the overall distribution of attitudes (KS p-value = 0.0154). The polarization for police attitudes among Black respondents increased dramatically indicating a substantial increase in polarization. Other changes in Black respondents’ attitudes were observed but were not statistically significant.

Data Preparation and Analysis

# Input data
data <- tibble(
  Political_Object = rep(c("Police", "White", "Democratic Party", "Lyndon Johnson", "NAACP", "Black", "Republican Party", "Richard Nixon", "National Politicians"), each = 4),
  Time = rep(c("B", "A"), times = 18),
  Race = rep(c("White", "Black"), each = 2, times = 9),
  Negative = c(3.8, 5.8, 3.7, 31.0, 0.0, 1.9, 11.1, 24.1, 9.9, 15.4, 0.0, 3.4, 28.6, 32.7, 11.1, 17.2, 30.8, 31.4, 11.1, 3.4, 10.4, 16.7, 0.0, 0.0, 8.8, 9.6, 22.2, 31.0, 19.8, 24.4, 22.2, 48.3, 7.1, 9.6, 7.4, 24.1),
  Neutral = c(8.2, 7.7, 7.4, 10.3, 18.1, 18.6, 18.5, 24.1, 21.4, 17.3, 22.2, 10.3, 16.5, 10.3, 14.8, 6.9, 24.2, 20.5, 22.2, 13.8, 33.0, 25.0, 14.8, 10.3, 22.0, 17.9, 29.6, 34.5, 15.9, 12.8, 18.5, 20.7, 26.9, 16.0, 37.0, 41.4),
  Positive = c(87.9, 86.5, 88.9, 58.6, 81.9, 79.5, 70.4, 51.7, 68.7, 67.3, 77.8, 86.2, 54.9, 57.1, 74.1, 75.9, 45.1, 48.1, 66.7, 82.8, 56.6, 58.3, 85.2, 89.7, 69.2, 72.4, 48.1, 34.5, 64.3, 62.8, 59.3, 31.0, 65.9, 74.4, 55.6, 34.5)
)

# Add sample sizes
sample_sizes <- tibble(
  Race = c("White", "White", "Black", "Black"),
  Time = c("B", "A", "B", "A"),
  Sample_Size = c(182, 156, 27, 29)
)

# Join sample sizes to main data
data <- data %>%
  left_join(sample_sizes, by = c("Race", "Time"))

# Analysis function
analyze_affect <- function(object, race, affect_type) {
  obj_data <- data %>% 
    filter(Political_Object == object, Race == race) %>%
    select(Time, !!sym(affect_type), Sample_Size) %>%
    mutate(Value = round(!!sym(affect_type) * Sample_Size / 100)) # Convert percentages to counts
  
  contingency_table <- xtabs(Value ~ Time, data = obj_data)
  
  # Check for zero entries in contingency table
  if (all(contingency_table == 0)) {
    return(tibble(
      Political_Object = object,
      Race = race,
      Affect_Type = affect_type,
      Before_Affect = 0,
      After_Affect = 0,
      Difference = 0,
      P_value = NA
    ))
  }
  
  # Perform chi-squared test if there are positive entries
  chi_test <- tryCatch({
    chisq.test(contingency_table)
  }, error = function(e) {
    return(list(p.value = NA)) # Return NA if test fails
  })
  
  tibble(
    Political_Object = object,
    Race = race,
    Affect_Type = affect_type,
    Before_Affect = obj_data$Value[obj_data$Time == "B"] / obj_data$Sample_Size[obj_data$Time == "B"][1] * 100,
    After_Affect = obj_data$Value[obj_data$Time == "A"] / obj_data$Sample_Size[obj_data$Time == "A"][1] * 100,
    Difference = After_Affect - Before_Affect,
    P_value = chi_test$p.value
  )
}

# Run analysis for all combinations of Political Object, Race, and Affect Type
results <- crossing(
  Political_Object = unique(data$Political_Object),
  Race = unique(data$Race),
  Affect_Type = c("Positive", "Negative")
) %>%
  pmap_dfr(~analyze_affect(..1, ..2, ..3))

Results

Changes in Positive Affect

Changes in Positive Affect Before and After the King Assassination
Positive Affect (%)
Political_Object Race Before_Affect After_Affect Difference P_value Significant
Police Black 88.9 58.6 -30.3 0.274
Richard Nixon Black 59.3 31.0 -28.2 0.162
National Politicians Black 55.6 34.5 -21.1 0.317
White Black 70.4 51.7 -18.6 0.493
NAACP Black 66.7 82.8 16.1 0.355
Republican Party Black 48.1 34.5 -13.7 0.532
Democratic Party Black 77.8 86.2 8.4 0.555
Black Black 85.2 89.7 4.5 0.668
Lyndon Johnson Black 74.1 75.9 1.8 0.758
National Politicians White 65.9 74.4 8.4 0.795
Republican Party White 69.2 72.4 3.2 0.400
NAACP White 45.1 48.1 3.0 0.576
White White 81.9 79.5 -2.4 0.130
Lyndon Johnson White 54.9 57.1 2.1 0.424
Black White 56.6 58.3 1.7 0.389
Richard Nixon White 64.3 62.8 -1.5 0.195
Democratic Party White 68.7 67.3 -1.4 0.187
Police White 87.9 86.5 -1.4 0.146

Changes in Negative Affect

Changes in Negative Affect Before and After the King Assassination
Negative Affect (%)
Political_Object Race Before_Affect After_Affect Difference P_value Significant
Police Black 3.7 31.0 27.3 0.0114
Richard Nixon Black 22.2 48.3 26.1 0.0736
National Politicians Black 7.4 24.1 16.7 0.0956
White Black 11.1 24.1 13.0 0.2059
Republican Party Black 22.2 31.0 8.8 0.4386
NAACP Black 11.1 3.4 -7.7 0.3173
Lyndon Johnson Black 11.1 17.2 6.1 0.4795
Democratic Party Black 0.0 3.4 3.4 0.3173
Black Black 0.0 0.0 0.0 NA NA
Black White 10.4 16.7 6.2 0.2967
Democratic Party White 9.9 15.4 5.5 0.3545
Richard Nixon White 19.8 24.4 4.6 0.8162
Lyndon Johnson White 28.6 32.7 4.1 0.9215
National Politicians White 7.1 9.6 2.5 0.7055
Police White 3.8 5.8 1.9 0.6171
White White 0.0 1.9 1.9 0.0833
Republican Party White 8.8 9.6 0.8 0.8575
NAACP White 30.8 31.4 0.6 0.4945

Extract significant changes

Statistically Significant Changes in Affect Before and After the King Assassination
Affect (%)
Political_Object Race Affect_Type Before_Affect After_Affect Difference P_value
Police Black Negative 3.7 31 27.3 0.0114

Visualizations

Statistically significant changes

All affect changes

Tests of Polarization

Levene’s test

# Load necessary libraries
library(tidyverse)

# Function to calculate variance ratio and perform Levene's test
analyze_polarization <- function(object, race) {
  obj_data <- data %>% 
    filter(Political_Object == object, Race == race) %>%
    select(Time, Positive, Sample_Size) %>%
    mutate(
      Positive_Count = round(Positive * Sample_Size / 100),
      Negative_Count = Sample_Size - Positive_Count
    )
  
  # Calculate variance for before and after
  var_before <- var(c(rep(1, obj_data$Positive_Count[obj_data$Time == "B"]), 
                      rep(0, obj_data$Negative_Count[obj_data$Time == "B"])))
  var_after <- var(c(rep(1, obj_data$Positive_Count[obj_data$Time == "A"]), 
                     rep(0, obj_data$Negative_Count[obj_data$Time == "A"])))
  
  # Prepare data for Levene's test
  levene_data <- data.frame(
    affect = c(rep(1, obj_data$Positive_Count[obj_data$Time == "B"]), 
               rep(0, obj_data$Negative_Count[obj_data$Time == "B"]),
               rep(1, obj_data$Positive_Count[obj_data$Time == "A"]), 
               rep(0, obj_data$Negative_Count[obj_data$Time == "A"])),
    time = factor(c(rep("B", sum(obj_data$Sample_Size[obj_data$Time == "B"])),
                    rep("A", sum(obj_data$Sample_Size[obj_data$Time == "A"]))))
  )
  
  # Perform Levene's test
  levene_result <- leveneTest(affect ~ time, data = levene_data)
  
  tibble(
    Political_Object = object,
    Race = race,
    Variance_Before = var_before,
    Variance_After = var_after,
    Variance_Ratio = var_after / var_before,
    Levene_Statistic = levene_result$`F value`[1],
    Levene_P_value = levene_result$`Pr(>F)`[1]
  )
}

# Run analysis for all combinations of Political Object and Race
polarization_results <- crossing(
  Political_Object = unique(data$Political_Object),
  Race = unique(data$Race)
) %>%
  pmap_dfr(~analyze_polarization(..1, ..2))

# Display results
polarization_results %>%
  mutate(
    Significant = ifelse(Levene_P_value < 0.05, "*", ""),
    Variance_Ratio = round(Variance_Ratio, 3),
    Levene_P_value = format.pval(Levene_P_value, digits = 3)
  ) %>%
  arrange(Race, desc(abs(Variance_Ratio - 1))) %>%
  knitr::kable(digits = 3, caption = "Within-Group Polarization Analysis: Before vs After MLK Assassination") %>%
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = F)
Within-Group Polarization Analysis: Before vs After MLK Assassination
Political_Object Race Variance_Before Variance_After Variance_Ratio Levene_Statistic Levene_P_value Significant
Police Black 0.103 0.251 2.450 7.130 0.00999
NAACP Black 0.231 0.148 0.640 1.929 0.17062
Democratic Party Black 0.179 0.123 0.686 0.661 0.41975
Black Black 0.131 0.096 0.733 0.247 0.62091
White Black 0.217 0.259 1.194 2.040 0.15901
Richard Nixon Black 0.251 0.222 0.884 0.559 0.45791
Republican Party Black 0.259 0.234 0.903 1.061 0.30764
National Politicians Black 0.256 0.234 0.913 0.567 0.45479
Lyndon Johnson Black 0.199 0.190 0.951 0.023 0.88003
National Politicians White 0.226 0.192 0.850 2.837 0.09307
White White 0.149 0.164 1.099 0.305 0.58111
Police White 0.107 0.117 1.097 0.142 0.70658
Republican Party White 0.214 0.201 0.938 0.415 0.52004
Democratic Party White 0.216 0.221 1.024 0.072 0.78793
Richard Nixon White 0.231 0.235 1.018 0.077 0.78094
Black White 0.247 0.245 0.990 0.103 0.74797
Lyndon Johnson White 0.249 0.247 0.991 0.150 0.69845
NAACP White 0.249 0.251 1.009 0.307 0.57998
# Visualization of polarization
ggplot(polarization_results, aes(x = reorder(Political_Object, Variance_Ratio), y = Variance_Ratio, fill = Race)) +
  geom_col(position = position_dodge()) +
  geom_text(aes(label = ifelse(Levene_P_value < 0.05, "*", "")), 
            position = position_dodge(width = 0.9), 
            vjust = -0.5, size = 5) +
  coord_flip() +
  facet_wrap(~ Race, scales = "free_y") +
  labs(
    title = "Change in Within-Group Variance After MLK Assassination",
    subtitle = "Ratio of After/Before Variance (> 1 indicates increased polarization)\n* indicates statistically significant change (p < 0.05)",
    x = "Political Object",
    y = "Variance Ratio (After / Before)",
    fill = "Race"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

Kurtosis and Kolmogorov-Smirnov test

# Function to analyze polarization using kurtosis and KS test
analyze_polarization <- function(object, race) {
  obj_data <- data %>% 
    filter(Political_Object == object, Race == race) %>%
    select(Time, Positive, Sample_Size) %>%
    mutate(
      Positive_Count = round(Positive * Sample_Size / 100),
      Negative_Count = Sample_Size - Positive_Count
    )
  
  # Create full distribution
  before_dist <- c(rep(1, obj_data$Positive_Count[obj_data$Time == "B"]), 
                   rep(0, obj_data$Negative_Count[obj_data$Time == "B"]))
  after_dist <- c(rep(1, obj_data$Positive_Count[obj_data$Time == "A"]), 
                  rep(0, obj_data$Negative_Count[obj_data$Time == "A"]))
  
  # Calculate kurtosis
  K_before <- kurtosis(before_dist)
  K_after <- kurtosis(after_dist)
  
  # Perform KS test
  ks_result <- ks.test(before_dist, after_dist)
  
  tibble(
    Political_Object = object,
    Race = race,
    K_Before = K_before,
    K_After = K_after,
    K_Ratio = K_after / K_before,
    KS_Statistic = ks_result$statistic,
    KS_P_value = ks_result$p.value
  )
}

# Run analysis for all combinations of Political Object and Race
polarization_results <- crossing(
  Political_Object = unique(data$Political_Object),  # Use survey_data instead of data
  Race = unique(data$Race)
) %>%
  pmap_dfr(~analyze_polarization(..1, ..2))

# Display results
polarization_results %>%
  mutate(
    Significant = ifelse(KS_P_value < 0.05, "*", ""),
    K_Ratio = round(K_Ratio, 3),
    KS_P_value = format.pval(KS_P_value, digits = 3)
  ) %>%
  arrange(Race, desc(abs(K_Ratio - 1))) %>%
  knitr::kable(digits = 3, caption = "Kurtosis and KS Test Analysis: Before vs After MLK Assassination") %>%
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = F)
Kurtosis and KS Test Analysis: Before vs After MLK Assassination
Political_Object Race K_Before K_After K_Ratio KS_Statistic KS_P_value Significant
NAACP Black 1.500 4.008 2.672 0.161 0.2214
Democratic Party Black 2.786 5.410 1.942 0.084 0.4966
Police Black 7.125 1.123 0.158 0.303 0.0154
Black Black 4.924 7.782 1.580 0.045 0.7004
Richard Nixon Black 1.142 1.672 1.464 0.282 0.0588
White Black 1.796 1.005 0.559 0.186 0.1804
Republican Party Black 1.005 1.426 1.419 0.137 0.4157
National Politicians Black 1.050 1.426 1.358 0.211 0.1784
Lyndon Johnson Black 2.207 2.461 1.115 0.018 1.0000
National Politicians White 1.452 2.245 1.546 0.084 0.5900
Republican Party White 1.694 2.008 1.185 0.032 1.0000
White White 3.737 3.133 0.838 0.024 1.0000
Police White 6.410 5.584 0.871 0.014 1.0000
Democratic Party White 1.649 1.545 0.937 0.014 1.0000
Richard Nixon White 1.356 1.281 0.945 0.015 1.0000
Black White 1.071 1.114 1.041 0.017 1.0000
Lyndon Johnson White 1.040 1.081 1.040 0.021 1.0000
NAACP White 1.040 1.006 0.968 0.030 1.0000
# Visualization of kurtosis changes
ggplot(polarization_results, aes(x = reorder(Political_Object, K_Ratio), y = K_Ratio, fill = Race)) +
  geom_col(position = position_dodge()) +
  geom_text(aes(label = ifelse(KS_P_value < 0.05, "*", "")), 
            position = position_dodge(width = 0.9), 
            vjust = -0.5, size = 5) +
  coord_flip() +
  facet_wrap(~ Race, scales = "free_y") +
  labs(
    title = "Change in Kurtosis After MLK Assassination",
    subtitle = "Ratio of After/Before Kurtosis (> 1 indicates more extreme views)\n* indicates statistically significant change in distribution (KS test p < 0.05)",
    x = "Political Object",
    y = "Kurtosis Ratio (After / Before)",
    fill = "Race"
  ) +
  theme_minimal() +
  theme(legend.position = "none")