Australia Gun Control Experience

In 1996 Australia created the “National Firearms Agreement” (NFA) in which all the different territories agreed to unify their gun laws, many guns were banned for normal use based on various categories, license schemes were put in place for those who still continued to own the unbanned guns, and possibly the largest buyback in any country occurred where the governments confiscated around 650,000 firearms, most of which were pump action shotguns but also various semi-automatic rifles and shotguns, etc.

This occurred during a period when Australia had around 3.5 Million legally owned firearms country wide, in a population of about 18 Million people.

To evaluate what happened, we will first find various data sources, compile them together to give a picture of what data is available, and then analyze the data in the context of several potential models. The goal being to determine whether there is a clear-cut effect of banning firearms on crime statistics, and/or what one would find reasonable to believe quantitatively if one held various assumptions about the way firearms and crime interact.

There is simply not any definitive way to analyze this data. In the first place, the experiment took place in a time where many things were changing in Australia. So differentiating between those effects requires making assumptions about how they work. Furthermore, there was no control country, similar to australia in most respects, which did NOT implement a ban at the same time. The key to understanding the causal effect of gun bans is to understand that this causal effect is the difference between what did happen in the presence of the ban, and what would have happened if the ban were not implemented. For example, perhaps the ban occured and crime decreased… but our magic crystal ball tells us that they would have decreased even more if the ban had not occurred. In those kinds of circumstances, then the effect of the ban was to increase crime.

Similarly if the ban had not occurred, and crime decreased, but would have decreased even more with a ban, then the effect of the ban would have been to decrease crime.

Since inherently the question involves comparing something that did happen to an estimate of what would have happened if the world had been different, we need methods to predict what would have happened, and such methods always rely on some assumptions. The only way to address this question fairly is to address a range of possible models for what might have happened if Australia had not enacted the NFA.

We begin with setting up the tools we need and collecting the data.

using Pkg
Pkg.activate(".")

using CSV,DataFrames,Downloads,DataFramesMeta, StatsPlots, XLSX, 
    Dates, Statistics, Turing, LinearAlgebra, Interpolations, Serialization, Logging

disable_logging(Logging.Warn)

include("utilities.jl")

getifnotthere("./data/australia-homicides.xlsx","https://www.aic.gov.au/sites/default/files/2022-03/homicideincidents1989-90to2019-20_0.xlsx")
getifnotthere("./data/australia-suicides.xlsx","https://www.aihw.gov.au/getmedia/47de5d8a-b550-4df2-b938-d9bf3f6cd3e3/2020-aihw-suicide-and-self-harm-monitoring-nmd-suicide-icd-10-x60-x84-y87-0.xlsx.aspx")

# a pdf of a report breaking down homicide information including by type of firearm
getifnotthere("./data/aussie-homicide-report.pdf", "https://www.aic.gov.au/sites/default/files/2020-05/tandi075.pdf")

# data on fatal road crashes, for use in control for risk taking behavior etc
# see https://data.gov.au/dataset/ds-dga-5b530fb8-526e-4fbf-b0f6-aa24e84e4277/details?q=australian%20road%20deaths%20database

getifnotthere("./data/aussie-crash-data.csv", "https://data.gov.au/data/dataset/5b530fb8-526e-4fbf-b0f6-aa24e84e4277/resource/d54f7465-74b8-4fff-8653-37e724d0ebbb/download/ardd_fatal_crashes_jun2022.csv")

getifnotthere("./data/australia-population.xlsx","https://www.abs.gov.au/statistics/people/population/national-state-and-territory-population/dec-2021/310104.xlsx")

ozpop = DataFrame(XLSX.readtable("./data/australia-population.xlsx",2; first_row=10)...)
rename!(ozpop,[Symbol("Series ID") => :date, :A2060842F => :TotPop])
@select!(ozpop,:date,:TotPop)
ozpop.date = Date.(ozpop.date)
@transform!(ozpop,:year = year.(:date))
ozpop = @by(ozpop,:year,:TotPop = mean(:TotPop))


const NFAyear = 1996
  Activating project at `~/Consulting/LakelandAppliedSciLLC/CriminologyGuns`
1996

Crime data

Australia has collected various crime data extending back to the 1990’s. Apparently there were two separate datasets, but these were consolidated recently into a single long time series dataset.

