Calculating
calculate_row
calculate_row(record: Mapping[str, Any], **options) -> dict
One household in, one dict out. record maps input names to values;
options are any of the keyword options of calculate_taxes below.
from taxsim_py import calculate_row
calculate_row({"year": 2023, "state": 5, "mstat": 1, "pwages": 60_000}, mtr=85)
It builds a one-row dataframe and calls calculate_taxes, so for more than a handful
of households use calculate_taxes directly.
calculate_taxes
calculate_taxes(df, *, year=None, mtr=None, idtl=None, ...) -> pl.DataFrame
df is a Polars DataFrame or LazyFrame. The result is an eager DataFrame:
the input, unchanged and in order, plus the output columns.
from taxsim_py import calculate_taxes
calculate_taxes(households)
Options
Everything below is a keyword argument, and each is optional.
Which year, which state coding
| Option | Default | Meaning |
|---|---|---|
year |
the year column |
Use this tax year for every row. Without it the frame needs a year column, and rows may mix years. |
year_column |
"year" |
Name of the year column. |
state_column |
"state" |
Name of the state column. |
state_id_type |
"taxsim" |
"taxsim" (codes 1-51, 0 for no state) or "fips" (Census state FIPS codes). |
calculate_taxes(df, year=2024)
calculate_taxes(df, state_id_type="fips") # state=6 is California, not Colorado
Marginal rates: mtr
mtr adds frate (federal) and srate (state) marginal rates, in percent, with respect
to one kind of income or deduction. Pass a MarginalInput or TAXSIM's own numeric code,
or put an integer mtr column in the frame to choose per row. 0 means no rates.
from taxsim_py import MarginalInput
calculate_taxes(df, mtr=MarginalInput.PRIMARY_WAGES) # same as mtr=85
MarginalInput |
Code | MarginalInput |
Code | |
|---|---|---|---|---|
NONE |
0 | OTHER_PROPERTY_INCOME |
79 | |
BOTH_WAGES |
11 | PRIMARY_UNEMPLOYMENT |
82 | |
DIVIDENDS |
12 | PRIMARY_WAGES |
85 | |
INTEREST_RECEIVED |
14 | SPOUSE_WAGES |
86 | |
PRIMARY_SELF_EMPLOYMENT_INCOME |
17 | SOCIAL_SECURITY_BENEFITS |
91 | |
PENSIONS |
20 | RENT_PAID |
160 | |
NONPROPERTY_INCOME |
30 | SPOUSE_UNEMPLOYMENT |
180 | |
TRANSFERS |
41 | PRIMARY_BUSINESS_INCOME |
211 | |
PROPERTY_TAX |
51 | PRIMARY_PROFESSIONAL_INCOME |
212 | |
OTHER_ITEMIZED_DEDUCTIONS |
54 | S_CORPORATION_INCOME |
213 | |
MORTGAGE_INTEREST |
56 | SPOUSE_BUSINESS_INCOME |
214 | |
CHILDCARE_EXPENSES |
64 | SPOUSE_PROFESSIONAL_INCOME |
215 | |
SHORT_TERM_CAPITAL_GAINS |
68 | |||
LONG_TERM_CAPITAL_GAINS |
70 |
Marginal rates cost extra calculations, so leave mtr off when you do not need them.
Detail: idtl, taxsim_names, keep_intermediate
idtl=2(or anidtlcolumn holding 2) adds the federal and state worksheet lines with descriptive names, such asfederal_taxable_incomeandstate_adjusted_gross_income. See Outputs.taxsim_names=Truerenames only those worksheet columns to TAXSIM's labels (credits,v10tov45,staxbc).keep_intermediate=Truealso returns every intermediate federal and state column, for auditing.
calculate_taxes(df, idtl=2)
calculate_taxes(df, idtl=2, taxsim_names=True)
Calculation mode
calculation_mode |
Behavior |
|---|---|
"statutory" (default) |
Uses the current-law parameter tables and the reviewed corrections to TAXSIM. Use this for new analysis. |
"taxsim" |
Reproduces the compiled TAXSIM, known bugs included, for replication and comparison. |
You can also pass taxsim_py.CalculationMode.STATUTORY or .TAXSIM. The list of
differences is in Statutory corrections.
Speed and memory
| Option | Meaning |
|---|---|
batch_rows |
Maximum input rows per batch. Lower it to cap memory on very large inputs. |
max_year_workers |
Threads used to run years and row batches concurrently. The default is Polars' thread pool size (set POLARS_MAX_THREADS to change it). |
See Performance for timings and memory.
Errors
calculate_taxes raises ValueError for a missing state, mstat or year column; a
null mstat or year; an unsupported mstat; an empty frame; and years outside 1960-2025
(state tax from 1977).