Calculations of income tax are rolling joins

Short introduction to ordinary income tax

library(knitr)
library(magrittr)
library(data.table)
library(hutils)
library(grattan)

Generally, income taxes are parmeterized by tax tables. In Australia, for the 2017-18 financial year, the table looks like

dollar <- function(x) paste0("$", prettyNum(x, big.mark = ","))
grattan:::tax_table2[fy_year == "2017-18",
                     .(`Lower bracket` = dollar(lower_bracket),
                       `Tax payable` = dollar(tax_at),
                       `Marginal rate` = marginal_rate)] %>%
  kable(align = "r")

To calculate the income tax for a given income find the next lowest value in the Lower bracket column, then add the tax payable and difference between the lower bracket value and the income multiplied by the marginal rate. Originally, we implemented it like this:

income <- 50e3
fy_year <- "2017-18"

ifelse(fy_year == '2017-18',
       ifelse(income < 18200,
              0,
              ifelse(income < 37e3,
                     0 + 0.19 * (income - 18200),
                     ifelse(income < 87e3,
                            3572 + 0.325 * (income - 37000),
                            ifelse(income < 180e3,
                                   19822 + 0.37 * (income - 87e3),
                                   54232 + 0.45 * (income - 180e3))))),
       stop("Not yet implemented."))

There were some problems, however. One is that it's difficult to update or modify. But perhaps more importantly is that it's not particularly literate: the code merely 'happens' to give the right answer, rather than expressing the method too.

Income tax calculations are rolling joins

A more natural and expressive approach is to treat the income tax as a rolling join.

input <- data.table(income = income)
tax_table2 <- copy(grattan:::tax_table2)

# Record the order if needed
input[, the_order := .I]
input[, fy_year := "2017-18"]
setkey(input, fy_year, income)

tax_table2[input, roll = TRUE] %>%
  .[, tax := tax_at + (income - lower_bracket) * marginal_rate] %>%
  .[order(the_order)]

With this approach, we can just append new tax years or proposed tax rates to tax_table2, rather than pipetting magic numbers into a nest of ifelses. The code and the data are separate and both are easier to manage.



Try the grattan package in your browser

Any scripts or data that you put into this service are public.

grattan documentation built on Oct. 17, 2018, 1:05 a.m.