The data can be found here and was copy and pasted into the files below because the data appears to be embedded in the page via javascript or something similar rather than actually separately downloadable with links. Nevertheless, the data files included in the data directory are the csv files published by Australia’s government that were downloaded by clicking the download links.

# data from https://www.abs.gov.au/articles/27-years-recorded-crime-victims-data
# this can't actually be downloaded from these URLs unfortunately but if you go to the above URL
# you can manually verify the data I downloaded by hand

getifnotthere("./data/australia-homicide-and-related.csv","https://www.abs.gov.au/b1067eb4-bf73-4a86-86d0-b4d973df6b5c")
getifnotthere("./data/australia-assault.csv","https://www.abs.gov.au/4a75956d-b1d0-4dda-a5a6-ef5946f51ddf")
getifnotthere("./data/australia-sex-assault.csv","https://www.abs.gov.au/b6bdbf80-4be1-40aa-9100-a3e306d38175")
getifnotthere("./data/australia-robbery.csv","https://www.abs.gov.au/00cf1a97-d00e-4be2-8a75-aacdd9a6a24b")
getifnotthere("./data/australia-entry-w-intent.csv","https://www.abs.gov.au/9029832b-f956-4e53-8c99-54b3a464dcd1")
getifnotthere("./data/australia-motor-vehicle-theft.csv","https://www.abs.gov.au/ae6584de-a07c-452e-b1ce-afacaa79fb54")
getifnotthere("./data/australia-other-theft.csv","https://www.abs.gov.au/3c9ad1bc-d611-4161-9907-6b2dfde7cf07")

Let’s start with the history of Crime Rates

Using the Australia crime data above, we can first take a look at what happened to various crimes through time.

function readauscsv(file; footerskip = 2)
    dat = CSV.read(file, DataFrame; skipto=3, footerskip = footerskip)
    rename!(dat,[:year,:data])
    dat
end

function plotdat(df; etc...)
    @df df plot(:year,:rate; etc...)
    p = plot!([NFAyear,NFAyear],[0.0,maximum(df.rate) * 1.25]; label="NFA Year")
    display(p)
    p
end

homreldat = @chain readauscsv("./data/australia-homicide-and-related.csv") begin
    leftjoin(ozpop,on=:year)
    @transform(:rate = :data ./ :TotPop .* 100e3)
end

assaultdat = @chain CSV.read("./data/australia-assault.csv",DataFrame;skipto=3,header=2,footerskip=4) begin
    rename!([1=>:year])
    DataFramesMeta.stack(Not(:year))
    rename!([:variable=>:territory])
    @rtransform(:rate = ismissing(:value) ? missing : typeof(:value) == Float64 ? :value : tryparse(Float64,replace(:value, r"," => "")))
end


sexassaultdat = @chain readauscsv("./data/australia-sex-assault.csv"; footerskip=4) begin @transform(:rate = :data) end

robberydat = @chain readauscsv("./data/australia-robbery.csv") begin @rtransform(:rate = tryparse(Float64, replace(:data,r"," => ""))) end

entryintentdat = @chain readauscsv("./data/australia-entry-w-intent.csv") begin 
    @rtransform(:rate = tryparse(Float64,replace(:data,r"," => ""))) 
end

mvtheftdat = @chain readauscsv("./data/australia-motor-vehicle-theft.csv") begin
    @rtransform(:rate = tryparse(Float64,replace(:data,r"," => "")))
end


othertheftdat = @chain readauscsv("./data/australia-other-theft.csv") begin
    @rtransform(:rate = tryparse(Float64,replace(:data,r"," => "")))
end


plotdat(homreldat; title="Australia Homicide and Related")

@df assaultdat plot(:year, :rate; group = :territory,legend=:topleft,title="Assault rates by territory")
p = plot!([NFAyear,NFAyear],[0.0,3500.0]; label="NFA year",color="red")
display(p)

plotdat(sexassaultdat; title="Australia Sex Assault", ylab="per 100k/yr")
plotdat(robberydat; title="Australia Robbery", ylab="per 100k/yr")
plotdat(entryintentdat; title="Australia Entry with Intent", ylab="Count/yr")
plotdat(mvtheftdat; title= "Australia Vehicle Theft", ylab="Count/yr")
plotdat(othertheftdat; title="Australia Other Theft", ylab="Count/yr")
nothing

