Senate Inequality Beyond Framers' Frame of Reference

While the Framers of the American Constitution were “pretty smart,” they had no experience with the type of representational inequality of today’s Senate. The Gini index of representational inequality in the Senate was 0.342 in 1790 and was 0.506 in 2015, the latest date from the data. This is an enormous change—in the income inequality literature, a change of 0.03 is considered “salient.”1

Another way to think about this, rather than with the difficult to interpret Gini, is the “social tables” approach preferred by Piketty.2 This shows us that the 50% of the population with the least representation in the Senate had 28.6% of senators in 1790 and a shocking 17.2% in 2015.

This begs the question, what about a state needs representation?


Code

histstatepop.long <- histstatepop %>%
  tidyr::gather(key = "state", value = "pop", 2:ncol(histstatepop)) %>%
  dplyr::mutate(pop = as.numeric(pop)) %>%
  dplyr::mutate(senate.power = ifelse(state == "DC", 0, 2 / pop))

# help make an animated .gif
jpeg("/tmp/foo%02d.jpg")
# mark the progress
p <- dplyr::progress_estimated(n = ((2015-1790) + 1))
# count the time elapsed
start_time <- Sys.time()
  
for(year in 1790:2015) {
  curveLorenz.df <- histstatepop.long %>%
    dplyr::filter(Year == year, !is.na(pop)) %>%
    dplyr::arrange(senate.power) %>%
    dplyr::mutate(cumsum.pop = cumsum(pop),
         cumsum.senate.power = cumsum((senate.power * pop) / sum(senate.power * pop, na.rm = TRUE)),
         Rank = rank(cumsum.pop)) %>%
    dplyr::mutate(pop.max.ineq = ifelse(Rank == min(Rank), sum(pop), 1)) %>%
    dplyr::mutate(senate.power.max.ineq = ifelse(state == "DC", 0, 2 / pop.max.ineq))
  
  if(nrow(curveLorenz.df) >= 2) {
    gini <- reldist::gini(subset(curveLorenz.df$senate.power, !is.na(curveLorenz.df$senate.power)),
     weights = subset(curveLorenz.df$pop, !is.na(curveLorenz.df$senate.power)))
    gini.max.ineq <- reldist::gini(subset(curveLorenz.df$senate.power.max.ineq, !is.na(curveLorenz.df$senate.power)),
     weights = subset(curveLorenz.df$pop.max.ineq, !is.na(curveLorenz.df$senate.power)))
  
    if(year == 1790) {
      gini.df <- data.frame(Year = year,
                            Gini = gini,
                            GiniCeiling = gini.max.ineq)
    } else {
      gini.df <- rbind(gini.df,
                       data.frame(Year = year,
                                  Gini = gini,
                                  GiniCeiling = gini.max.ineq))
    }
    
    y.range <- max(gini.df$Gini) - min(gini.df$Gini)
    y.text <- min(gini.df$Gini) + (y.range / 10)
    
    gg <- ggplot() +
      geom_smooth(data = gini.df, 
                  aes(x = Year,
                   y = Gini),
                  color = "#4caf50",
                  fill = "#4caf50",
                  alpha = 0.75) +
      geom_point(data = gini.df, 
                  aes(x = Year,
                   y = Gini),
                   size = 2,
                 color = "#2b94c3",
                 alpha = 0.5) +
      # geom_smooth(data = gini.df,
      #             aes(x = Year,
      #              y = GiniCeiling),
      #             linetype = "dash") +
      coord_cartesian(xlim = c(1790, 2020), 
                      ylim = c(0, 1)) +
      theme_classic() +
      geom_label(aes(x = 1830, 
                        y = y.text), 
                    label = paste0("Gini Index of Senate Representation, ", year, ": ", 
                                   format(gini.df$Gini[gini.df$Year == year], 
                                          digits = 3, 
                                          nsmall = 3)), 
                    size = 5, 
                    hjust = -0.05)
  
    print(gg)
  }
  
#   
#   p <- ggplot() +
#   geom_point(data = curveLorenz.df[curveLorenz.df$Rank %% (max(curveLorenz.df$Rank) %/% 40) == 0, ],
#              aes(x = cumsum.pop,
#                  y = cumsum.senate.power),
#                  size = 2)
# 
# gg <- p +
#   geom_segment(aes(x = 0, y = 0, xend = 1, yend = 1), linetype = "dashed") +
#   geom_line(data = curveLorenz.df,
#             aes(x = cumsum.pop,
#                 y = cumsum.senate.power)) +
#   theme_classic() +
#   theme(text=element_text(size = 12, family = "serif")) +
#   theme(axis.text = element_text(color = "black")) +
#   labs(x = "p",
#        y = "L(p)") +
#   guides(size = FALSE, shape = guide_legend(override.aes = list(size = 2)))
# 
# print(gg)
# 
# # ggsave(filename = "_tabsandfigs/original-vs-jd-lorenz.svg", plot = gg)
  p$pause(0.01)$tick()$print()
}

