ccao-data / ptaxsim

R package for estimating Cook County property tax bills
https://ccao-data.github.io/ptaxsim/
GNU Affero General Public License v3.0
11 stars 2 forks source link

Add tax share vignette #7

Open dfsnow opened 1 year ago

dfsnow commented 1 year ago

Original issue:

Please add the ability to easily calculate each property's tax price (See this paper for an explanation of tax price). This could be achieved by adding a new tax_price() function to the package, or adding tax price or agency tax base to the tax_bill() function output.

Not sure that a separate argument/function just for tax share is warranted, but I think it would be great to add a vignette using it as a technique to decompose a tax bill (or area).

erhla commented 1 year ago

I think that this may make more sense to include this in #5 instead of building out any separate functionality. For example, the tidy code below calculates the various tax price information.


  #tax price https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3888468
  library(ptaxsim)
  library(tidyverse)
  ptaxsim_db_conn <- DBI::dbConnect(RSQLite::SQLite(), "../bor/ptaxsim.db")

  year_vec <- c(2010:2020)
  pin_vec <- c('13131270050000', '20111040491005')

  bills <- ptaxsim::tax_bill(
    append(year_vec, min(year_vec) - 1), #grab one year back for lagged values
    pin_vec,
    simplify = FALSE)

  rslt <- bills %>%
    mutate(eav_exempt = eav - exe_total,
           tax_share = eav_exempt / agency_total_eav) %>%
    select(year, pin, tax_share, agency_num,
           agency_total_ext, final_tax_to_dist) %>%
    group_by(pin, agency_num) %>%
    mutate(
      lag_year = lag(year),
      lag_agency_total_ext = lag(agency_total_ext),
      lag_tax_share = lag(tax_share),
      lag_final_tax_to_dist = lag(final_tax_to_dist)
    ) %>%
    ungroup() %>%
    mutate(
      #est change due to changes in tax share
      tax_share_effect = (tax_share - lag_tax_share) * lag_agency_total_ext,
      #est change due to changes in taxing district extensions
      tax_ext_effect = (agency_total_ext - lag_agency_total_ext) * lag_tax_share,
      #actual change
      tax_bill_change = final_tax_to_dist - lag_final_tax_to_dist
    ) %>%
    filter(year > min(year), !is.na(lag_year)) %>% #drop new taxing districts
    group_by(pin, year) %>%
    #summarize for all taxing districts
    summarize(
      tax_share_effect = sum(tax_share_effect),
      tax_ext_effect = sum(tax_ext_effect),
      tax_change_est = tax_share_effect + tax_ext_effect,
      actual_tax_change = sum(tax_bill_change),
      pct_change_tax_share = sum(tax_share - lag_tax_share) / sum(lag_tax_share),
      pct_change_ext = sum(agency_total_ext - lag_agency_total_ext) / sum(lag_agency_total_ext),
      pct_change_tax_liability_estimate = pct_change_tax_share + pct_change_ext,
      pct_change_tax = actual_tax_change / sum(lag_final_tax_to_dist),
      final_tax = sum(final_tax_to_dist)
    )

  #example graph from paper

  rslt %>% select(pin, year, tax_share_effect, tax_ext_effect) %>%
    pivot_longer(!c(pin, year)) %>%
    ggplot(aes(x=`year`, y=`value`, fill=`name`)) +
    geom_bar(stat='identity', position='stack') +
    scale_x_continuous(breaks= scales::pretty_breaks()) +
    theme_bw() +
    facet_wrap(~pin) +
    labs(x='Year', y='Nominal Change in Estimated Taxes', title='Decomposed Actual Changes') +
    theme(legend.position = 'bottom')
erhla commented 1 year ago

image

dfsnow commented 1 year ago

@erhla Nice work! Now that I see what's involved, I'm not sure that just adding tax_share warrants changes to tax_bill(). That said, I'd love to see a vignette that breaks down levies vs base using tax share. I think that's actually separate from #5 (which is more about PTELL and inflation). I'm going to amend this issue to focus on the vignette. Would love to see a PR if you have the time.