The apparent situation

Post 1996 ban, apparently crime in most categories increased for several years, until shortly after 2000 when many forms of crime began an exponential plummet…

What happened around the year 2000? One critically important fact is that Australia began a huge increase in GDP/capita, nearly tripling the quantity as measured in constant current US dollars. The World Bank provides this information. As best as I can tell, this increase was caused largely by providing the raw materials such as iron ore and coal to fuel China’s economic growth through the 2000-present time period.

getifnotthere("./data/australia-gdp-per-capita.csv.zip","https://api.worldbank.org/v2/en/indicator/NY.GDP.PCAP.CD?downloadformat=csv")
cd("data")
if ! Base.Filesystem.ispath("API_NY.GDP.PCAP.CD_DS2_en_csv_v2_4251004.csv")
    run(`unzip ./australia-gdp-per-capita.csv.zip`)
end
cd("..")

gdp = CSV.read("data/API_NY.GDP.PCAP.CD_DS2_en_csv_v2_4251004.csv",DataFrame; header=5,skipto=6)
rename!(gdp,[Symbol("Country Name") => :country, Symbol("Country Code") => :ccode])

ausgdp = @subset(gdp,:country .== "Australia")
ausgdp = DataFramesMeta.stack(ausgdp,Not([:country,:ccode,Symbol("Indicator Name"),Symbol("Indicator Code")]))
rename!(ausgdp,[:variable => :year, :value => :gdppcap])
ausgdp = @chain ausgdp begin @transform(:year = tryparse.(Int64,:year)) 
    @subset(typeof.(:year) .== Int64)
end


@df ausgdp plot(:year,:gdppcap,title="Australia GDP/capita Constant 2022 Dollars",legend=:topleft)
plot!([NFAyear,NFAyear],[0.0,70e3],label="NFA year")

It is reasonable to believe that crime rates are affected by several important considerations

  • Motive. Important motives for many crimes are economic, with the goal of acquiring someone elses property or anger about failure to repay loans etc.
  • Probability of being caught.
  • Probability of being met with armed resistance.
  • Severity of punishment if caught
  • Relative attractiveness of alternatives (such as finding a well paid job)

When economic conditions improve rapidly, not only can many people improve on their day to day income and ability to afford to purchase things they need or want, but also when things improve rapidly, waiting a short while until those improvements can be realized becomes more attractive compared to a situation where things remain static or even decline during a recession.

This suggests a model in which the level of various crimes is predicted as a difference equation, with next years value being the same as the current years value, plus some change in the direction of an equilibrium value predicted by the current level of GDP, guns, and gun owners. In addition to the current levels, we also can include the rate of change of those predictors, as when for example GDP/capita increases rapidly, many more people may choose to move away from crime towards some lower risk activity, and/or when gun owners decrease rapidly, criminals may become aware of this and choose these times to commit crimes in relative safety, or alternatively, guns may become harder to acquire and enforcement increases, so gun crimes may decrease.

First we will set up a model, and a dataset to analyze

include("ausmodel.jl")

modeldata = leftjoin(homreldat,ausgdp, on=:year)
rename!(modeldata,[:rate => :homrate])
modeldata = leftjoin(modeldata,sexassaultdat; on = :year,makeunique=true)
rename!(modeldata,[:rate => :sexassaultrate])
modeldata = leftjoin(modeldata,robberydat; on = :year,makeunique=true)
rename!(modeldata,[:rate => :robberyrate])
modeldata = leftjoin(modeldata,entryintentdat; on = :year,makeunique=true)
rename!(modeldata,[:rate => :entryrate])
modeldata = leftjoin(modeldata,mvtheftdat; on = :year,makeunique=true)
rename!(modeldata,[:rate => :mvtheftrate])
modeldata = leftjoin(modeldata,othertheftdat; on = :year,makeunique=true)
rename!(modeldata,[:rate => :theftrate])
modeldata = leftjoin(modeldata,ozpop; on = :year, makeunique=true)
@select!(modeldata,:year,:TotPop,:homrate,:gdppcap,:sexassaultrate,:robberyrate,:entryrate,:mvtheftrate,:theftrate)

modeldata = @orderby(modeldata, :year)