for(i in 1:10) {
  print(gg)
  }
  
end_time <- Sys.time()
end_time - start_time
## Time difference of 13.43413 secs
dev.off()
## png 
##   2
system("ffmpeg -y -r 8 -i /tmp/foo%02d.jpg -qscale 2 featured.gif")
system("rm /tmp/foo*.jpg")
curveLorenz.df <- histstatepop.long %>%
    dplyr::filter(Year == 1790, !is.na(pop)) %>%
    dplyr::arrange(senate.power) %>%
    dplyr::mutate(cumsum.pop = cumsum(pop),
         cumsum.senate.power = cumsum((senate.power * pop) / sum(senate.power * pop, na.rm = TRUE)),
         Rank = rank(cumsum.pop)) %>%
    dplyr::mutate(pop.max.ineq = ifelse(Rank == min(Rank), sum(pop), 1)) %>%
    dplyr::mutate(senate.power.max.ineq = ifelse(state == "DC", 0, 2 / pop.max.ineq))

p50 <- max(curveLorenz.df$cumsum.pop) * 0.5
p90 <- max(curveLorenz.df$cumsum.pop) * 0.9
p95 <- max(curveLorenz.df$cumsum.pop) * 0.95
p99 <- max(curveLorenz.df$cumsum.pop) * 0.99

p50.share <- curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.5, weight = curveLorenz.df$pop)) - 1] + (curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.5, weight = curveLorenz.df$pop))] - curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.5, weight = curveLorenz.df$pop)) - 1]) * (p50 - curveLorenz.df$cumsum.pop[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.5, weight = curveLorenz.df$pop)) - 1]) / curveLorenz.df$pop[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.5, weight = curveLorenz.df$pop))]

p90.share <- curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.9, weight = curveLorenz.df$pop)) - 1] + (curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.9, weight = curveLorenz.df$pop))] - curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.9, weight = curveLorenz.df$pop)) - 1]) * (p90 - curveLorenz.df$cumsum.pop[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.9, weight = curveLorenz.df$pop)) - 1]) / curveLorenz.df$pop[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.9, weight = curveLorenz.df$pop))]

top10.share <- 1 - p90.share

p95.share <- curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.95, weight = curveLorenz.df$pop)) - 1] + (curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.95, weight = curveLorenz.df$pop))] - curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.95, weight = curveLorenz.df$pop)) - 1]) * (p95 - curveLorenz.df$cumsum.pop[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.95, weight = curveLorenz.df$pop)) - 1]) / curveLorenz.df$pop[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.95, weight = curveLorenz.df$pop))]

top5.share <- 1 - p95.share

p99.share <- curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.99, weight = curveLorenz.df$pop)) - 1] + (curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.99, weight = curveLorenz.df$pop))] - curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.99, weight = curveLorenz.df$pop)) - 1]) * (p99 - curveLorenz.df$cumsum.pop[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.99, weight = curveLorenz.df$pop)) - 1]) / curveLorenz.df$pop[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.99, weight = curveLorenz.df$pop))]

top1.share <- 1 - p99.share

social.table <- data.frame(Year = 1790, Fifty = p50.share, Forty = p90.share, Ten = top10.share, Five = top5.share, One = top1.share)



