Gun Laws vs Death Rates

It turns out that Wikipedia has a page on firearm death rates by state. That page has a nice little table for death rates per 100,000 population in 2013. Furthermore, there is also a page on gun laws per state.

Let's do something stupidly simple: Let's count up the gun laws in each state, and compare it to the firearm death rates.

This is obviously a very flawed metric, but it serves as a good initial sanity check. I expect there to be a pretty strong negative relation - the more gun control laws, the less gun-related deaths. If that is found, then sanity check passed, and barring more in-depth research showing otherwise, I can accept that adding gun control laws could plausibly decrease the gun death rate.

Scraping the wikipedia articles turns out to be surprisingly easy using pandas:

In [107]:
import pandas as pd

# Read the tables from the wikipedia page, and return the second one (index 1), which corresponds to the
# gun death rate per state.
gun_death_rate = pd.read_html("https://en.wikipedia.org/wiki/Firearm_death_rates_in_the_United_States_by_state",
             header=0,
             attrs={"class": ["sortable","wikitable", "plainrowheaders"]})[1]

# Read the tables from the gun laws wikipedia page, and return the 51 tables corresponding to the gun laws
# in each state, plus the district of columbia
per_state_gun_laws = pd.read_html("https://en.wikipedia.org/wiki/Gun_laws_in_the_United_States_by_state",header=0)[1:-7]

Now we combine the two datasets by just counting the laws per state:

In [113]:
# Let's extract the number of restrictions (ie, count the number of laws) for each state
number_of_restrictions_per_state = []
for state_laws in per_state_gun_laws:
    # Everywhere there is a "Yes", we say that there is an additional restriction,
    # except for the "open carry" row, which is reversed, disallowing open carry is
    # a restriction
    open_carry_row = (state_laws[state_laws["Subject/Law"].str.contains("Open carry|Open Carry")].index[0])
    
    handgun_restrictions = (state_laws["Handguns"].str.contains("Yes") 
                            + 0.5*state_laws["Handguns"].str.contains("Partial"))
    handgun_restrictions[open_carry_row] = 1 - handgun_restrictions[open_carry_row]
    
    # Annoyingly, wikipedia uses two different table headings
    try:
        longgun_restrictions = (state_laws["Long Guns"].str.contains("Yes")
                                + 0.5*state_laws["Long Guns"].str.contains("Partial"))
    except:
        longgun_restrictions = (state_laws["Long guns"].str.contains("Yes")
                                + 0.5*state_laws["Long guns"].str.contains("Partial"))
        
    longgun_restrictions[open_carry_row] = 1 - longgun_restrictions[open_carry_row]
    
    number_of_restrictions_per_state.append(handgun_restrictions.sum() + longgun_restrictions.sum())

# Thankfully the states are alphabetical in both wikipedia pages, so they match up without any more work.
# We just need to remove the district of columbia (8th element, 0-indexed)
del number_of_restrictions_per_state[8]
full_dataset = gun_death_rate.assign(Laws=number_of_restrictions_per_state)

# Now a bit of cleanup:
# Winsconsin has a weird table, which we need to fix manually
full_dataset.loc[full_dataset["State"]=="Wisconsin","Laws"] += 3

full_dataset
Out[113]:
StateRateLaws
0Alabama17.793.0
1Alaska19.594.0
2Arizona14.203.0
3Arkansas16.936.0
4California7.8921.0
5Colorado11.7513.0
6Connecticut4.4816.0
7Delaware10.808.0
8Florida12.495.0
9Georgia12.633.0
10Hawaii2.7113.0
11Idaho14.082.0
12Illinois8.6716.0
13Indiana13.049.0
14Iowa8.198.0
15Kansas11.442.0
16Kentucky14.155.0
17Louisiana19.153.0
18Maine11.894.0
19Maryland9.7510.0
20Massachusetts3.1814.0
21Michigan12.035.0
22Minnesota7.887.0
23Mississippi17.554.0
24Missouri14.564.0
25Montana16.945.0
26Nebraska8.995.0
27Nevada14.165.0
28New Hampshire7.032.0
29New Jersey5.6912.0
30New Mexico15.637.5
31New York4.3917.0
32North Carolina12.427.0
33North Dakota11.894.0
34Ohio11.146.0
35Oklahoma16.416.0
36Oregon11.768.0
37Pennsylvania11.369.0
38Rhode Island5.3312.0
39South Carolina15.604.0
40South Dakota9.473.0
41Tennessee15.867.0
42Texas10.508.0
43Utah11.6912.0
44Vermont10.372.0
45Virginia10.465.0
46Washington9.078.5
47West Virginia15.104.0
48Wisconsin9.937.0
49Wyoming17.512.0

So, let's plot it!

In [114]:
%matplotlib inline
import seaborn as sb

sb.regplot(x="Laws",y="Rate",data=full_dataset)
Out[114]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f15b06cc978>

Given the large negative correlation, unless research is sent to me with a more in-depth analysis of the issue, I can accept that it is very plausible1 that adding gun control laws would decrease the firearm death rate.


  1. Correlation does not imply causation.