# now, how many guns are there in AU, and how many licensed owners?

## to get this data I relied on https://www.gunpolicy.org/firearms/region/australia#number_of_licensed_firearm_owners

# The survey is not carried out each year, so I linearly interpolate the data between surveys

auguns = CSV.read("data/AUGunCounts.csv",DataFrame; header=2)
auguns.guns = Vector{Float64}(auguns.guns)
auguns = @orderby(auguns,:year)
interpg = LinearInterpolation(auguns.year,auguns.guns)


augunowners = CSV.read("data/AUGunOwners.csv",DataFrame; header=2)
augunowners.gunowners = Vector{Float64}(augunowners.gunowners)
augunowners = @orderby(augunowners,:year)
interpgo = LinearInterpolation(augunowners.year,augunowners.gunowners)

modeldata.guns = [interpg(y) for y in modeldata.year]
modeldata.gunowners = [interpgo(y) for y in modeldata.year]
27-element Vector{Float64}:
      1.7905e6
      1.642875e6
      1.49525e6
      1.347625e6
      1.2e6
      1.0911295e6
 982259.0
 873388.5
 764518.0
 707279.6000000001
 650041.2
 592802.8
 535564.4
      ⋮
 778919.6666666666
 826272.3333333333
 873625.0
 734000.0
 730000.0
 755762.0
 781524.0
 823360.0
 848219.0
 869077.0
 873432.0
 864214.0

What happened to Gun ownership

Let’s first see how many guns and gun owners Australia has had in the last few decades.

let p = plot(modeldata.year,modeldata.guns ./ 1e6; title="Gun count in AU (millions)", legend=false, ylim=[0.0,4.0])
    p = plot!([NFAyear,NFAyear],[0.0,4.0]; color="red")
    display(p)

    p = plot(modeldata.year,modeldata.gunowners ./ 1e6; title="Gun owner count in AU (millions)", legend=false, ylim=[0.0,2.0])
    p = plot!([NFAyear,NFAyear],[0.0,2]; color="red")
    display(p)
end

As can be seen, Australia started out with around 3.5M guns, the total number plummeted after implementing the NFA buyback, and then after about 2000 grew over the next 20 years or so back to approximately its original value. However, gun ownership declined rapidly post 1996 and recovered somewhat but is approximately 45% of what it was at the beginning of the data collection period.

## fill in 2 missing values for 1993, 1994 as same as 1995 data
modeldata[1,:theftrate] = 490527.0
modeldata[2,:theftrate] = 490527.0

rawdata = copy(modeldata) # save the unnormalized data

# Normalize all the data by the value at the beginning of the period (in 1993)
for n in Iterators.drop(names(modeldata),1)
    setproperty!(modeldata,n,Vector{Float64}(getproperty(modeldata,n)))
    setproperty!(modeldata,n, getproperty(modeldata,n) ./ getproperty(modeldata,n)[1])

end

display(modeldata)


theaumod = ausmodel(modeldata.year,modeldata.gdppcap, modeldata.guns, modeldata.gunowners,
    modeldata.TotPop, modeldata.homrate, modeldata.sexassaultrate, 
    modeldata.robberyrate, modeldata.entryrate, modeldata.mvtheftrate,
    modeldata.theftrate)


savedfile = "./saved/ausamples.dat"
global ausamp = []
if stat(savedfile).mtime > stat("./ausmodel.jl").mtime
    global ausamp = deserialize(savedfile)
else
    global ausamp = sample(theaumod,NUTS(500,0.8),MCMCThreads(),500,3)
    serialize(savedfile,ausamp)
end

27 rows × 11 columns (omitted printing of 3 columns)