curveLorenz.df <- histstatepop.long %>%
    dplyr::filter(Year == 2015, !is.na(pop)) %>%
    dplyr::arrange(senate.power) %>%
    dplyr::mutate(cumsum.pop = cumsum(pop),
         cumsum.senate.power = cumsum((senate.power * pop) / sum(senate.power * pop, na.rm = TRUE)),
         Rank = rank(cumsum.pop)) %>%
    dplyr::mutate(pop.max.ineq = ifelse(Rank == min(Rank), sum(pop), 1)) %>%
    dplyr::mutate(senate.power.max.ineq = ifelse(state == "DC", 0, 2 / pop.max.ineq))

p50 <- max(curveLorenz.df$cumsum.pop) * 0.5
p90 <- max(curveLorenz.df$cumsum.pop) * 0.9
p95 <- max(curveLorenz.df$cumsum.pop) * 0.95
p99 <- max(curveLorenz.df$cumsum.pop) * 0.99

p50.share <- curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.5, weight = curveLorenz.df$pop)) - 1] + (curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.5, weight = curveLorenz.df$pop))] - curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.5, weight = curveLorenz.df$pop)) - 1]) * (p50 - curveLorenz.df$cumsum.pop[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.5, weight = curveLorenz.df$pop)) - 1]) / curveLorenz.df$pop[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.5, weight = curveLorenz.df$pop))]

p90.share <- curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.9, weight = curveLorenz.df$pop)) - 1] + (curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.9, weight = curveLorenz.df$pop))] - curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.9, weight = curveLorenz.df$pop)) - 1]) * (p90 - curveLorenz.df$cumsum.pop[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.9, weight = curveLorenz.df$pop)) - 1]) / curveLorenz.df$pop[which(curveLorenz.df$cumsum.senate.power == reldist::wtd.quantile(curveLorenz.df$cumsum.senate.power, q = 0.9, weight = curveLorenz.df$pop))]

top10.share <- 1 - p90.share

p95.share <- curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.95, weight = curveLorenz.df$pop)) - 1] + (curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.95, weight = curveLorenz.df$pop))] - curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.95, weight = curveLorenz.df$pop)) - 1]) * (p95 - curveLorenz.df$cumsum.pop[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.95, weight = curveLorenz.df$pop)) - 1]) / curveLorenz.df$pop[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.95, weight = curveLorenz.df$pop))]

top5.share <- 1 - p95.share

p99.share <- curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.99, weight = curveLorenz.df$pop)) - 1] + (curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.99, weight = curveLorenz.df$pop))] - curveLorenz.df$cumsum.senate.power[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.99, weight = curveLorenz.df$pop)) - 1]) * (p99 - curveLorenz.df$cumsum.pop[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.99, weight = curveLorenz.df$pop)) - 1]) / curveLorenz.df$pop[which(curveLorenz.df$cumsum.pop == reldist::wtd.quantile(curveLorenz.df$cumsum.pop, q = 0.99, weight = curveLorenz.df$pop))]

top1.share <- 1 - p99.share

social.table <- rbind(social.table,
                      data.frame(Year = 2015, Fifty = p50.share, Forty = p90.share, Ten = top10.share, Five = top5.share, One = top1.share))

social.table %>%
  tidyr::gather(-Year, key = "Group", value = "Share") %>%
  dplyr::mutate(Year = factor(Year),
                Group = factor(Group, 
                               levels = c("Fifty", "Forty", "Ten", "Five", "One"), 
                               labels = c("Bottom 50%", "Middle 40%", "Top 10%", "Top 5%", "Top 1%"))) %>%
  ggplot() +
  geom_col(aes(x = Group, y = Share, fill = Year), position = "dodge2") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("#4caf50", "#2b94c3")) +
  theme_classic()


  1. Atkinson (2015). https://www.hup.harvard.edu/catalog.php?isbn=9780674504769

  2. Piketty (2014), 246-270.

Edit this page

Avatar
Joseph de la Torre Dwyer
Researcher

My research interests include distributive justice; the principles of responsibility, desert, and control; and reproducible research with R.

Related