yearTotPophomrategdppcapsexassaultraterobberyrateentryratemvtheftrate
Int64Float64Float64Float64Float64Float64Float64Float64
119931.01.01.01.01.01.01.0
219941.009670.9350061.023331.034731.094070.9940381.06221
319951.021110.9231281.152321.053551.140991.008991.13003
419961.033480.9523381.239831.15631.282291.053161.09285
519971.044490.9326771.330681.131691.668911.104211.15705
619981.055160.9762781.208231.141821.864491.13761.16982
719991.066851.001891.163681.130251.770741.088931.15187
820001.07921.005051.228141.247471.82761.144551.23511
920011.092971.061961.105291.319832.082711.141361.24382
1020021.105530.9940851.138711.389291.644081.032841.00877
1120031.11820.8955741.329721.322721.543670.9272730.873951
1220041.130440.7818071.727151.392191.293260.8085010.781848
1320051.144560.7207721.929061.341531.345270.7386240.71456
1420061.160970.6945192.044331.38351.360850.6862670.670185
1520071.182080.6457012.320751.38641.409340.6508250.627845
1620081.206560.6278462.810571.361791.293490.6332340.606924
1720091.230720.6166842.421631.263391.194330.5833470.52429
1820101.249490.5281942.948291.238781.146240.5450690.487401
1920111.267760.5318973.541831.20551.069160.5478140.49856
2020121.290020.4993633.850521.238781.030860.5631710.520654
2120131.3120.4745953.857811.253260.9172870.5095280.466854
2220141.331760.4557033.538291.279310.7748880.4764280.446173
2320151.351090.4438743.209741.33430.7024360.4819680.458114
2420161.372710.4734632.823411.379160.7372130.4944090.498328
2520171.395110.442213.052791.520980.7513120.4617440.466258
2620181.416520.3818443.236551.525330.7928250.4401720.474109
2720191.437860.4150913.106061.534010.92230.4540380.515871
Chains MCMC chain (500×83×3 Array{Float64, 3}):
Iterations        = 1:1:500
Number of chains  = 3
Samples per chain = 500
parameters        = bnecoefs[1], bnecoefs[2], bnecoefs[3], bnecoefs[4], bnecoefs[5], bnecoefs[6], bnecoefs[7], err, f, homcoefs[1], homcoefs[2], homcoefs[3], homcoefs[4], homcoefs[5], homcoefs[6], homcoefs[7], rapecoefs[1], rapecoefs[2], rapecoefs[3], rapecoefs[4], rapecoefs[5], rapecoefs[6], rapecoefs[7], robcoefs[1], robcoefs[2], robcoefs[3], robcoefs[4], robcoefs[5], robcoefs[6], robcoefs[7], stuff[1], stuff[2], stuff[3], stuff[4], stuff[5], stuff[6], stuff[7], stuff[8], stuff[9], stuff[10], stuff[11], stuff[12], stuff[13], stuff[14], stuff[15], stuff[16], stuff[17], stuff[18], stuff[19], stuff[20], stuff[21], stuff[22], stuff[23], stuff[24], stuff[25], stuff[26], stuff[27], theftcoefs[1], theftcoefs[2], theftcoefs[3], theftcoefs[4], theftcoefs[5], theftcoefs[6], theftcoefs[7], vehthcoefs[1], vehthcoefs[2], vehthcoefs[3], vehthcoefs[4], vehthcoefs[5], vehthcoefs[6], vehthcoefs[7]
internals         = acceptance_rate, hamiltonian_energy, hamiltonian_energy_error, is_accept, log_density, lp, max_hamiltonian_energy_error, n_steps, nom_step_size, numerical_error, step_size, tree_depth
Summary Statistics
    parameters      mean       std   naive_se      mcse         ess      rhat 
        Symbol   Float64   Float64    Float64   Float64     Float64   Float64 
   bnecoefs[1]   -0.2157    0.3486     0.0090    0.0137    569.4866    1.0068
   bnecoefs[2]   -2.7035    1.8524     0.0478    0.0787    493.7484    1.0031
   bnecoefs[3]   -1.7673    3.0002     0.0775    0.1062    717.9328    1.0027
   bnecoefs[4]   -5.4889    2.7891     0.0720    0.0701   1708.8772    0.9994
   bnecoefs[5]    2.5897    2.4194     0.0625    0.0789    909.7750    1.0019
   bnecoefs[6]   -3.4886    4.3556     0.1125    0.0955   1888.3949    1.0001
   bnecoefs[7]   -0.4577    0.7742     0.0200    0.0279    796.5096    1.0006
           err    0.0671    0.0047     0.0001    0.0002    837.1023    1.0020
             f    0.1036    0.0126     0.0003    0.0007    359.6251    1.0075
   homcoefs[1]   -0.6497    0.4138     0.0107    0.0149    722.5560    0.9991
   homcoefs[2]   -4.0840    2.0651     0.0533    0.0753    711.0860    0.9998
   homcoefs[3]   -1.6749    3.2719     0.0845    0.0938   1071.6925    0.9994
   homcoefs[4]   -3.3173    3.4202     0.0883    0.0740   1954.5908    0.9988
   homcoefs[5]    1.3144    2.7078     0.0699    0.0720   1175.7189    0.9997
   homcoefs[6]   -2.3114    4.6067     0.1189    0.0990   1906.4600    0.9986
   homcoefs[7]    0.8308    0.7599     0.0196    0.0195   1354.2688    0.9985
  rapecoefs[1]   -0.0693    0.0755     0.0019    0.0018   1212.6887    1.0002
  rapecoefs[2]   -1.1095    0.3256     0.0084    0.0105    957.2328    1.0009
  rapecoefs[3]    2.0927    1.0765     0.0278    0.0381    899.1670    1.0021
  rapecoefs[4]    2.2047    2.3136     0.0597    0.0498   2192.6915    0.9985
  rapecoefs[5]   -2.1099    0.9816     0.0253    0.0315    902.8295    1.0009
  rapecoefs[6]   -4.0798    2.6453     0.0683    0.0664   1529.6058    1.0004
  rapecoefs[7]   -0.0369    0.3802     0.0098    0.0124   1182.5614    1.0009
       ⋮            ⋮         ⋮         ⋮          ⋮          ⋮          ⋮
                                                                48 rows omitted
Quantiles
    parameters       2.5%     25.0%     50.0%     75.0%     97.5% 
        Symbol    Float64   Float64   Float64   Float64   Float64 
   bnecoefs[1]    -1.0831   -0.4063   -0.1578    0.0277    0.3296
   bnecoefs[2]    -7.0735   -3.7648   -2.3577   -1.3315   -0.0904
   bnecoefs[3]    -7.1270   -3.9145   -1.9516    0.2061    4.4838
   bnecoefs[4]   -10.6051   -7.2343   -5.5379   -3.8299    0.4358
   bnecoefs[5]    -2.2760    1.0097    2.7043    4.1506    7.2064
   bnecoefs[6]   -12.4099   -6.4387   -3.4972   -0.6027    4.9074
   bnecoefs[7]    -2.0740   -0.9296   -0.4197    0.0926    0.9380
           err     0.0590    0.0637    0.0668    0.0700    0.0775
             f     0.0802    0.0951    0.1028    0.1110    0.1308
   homcoefs[1]    -1.6095   -0.9005   -0.5933   -0.3336   -0.0113
   homcoefs[2]    -8.6450   -5.3143   -3.8407   -2.6109   -0.7950
   homcoefs[3]    -7.9779   -3.9783   -1.7285    0.6721    4.5944
   homcoefs[4]    -9.5273   -5.6431   -3.6703   -1.3414    3.7770
   homcoefs[5]    -3.8638   -0.5612    1.3411    3.2135    6.5462
   homcoefs[6]   -11.4155   -5.3782   -2.1863    0.9548    6.2533
   homcoefs[7]    -0.6183    0.3493    0.8115    1.3058    2.4157
  rapecoefs[1]    -0.2290   -0.1149   -0.0641   -0.0175    0.0681
  rapecoefs[2]    -1.8357   -1.3009   -1.0860   -0.8806   -0.5403
  rapecoefs[3]     0.0315    1.3876    2.0713    2.8008    4.1819
  rapecoefs[4]    -1.7624    0.5533    2.0799    3.6852    7.3761
  rapecoefs[5]    -4.0341   -2.7634   -2.0878   -1.4624   -0.1827
  rapecoefs[6]    -9.8072   -5.7089   -3.9919   -2.2791    0.6549
  rapecoefs[7]    -0.7464   -0.3048   -0.0368    0.2238    0.7127
       ⋮            ⋮          ⋮         ⋮         ⋮         ⋮
                                                    48 rows omitted

What does the model suggest?

Let’s look at each of the major crimes. In the model we linearly predict the “next year” rates from the current year predicted rates, and some fraction f of the difference between the predicted equilibrium value (from a linear model) and the current value. In other words, if f is 0.1 then the rate would move 10% of the way towards the predicted value in each year. As the predictors change, each year the “set point” changes and the prediction “chases” these values with a kind of “drag” that prevents it from moving all at once. This results in the time series.

Each different crime rate is predicted in a linear model as \[ \exp(coefs \cdot predictors)\] with the predictors being:

  • GDP/capita
  • d/dt (GDP/capita)
  • Guns/capita
  • d/dt (Guns/capita)
  • Gun Owners/Capita
  • d/dt (Gun Owners/Capita)
  • 1.0

With 1.0 acting as a constant offset. Because we’ve normalized these values to their value at the beginning of the time series, they are all O(1) and we use a Normal(0.0,5.0) prior for all coefficients, as exp(5) ~ 148 which would be an enormous change from the original values, so we expect that coefficients outside that range are incompatible with the real world values which stay O(1). However we do allow symmetry in the predictions on the log scale, meaning, a-priori increasing or decreasing crime is equally likely for each of the predictors.

Let’s look at robbery:

p = density(getcoefsrename(ausamp,:robcoefs))
display(p)



p = plot(modeldata.year,modeldata.robberyrate; linewidth=3, legend=false, title="AU Robbery relative change\n Actual and Predicted")
for i in sam
    p = plot!(modeldata.year,gquan[i,1].prob; alpha=.5)
end
display(p)

How about the coefficients for the other major crimes?

p = density(getcoefsrename(ausamp,:rapecoefs))
display(p)
p = density(getcoefsrename(ausamp,:bnecoefs))
display(p)
p = density(getcoefsrename(ausamp,:vehthcoefs))
display(p)
p = density(getcoefsrename(ausamp,:theftcoefs))
display(p)

p = density(group(ausamp,:f))
display(p)

p = density(group(ausamp,:err))
display(p)

Suicide

The story when it comes to suicides in Australia and the NFA affect seems to be fairly straightforward. Starting around 1990 an organic trend occurred where suicides by firearm dropped on their own as they were replaced with suicide by hanging. Around the time of the NFA itself, the number of hangings spiked upwards in the immediate year or two after the NFA buyback, and then declined for a few years until hangings took off again. Overall across these two methods, suicides trended upwards in the years after the NFA as firearm method declined but hangings increased at an even greater rate.

To the extent that suicides overall, including other methods, have declined, it’s primarily because suicide by “gas” has declined dramatically starting in about 1999.

suicdata = DataFrame(XLSX.readtable("data/australia-suicides.xlsx",5; first_row = 2)...)
suicdata = DataFramesMeta.stack(suicdata,Not([1,2,3]))
rename!(suicdata,Dict(:variable => :year,:value => :suicrate))
suicdata.suicrate = map(x -> if typeof(x) == Float64 x else missing end, suicdata.suicrate)
suicdata.year = map(x -> begin y = tryparse(Int64,x);  y; end, suicdata.year) 
@subset!(suicdata,:Measure .== "Age-standardised rate (per 100,000)")

suicall = @subset(suicdata,:Sex .== "Persons")

pl = @df suicall plot(:year,:suicrate; group = :Mechanism, title= "Suicide in Australia", ylab="Rate/100k", legend=:topleft)


@df @subset(suicall,:year .>= 1950) plot(:year,:suicrate; group = :Mechanism,xlim=(1950,2040),size=(800,800),title="Australia Suicides")
display(plot!([1996,1996],[0,15],color="red",label="NFA year"))



suicmeth = @transform(unstack(@select(suicdata,:Mechanism,:year,:suicrate),:Mechanism,:suicrate; allowduplicates=true),:gunhang = :Firearms + :Hanging)

let p1 = [], p2 = []

    p1 = @df suicmeth plot(:year,:Firearms; label = "Firearms", title = "Suicide in Australia by Method",legend=:topleft)
    @df suicmeth plot!(:year,:Hanging; label = "Hanging")
    @df suicmeth plot!(:year,:gunhang; label = "Firearms + Hanging")
    plot!([NFAyear,NFAyear],[0.0,10.0]; label = "NFA Year", color = "purple", alpha=0.5)

    p2 = @df suicmeth plot(:year,:Gas; title = "Suicide by Gas Rate", legend=:topleft, label="Suicide by Gas")

    display(plot(p1,p2,layout = @layout([a{.8h};b{0.2h}])))
end