Ejemplo n.º 1
0
def test_gini():
    # Unweighted
    mdf.gini(df, "x")
    # Weighted
    mdf.gini(df, "x", "w")
    # Unweighted, grouped
    mdf.gini(dfg, "x", groupby="g")
    # Weighted, grouped
    mdf.gini(dfg, "x", "w", groupby="g")
Ejemplo n.º 2
0
def tax(flat_tax, total_type="person"):
    """Calculate all metrics given a flat tax.

    Args:
        flat_tax: Percentage tax rate (0-100).
        total_type: Whether to use total population and current tax liability
            from SPM units or persons. Either "person" or "spmu".
            Defaults to "person".
    """
    flat_tax /= 100
    spmu["new_tax"] = spmu.spmu_agi * flat_tax
    new_revenue = mdf.weighted_sum(spmu, "new_tax", "spm_weight")
    change_revenue = new_revenue - totals.loc[total_type].fica_fedtax_ac
    ubi = change_revenue / totals.loc[total_type].person

    spmu["new_spm_resources"] = (spmu.spm_resources_before_tax +
                                 ubi * spmu.spmu_total_people - spmu.new_tax)

    # Merge back to each person.
    target_persons = person.merge(spmu[SPM_COLS + ["new_spm_resources"]],
                                  on=SPM_COLS)

    target_persons["new_spm_resources_pp"] = (
        target_persons.new_spm_resources / target_persons.spmu_total_people)

    # Calculate poverty rate
    target_persons["new_poor"] = (target_persons.new_spm_resources <
                                  target_persons.spm_povthreshold)

    poverty_rate = mdf.weighted_mean(target_persons, "new_poor", "marsupwt")
    change_poverty_rate = chg(poverty_rate, initial_poverty_rate)

    # Calculate poverty gap
    poverty_gaps = np.maximum(spmu.spm_povthreshold - spmu.new_spm_resources,
                              0)
    poverty_gap = (poverty_gaps * spmu.spm_weight).sum()
    change_poverty_gap = chg(poverty_gap, initial_poverty_gap)

    # Calculate Gini
    gini = mdf.gini(target_persons, "new_spm_resources_pp", w="marsupwt")
    change_gini = chg(gini, initial_gini)

    # Percent winners
    target_persons["better_off"] = (target_persons.new_spm_resources >
                                    target_persons.spm_resources)
    percent_better_off = mdf.weighted_mean(target_persons, "better_off",
                                           "marsupwt")

    return pd.Series({
        "poverty_rate": poverty_rate,
        "poverty_gap": poverty_gap,
        "gini": gini,
        "percent_better_off": percent_better_off,
        "change_poverty_rate": change_poverty_rate,
        "change_poverty_gap": change_poverty_gap,
        "change_gini": change_gini,
        "change_revenue": change_revenue,
        "ubi": ubi,
    })
Ejemplo n.º 3
0
def test_gini():
    # Test nothing breaks.
    ms.gini()
    # Unweighted.
    mdf.gini(df, "x")
    # Weighted
    mdf.gini(df, "x", "w")
    # Unweighted, grouped
    mdf.gini(dfg, "x", groupby="g")
    # Weighted, grouped
    mdf.gini(dfg, "x", "w", groupby="g")
    # Test old and new match.
    assert ms.gini() == mdf.gini(df, "x", "w")
def ubi(funding_billions=0, percent=0):
  """ Calculate the poverty rate among the total US population by:
  
  -passing a total level of funding for a UBI proposal (billions USD),
  -passing a percent of the benefit recieved by a child and the benefit
  recieved by an adult
  AND
  taking into account that funding will be raise by a flat tax leveled on each households
  taxable income """

  percent = percent / 100

  funding = funding_billions * 1e9

  target_persons = person.copy(deep=True)

  # i think this is % funding, not % benefit
  adult_ubi = ((1 - percent) * funding) / adult_pop
  child_ubi = (percent * funding) / child_pop

  tax_rate = funding / total_taxable_income

  target_persons['hh_new_tax'] = target_persons.hh_tax_income * tax_rate

  target_persons['hh_ubi'] = (target_persons.hh_adults * adult_ubi + 
                              target_persons.hh_children * child_ubi)
  
  target_persons['new_spm_resources'] = (target_persons.spm_resources + 
                                         target_persons.hh_ubi -
                                         target_persons.hh_new_tax)
  
  target_persons['new_spm_resources_pp'] = (target_persons.new_spm_resources / 
                                            (target_persons.hh_total_people))

  
  # Calculate poverty rate
  target_persons['poor'] = (target_persons.new_spm_resources < 
                            target_persons.spm_povthreshold)
  
  total_poor = (target_persons.poor * target_persons.weight).sum()
  poverty_rate = (total_poor / pop * 100)

  # Calculate poverty gap
  target_persons['poverty_gap'] = target_persons.spm_povthreshold - target_persons.new_spm_resources
  poverty_gap = (((target_persons.poor * target_persons.poverty_gap
                             * target_persons.weight).sum()))

  # Calculate Gini
  gini = mdf.gini(target_persons, 'new_spm_resources_pp', w='weight')

  # Percent winners
  target_persons['better_off'] = (target_persons.new_spm_resources > target_persons.spm_resources)
  total_better_off = (target_persons.better_off * target_persons.weight).sum()
  percent_better_off = total_better_off / pop

  return pd.Series([poverty_rate, gini, poverty_gap, percent_better_off, adult_ubi, child_ubi])
Ejemplo n.º 5
0
def gin(data, group):
    return pd.DataFrame(
        data.groupby(group).apply(
            lambda x: mdf.gini(x, "spmftotval", "asecwt")))
Ejemplo n.º 6
0
                               "spm_weight")
spmu_totals.index = person_totals.index

totals = pd.concat([person_totals, spmu_totals], axis=1).T
totals.index = ["person", "spmu"]

# Calculate status quo
person["poor"] = person.spm_resources < person.spm_povthreshold
initial_poverty_rate = mdf.weighted_mean(person, "poor", "marsupwt")

spmu["initial_poverty_gap"] = np.maximum(
    spmu.spm_povthreshold - spmu.spm_resources, 0)
initial_poverty_gap = (spmu.initial_poverty_gap * spmu.spm_weight).sum()

person["spm_resources_pp"] = person.spm_resources / person.spmu_total_people
initial_gini = mdf.gini(person, "spm_resources_pp", w="marsupwt")


def chg(new, base):
    return (100 * (new - base) / base).round(1)


def tax(flat_tax, total_type="person"):
    """Calculate all metrics given a flat tax.

    Args:
        flat_tax: Percentage tax rate (0-100).
        total_type: Whether to use total population and current tax liability
            from SPM units or persons. Either "person" or "spmu".
            Defaults to "person".
    """
Ejemplo n.º 7
0
# append US statistics as additional 'state'
pop_df = pop_states.append(pop_us)
# melt df from wide to long format
pop_df = pop_df.melt(ignore_index=False, var_name="demog")
pop_df.insert(loc=1, column="metric", value="pop")

# concat poverty and population dfs
demog_stats = pd.concat([pov_df, pop_df])
# write to csv file
demog_stats.to_csv("demog_stats.csv.gz", compression="gzip")

# Caluclate original gini
person["spm_resources_per_person"] = person.spmtotres / person.numper
# Caluclate original gini for US
gini_us = pd.Series(
    mdf.gini(df=person, col="spm_resources_per_person", w="asecwt"))
# add name to series
gini_us.index = ["US"]

# calculate gini for each group by state
gini_states = mdf.gini(df=person,
                       col="spm_resources_per_person",
                       w="asecwt",
                       groupby="state")

# append US statistics as additional 'state'
gini_ser = gini_states.append(gini_us)
gini_ser.name = "gini"

# Calculate the original poverty gap
spmu["poverty_gap"] = np.where(
Ejemplo n.º 8
0
def evaluate_reform(reform):
    baseline = model()
    reformed = model(reform)
    period = "2020-10"
    family_weights = baseline.calculate("benunit_weight", period)
    adult_weights = baseline.calculate("adult_weight", period)
    household_weights = baseline.calculate("household_weight", period)
    net_gain = reformed.calculate(
        "benunit_net_income", period
    ) - baseline.calculate("benunit_net_income", period)
    gross_ubi_cost = (
        (reformed.calculate("benunit_basic_income", period)) * family_weights
    ).sum() * 52
    total_net_cost = (net_gain * family_weights).sum() * 52
    print("Total cost summary:")
    print(f"    Net cost of reform: {gbp(total_net_cost)}")
    print(f"    Gross cost of UBI: {gbp(gross_ubi_cost)}")
    poverty_ahc_reduction = percent_reduction(
        poverty_rate(baseline, "people_in_household"),
        poverty_rate(reformed, "people_in_household"),
    )
    adult_poverty_ahc_reduction = percent_reduction(
        poverty_rate(baseline, "adults_in_household"),
        poverty_rate(reformed, "adults_in_household"),
    )
    child_poverty_ahc_reduction = percent_reduction(
        poverty_rate(baseline, "children_in_household"),
        poverty_rate(reformed, "children_in_household"),
    )
    senior_poverty_ahc_reduction = percent_reduction(
        poverty_rate(baseline, "seniors_in_household"),
        poverty_rate(reformed, "seniors_in_household"),
    )
    print("Poverty statistics:")
    print(f"    AHC poverty change: {num(poverty_ahc_reduction * 100)}%")
    print(
        f"    AHC adult poverty change: {num(adult_poverty_ahc_reduction * 100)}%"
    )
    print(
        f"    AHC child poverty change: {num(child_poverty_ahc_reduction * 100)}%"
    )
    print(
        f"    AHC senior poverty change: {num(senior_poverty_ahc_reduction * 100)}%"
    )
    diff_vars_adult = ["state_pension", "JSA_contrib"]
    diff_vars_family = [
        "child_benefit",
        "income_support",
        "working_tax_credit",
        "child_tax_credit",
        "benunit_income_tax",
        "benunit_NI",
        "pension_credit",
        "JSA_income",
        "universal_credit",
    ]
    print("MTR:")
    baseline_MTR = calc_mtr(entity="household")
    reform_MTR = calc_mtr(reform, entity="household")
    average_baseline_MTR = np.average(baseline_MTR, weights=household_weights)
    average_reform_MTR = np.average(reform_MTR, weights=household_weights)
    on_benefits = baseline.calculate(
        "household_receives_means_tested_benefits", period
    ).astype(bool)
    average_baseline_ben_MTR = np.average(
        baseline_MTR[on_benefits], weights=household_weights[on_benefits]
    )
    average_reform_ben_MTR = np.average(
        reform_MTR[on_benefits], weights=household_weights[on_benefits]
    )
    print(f"    Average baseline MTR: {average_baseline_MTR}")
    print(f"    Average reform MTR: {average_reform_MTR}")
    print(
        f"    Average baseline MTR for households on benefits: {average_baseline_ben_MTR}"
    )
    print(
        f"    Average reform MTR for households on benefits: {average_reform_ben_MTR}"
    )
    print("Inequality:")
    household_net_ahc = pd.DataFrame()
    household_net_ahc["w"] = baseline.calculate(
        "household_weight", period
    ) * baseline.calculate("people_in_household", period)
    household_net_ahc["baseline"] = baseline.calculate(
        "equiv_household_net_income_ahc", period
    )
    household_net_ahc["reform"] = reformed.calculate(
        "equiv_household_net_income_ahc", period
    )
    baseline_gini = mdf.gini(household_net_ahc, "baseline", w="w")
    reform_gini = mdf.gini(household_net_ahc, "reform", w="w")
    gini_reduction = percent_reduction(baseline_gini, reform_gini)
    print(f"    Gini coefficient reduction: {num(gini_reduction * 100)}%")

    print("Rise in amounts per year across all:")
    print("    individuals:")
    for var in diff_vars_adult:
        diff = (
            (reformed.calculate(var, period) - baseline.calculate(var, period))
            * adult_weights
        ).sum() * 52
        print(f"        {var}: {gbp(diff)}")
    print("    families:")
    for var in diff_vars_family:
        diff = (
            (reformed.calculate(var, period) - baseline.calculate(var, period))
            * family_weights
        ).sum() * 52
        print(f"        {var}: {gbp(diff)}")
Ejemplo n.º 9
0
def ubi(statefip, level, agi_tax, benefits, taxes, exclude):

    if level == "federal":
        # combine lists and initialize
        taxes_benefits = taxes + benefits
        spmu["new_resources"] = spmu.spmtotres
        revenue = 0

        # Calculate the new revenue and spmu resources from tax and benefit change
        for tax_benefit in taxes_benefits:
            spmu.new_resources -= spmu[tax_benefit]
            revenue += mdf.weighted_sum(spmu, tax_benefit, "spmwt")

        if ("fedtaxac" in taxes_benefits) & ("ctc" in taxes_benefits):
            spmu.new_resources += spmu.ctc
            revenue -= mdf.weighted_sum(spmu, "ctc", "spmwt")

        if ("fedtaxac" in taxes_benefits) & ("eitcred" in taxes_benefits):
            spmu.new_resources += spmu.eitcred
            revenue -= mdf.weighted_sum(spmu, "eitcred", "spmwt")

        # Calculate the new taxes from flat tax on AGI
        tax_rate = agi_tax / 100
        spmu["new_taxes"] = np.maximum(spmu.adjginc, 0) * tax_rate

        spmu.new_resources -= spmu.new_taxes
        revenue += mdf.weighted_sum(spmu, "new_taxes", "spmwt")

        # Calculate the total UBI a spmu recieves based on exclusions
        spmu["numper_ubi"] = spmu.numper

        if "children" in exclude:
            spmu["numper_ubi"] -= spmu.child

        if "non_citizens" in exclude:
            spmu["numper_ubi"] -= spmu.non_citizen

        if ("children" in exclude) and ("non_citizens" in exclude):
            spmu["numper_ubi"] += spmu.non_citizen_child

        if "adults" in exclude:
            spmu["numper_ubi"] -= spmu.adult

        if ("adults" in exclude) and ("non_citizens" in exclude):
            spmu["numper_ubi"] += spmu.non_citizen_adult

        # Assign UBI
        ubi_population = (spmu.numper_ubi * spmu.spmwt).sum()
        ubi = revenue / ubi_population
        spmu["total_ubi"] = ubi * spmu.numper_ubi

        # Calculate change in resources
        spmu.new_resources += spmu.total_ubi
        spmu["new_resources_per_person"] = spmu.new_resources / spmu.numper
        # Sort by state
        if statefip == "US":
            target_spmu = spmu.copy(deep=True)
        else:
            target_spmu = spmu[spmu.statefip == statefip].copy(deep=True)

    if level == "state":

        # Sort by state
        if statefip == "US":
            target_spmu = spmu.copy(deep=True)
        else:
            target_spmu = spmu[spmu.statefip == statefip].copy(deep=True)

        # Initialize
        target_spmu["new_resources"] = target_spmu.spmtotres
        revenue = 0

        # Change income tax repeal to state level
        if "fedtaxac" in taxes:
            target_spmu.new_resources -= target_spmu.stataxac
            revenue += mdf.weighted_sum(target_spmu, "stataxac", "spmwt")

        # Calculate change in tax revenue
        tax_rate = agi_tax / 100
        target_spmu["new_taxes"] = target_spmu.adjginc * tax_rate

        target_spmu.new_resources -= target_spmu.new_taxes
        revenue += mdf.weighted_sum(target_spmu, "new_taxes", "spmwt")

        # Calculate the total UBI a spmu recieves based on exclusions
        target_spmu["numper_ubi"] = target_spmu.numper

        if "children" in exclude:
            target_spmu["numper_ubi"] -= target_spmu.child

        if "non_citizens" in exclude:
            target_spmu["numper_ubi"] -= target_spmu.non_citizen

        if ("children" in exclude) and ("non_citizens" in exclude):
            target_spmu["numper_ubi"] += target_spmu.non_citizen_child

        if "adults" in exclude:
            target_spmu["numper_ubi"] -= target_spmu.adult

        if ("adults" in exclude) and ("non_citizens" in exclude):
            target_spmu["numper_ubi"] += target_spmu.non_citizen_adult

        # Assign UBI
        ubi_population = (target_spmu.numper_ubi * target_spmu.spmwt).sum()
        ubi = revenue / ubi_population
        target_spmu["total_ubi"] = ubi * target_spmu.numper_ubi

        # Calculate change in resources
        target_spmu.new_resources += target_spmu.total_ubi
        target_spmu["new_resources_per_person"] = (
            target_spmu.new_resources / target_spmu.numper
        )

    # Merge and create target_persons
    sub_spmu = target_spmu[
        ["spmfamunit", "year", "new_resources", "new_resources_per_person"]
    ]
    target_persons = person.merge(sub_spmu, on=["spmfamunit", "year"])

    # Calculate populations
    population = target_persons.asecwt.sum()
    child_population = (target_persons.child * target_persons.asecwt).sum()
    non_citizen_population = (
        target_persons.non_citizen * target_persons.asecwt
    ).sum()
    non_citizen_child_population = (
        target_persons.non_citizen_child * target_persons.asecwt
    ).sum()

    # Calculate total change in resources
    original_total_resources = (
        target_spmu.spmtotres * target_spmu.spmwt
    ).sum()
    new_total_resources = (target_spmu.new_resources * target_spmu.spmwt).sum()
    change_total_resources = new_total_resources - original_total_resources
    change_pp = change_total_resources / population

    # Determine people originally in poverty
    target_persons["original_poor"] = (
        target_persons.spmtotres < target_persons.spmthresh
    )

    # Calculate original poverty rate
    original_total_poor = (
        target_persons.original_poor * target_persons.asecwt
    ).sum()
    original_poverty_rate = (original_total_poor / population) * 100

    # Calculate the original poverty gap
    target_spmu["poverty_gap"] = np.where(
        target_spmu.spmtotres < target_spmu.spmthresh,
        target_spmu.spmthresh - target_spmu.spmtotres,
        0,
    )

    original_poverty_gap = mdf.weighted_sum(
        target_spmu, "poverty_gap", "spmwt"
    )

    # Calculate the orginal demographic poverty rates
    def pov_rate(column):
        return (
            mdf.weighted_mean(
                target_persons[target_persons[column]],
                "original_poor",
                "asecwt",
            )
            * 100
        )

    original_child_poverty_rate = pov_rate("child")
    original_adult_poverty_rate = pov_rate("adult")
    original_pwd_poverty_rate = pov_rate("pwd")
    original_white_poverty_rate = pov_rate("white_non_hispanic")
    original_black_poverty_rate = pov_rate("black")
    original_hispanic_poverty_rate = pov_rate("hispanic")

    # Caluclate original gini
    target_persons["spm_resources_per_person"] = (
        target_persons.spmtotres / target_persons.numper
    )
    original_gini = mdf.gini(
        target_persons, "spm_resources_per_person", "asecwt"
    )

    # Calculate poverty gap
    target_spmu["new_poverty_gap"] = np.where(
        target_spmu.new_resources < target_spmu.spmthresh,
        target_spmu.spmthresh - target_spmu.new_resources,
        0,
    )
    poverty_gap = mdf.weighted_sum(target_spmu, "new_poverty_gap", "spmwt")
    poverty_gap_change = (
        (poverty_gap - original_poverty_gap) / original_poverty_gap * 100
    ).round(1)

    # Calculate the change in poverty rate
    target_persons["poor"] = (
        target_persons.new_resources < target_persons.spmthresh
    )
    total_poor = (target_persons.poor * target_persons.asecwt).sum()
    poverty_rate = (total_poor / population) * 100
    poverty_rate_change = (
        (poverty_rate - original_poverty_rate) / original_poverty_rate * 100
    ).round(1)

    # Calculate change in Gini
    gini = mdf.gini(target_persons, "new_resources_per_person", "asecwt")
    gini_change = ((gini - original_gini) / original_gini * 100).round(1)

    # Calculate percent winners
    target_persons["winner"] = (
        target_persons.new_resources > target_persons.spmtotres
    )
    total_winners = (target_persons.winner * target_persons.asecwt).sum()
    percent_winners = (total_winners / population * 100).round(1)

    # Calculate the new poverty rate for each demographic
    def pv_rate(column):
        return (
            mdf.weighted_mean(
                target_persons[target_persons[column]], "poor", "asecwt"
            )
            * 100
        )

    child_poverty_rate = pv_rate("child")
    adult_poverty_rate = pv_rate("adult")
    pwd_poverty_rate = pv_rate("pwd")
    white_poverty_rate = pv_rate("white_non_hispanic")
    black_poverty_rate = pv_rate("black")
    hispanic_poverty_rate = pv_rate("hispanic")

    # Calculate the percent change in poverty rate for each demographic
    child_poverty_rate_change = (
        (child_poverty_rate - original_child_poverty_rate)
        / original_child_poverty_rate
        * 100
    ).round(1)
    adult_poverty_rate_change = (
        (adult_poverty_rate - original_adult_poverty_rate)
        / original_adult_poverty_rate
        * 100
    ).round(1)
    pwd_poverty_rate_change = (
        (pwd_poverty_rate - original_pwd_poverty_rate)
        / original_pwd_poverty_rate
        * 100
    ).round(1)
    white_poverty_rate_change = (
        (white_poverty_rate - original_white_poverty_rate)
        / original_white_poverty_rate
        * 100
    ).round(1)
    black_poverty_rate_change = (
        (black_poverty_rate - original_black_poverty_rate)
        / original_black_poverty_rate
        * 100
    ).round(1)
    hispanic_poverty_rate_change = (
        (hispanic_poverty_rate - original_hispanic_poverty_rate)
        / original_hispanic_poverty_rate
        * 100
    ).round(1)

    # Round all numbers for display in hover
    original_poverty_rate_string = str(round(original_poverty_rate, 1))
    poverty_rate_string = str(round(poverty_rate, 1))
    original_child_poverty_rate_string = str(
        round(original_child_poverty_rate, 1)
    )
    child_poverty_rate_string = str(round(child_poverty_rate, 1))
    original_adult_poverty_rate_string = str(
        round(original_adult_poverty_rate, 1)
    )
    adult_poverty_rate_string = str(round(adult_poverty_rate, 1))
    original_pwd_poverty_rate_string = str(round(original_pwd_poverty_rate, 1))
    pwd_poverty_rate_string = str(round(pwd_poverty_rate, 1))
    original_white_poverty_rate_string = str(
        round(original_white_poverty_rate, 1)
    )
    white_poverty_rate_string = str(round(white_poverty_rate, 1))
    original_black_poverty_rate_string = str(
        round(original_black_poverty_rate, 1)
    )
    black_poverty_rate_string = str(round(black_poverty_rate, 1))
    original_hispanic_poverty_rate_string = str(
        round(original_hispanic_poverty_rate, 1)
    )
    hispanic_poverty_rate_string = str(round(hispanic_poverty_rate, 1))

    original_poverty_gap_billions = original_poverty_gap / 1e9
    original_poverty_gap_billions = int(original_poverty_gap_billions)
    original_poverty_gap_billions = "{:,}".format(
        original_poverty_gap_billions
    )

    poverty_gap_billions = poverty_gap / 1e9
    poverty_gap_billions = int(poverty_gap_billions)
    poverty_gap_billions = "{:,}".format(poverty_gap_billions)

    original_gini_string = str(round(original_gini, 3))
    gini_string = str(round(gini, 3))

    # Convert UBI and winners to string for title of chart
    ubi_int = int(ubi)
    ubi_int = "{:,}".format(ubi_int)
    ubi_string = str(ubi_int)
    winners_string = str(percent_winners)
    change_pp = int(change_pp)
    change_pp = "{:,}".format(change_pp)
    resources_string = str(change_pp)

    ubi_line = "UBI amount: $" + ubi_string
    winners_line = "Percent better off: " + winners_string + "%"
    resources_line = (
        "Average change in resources per person: $" + resources_string
    )

    # Create x-axis labels for each chart
    x = ["Poverty Rate", "Poverty Gap", "Inequality (Gini)"]
    x2 = [
        "Child",
        "Adult",
        "People<br>with<br>disabilities",
        "White",
        "Black",
        "Hispanic",
    ]

    fig = go.Figure(
        [
            go.Bar(
                x=x,
                y=[poverty_rate_change, poverty_gap_change, gini_change],
                text=[poverty_rate_change, poverty_gap_change, gini_change],
                hovertemplate=[
                    "Original poverty rate: "
                    + original_poverty_rate_string
                    + "%<br><extra></extra>"
                    "New poverty rate: " + poverty_rate_string + "%",
                    "Original poverty gap: $"
                    + original_poverty_gap_billions
                    + "B<br><extra></extra>"
                    "New poverty gap: $" + poverty_gap_billions + "B",
                    "Original gini: <extra></extra>"
                    + original_gini_string
                    + "<br>New gini: "
                    + gini_string,
                ],
                marker_color=BLUE,
            )
        ]
    )

    # Edit text and display the UBI amount and percent winners in title
    fig.update_layout(
        uniformtext_minsize=10, uniformtext_mode="hide", plot_bgcolor="white"
    )
    fig.update_traces(texttemplate="%{text}%", textposition="auto")
    fig.update_layout(title_text="Economic overview", title_x=0.5)

    fig.update_xaxes(
        tickangle=0, title_text="", tickfont={"size": 14}, title_standoff=25
    )

    fig.update_yaxes(
        # title_text = "Percent change",
        ticksuffix="%",
        tickprefix="",
        tickfont={"size": 14},
        title_standoff=25,
    )

    fig.update_layout(
        hoverlabel=dict(bgcolor="white", font_size=14, font_family="Roboto")
    )

    fig.update_xaxes(title_font=dict(size=14, family="Roboto", color="black"))
    fig.update_yaxes(title_font=dict(size=14, family="Roboto", color="black"))

    fig2 = go.Figure(
        [
            go.Bar(
                x=x2,
                y=[
                    child_poverty_rate_change,
                    adult_poverty_rate_change,
                    pwd_poverty_rate_change,
                    white_poverty_rate_change,
                    black_poverty_rate_change,
                    hispanic_poverty_rate_change,
                ],
                text=[
                    child_poverty_rate_change,
                    adult_poverty_rate_change,
                    pwd_poverty_rate_change,
                    white_poverty_rate_change,
                    black_poverty_rate_change,
                    hispanic_poverty_rate_change,
                ],
                hovertemplate=[
                    "Original child poverty rate: "
                    + original_child_poverty_rate_string
                    + "%<br><extra></extra>"
                    "New child poverty rate: "
                    + child_poverty_rate_string
                    + "%",
                    "Original adult poverty rate: "
                    + original_adult_poverty_rate_string
                    + "%<br><extra></extra>"
                    "New adult poverty rate: "
                    + adult_poverty_rate_string
                    + "%",
                    "Original pwd poverty rate: "
                    + original_pwd_poverty_rate_string
                    + "%<br><extra></extra>"
                    "New pwd poverty rate: " + pwd_poverty_rate_string + "%",
                    "Original White poverty rate: "
                    + original_white_poverty_rate_string
                    + "%<br><extra></extra>"
                    "New White poverty rate: "
                    + white_poverty_rate_string
                    + "%",
                    "Original Black poverty rate: "
                    + original_black_poverty_rate_string
                    + "%<br><extra></extra>"
                    "New Black poverty rate: "
                    + black_poverty_rate_string
                    + "%",
                    "Original Hispanic poverty rate: "
                    + original_hispanic_poverty_rate_string
                    + "%<br><extra></extra>"
                    "New Hispanic poverty rate: "
                    + hispanic_poverty_rate_string
                    + "%",
                ],
                marker_color=BLUE,
            )
        ]
    )

    fig2.update_layout(
        uniformtext_minsize=10, uniformtext_mode="hide", plot_bgcolor="white"
    )
    fig2.update_traces(texttemplate="%{text}%", textposition="auto")
    fig2.update_layout(title_text="Poverty rate breakdown", title_x=0.5)

    fig2.update_xaxes(
        tickangle=0, title_text="", tickfont={"size": 14}, title_standoff=25
    )

    fig2.update_yaxes(
        # title_text = "Percent change",
        ticksuffix="%",
        tickprefix="",
        tickfont={"size": 14},
        title_standoff=25,
    )

    fig2.update_layout(
        hoverlabel=dict(bgcolor="white", font_size=14, font_family="Roboto")
    )

    fig2.update_xaxes(title_font=dict(size=14, family="Roboto", color="black"))
    fig2.update_yaxes(title_font=dict(size=14, family="Roboto", color="black"))

    return ubi_line, winners_line, resources_line, fig, fig2
Ejemplo n.º 10
0
def loss_metrics(x: list, baseline_df, reform_base_df, budget) -> pd.Series:
    """Calculate each potential loss metric.

    :param x: List of optimization elements:
        [senior, child, dis_1, dis_2, dis_3, region1, region2, ..., region12]
    :type x: list
    :return: Series with five elements:
        loser_share: Share of the population who come out behind.
        losses: Total losses among losers in pounds.
        mean_pct_loss: Average percent loss across the population
            (including zeroes for people who don't experience losses).
        mean_pct_loss_pwd2: Average percent loss across the population, with
            double weight given to people with disabilities.
        poverty_gap_bhc: Poverty gap before housing costs.
        poverty_gap_ahc: Poverty gap after housing costs.
        gini: Gini index of per-person household net income in the reform
            scenario, weighted by person weight at the household level.
    :rtype: pd.Series
    """
    senior, child, dis_1, dis_2, dis_3, regions = extract(x)
    reform_df = set_ubi(reform_base_df, budget, senior, child, dis_1, dis_2,
                        dis_3, regions)
    # Calculate loss-related loss metrics.
    change = reform_df.household_net_income - baseline_df.household_net_income
    loss = np.maximum(-change, 0)
    weight = baseline_df.household_weight * baseline_df.people_in_household
    # Calculate loser share.
    total_pop = np.sum(weight)
    losers = np.sum(weight * (loss > 0))
    loser_share = losers / total_pop
    # Calculate total losses in pounds.
    losses = np.sum(weight * loss)
    # Calculate average percent loss (including zero for non-losers).
    pct_loss = loss / baseline_df.household_net_income
    valid_pct_loss = np.isfinite(pct_loss)
    total_pct_loss = np.sum(weight[valid_pct_loss] * pct_loss[valid_pct_loss])
    mean_pct_loss = total_pct_loss / total_pop
    # Calculate average percent loss with double weight for PWD.
    pwd2_weight = baseline_df.household_weight * (
        baseline_df.is_disabled + baseline_df.people_in_household)
    total_pct_loss_pwd2 = np.sum(pwd2_weight[valid_pct_loss] *
                                 pct_loss[valid_pct_loss])
    total_pop_pwd2 = pwd2_weight.sum()  # Denominator.
    mean_pct_loss_pwd2 = total_pct_loss_pwd2 / total_pop_pwd2
    # Gini of income per person.
    reform_hh_net_income_pp = (reform_df.household_net_income /
                               baseline_df.people_in_household)
    # mdf.gini requires a dataframe.
    reform_df = pd.DataFrame({
        "reform_hh_net_income_pp": reform_hh_net_income_pp,
        "weight": weight
    })
    gini = mdf.gini(reform_df, "reform_hh_net_income_pp", "weight")
    # Return Series of all metrics.
    return pd.Series({
        "loser_share": loser_share,
        "losses": losses,
        "mean_pct_loss": mean_pct_loss,
        "mean_pct_loss_pwd2": mean_pct_loss_pwd2,
        "gini": gini,
    })
Ejemplo n.º 11
0
# `gini` example

import microdf as mdf

x = [-10, -1, 0, 5, 100]
w = [1, 2, 3, 4, 5]

## Simple behavior

mdf.gini(x)

## Dealing with negatives

This will be equivalent to `mdf.gini([0, 0, 0, 5, 100])`.

mdf.gini(x, negatives='zero')

mdf.gini([0, 0, 0, 5, 100])

This will be equivalent to `mdf.gini([0, 9, 10, 15, 110])`.

mdf.gini(x, negatives='shift')

mdf.gini([0, 9, 10, 15, 110])

## Dealing with weights

mdf.gini(x, w)

mdf.gini([-10,
          -1, -1,
Ejemplo n.º 12
0
def ubi(state_dropdown, level, agi_tax, benefits, taxes, include):
    """this does everything from microsimulation to figure creation.
        Dash does something automatically where it takes the input arguments
        in the order given in the @app.callback decorator
    Args:
        state_dropdown:  takes input from callback input, component_id="state-dropdown"
        level:  component_id="level"
        agi_tax:  component_id="agi-slider"
        benefits:  component_id="benefits-checklist"
        taxes:  component_id="taxes-checklist"
        include: component_id="include-checklist"

    Returns:
        ubi_line: outputs to  "ubi-output" in @app.callback
        revenue_line: outputs to "revenue-output" in @app.callback
        ubi_population_line: outputs to "revenue-output" in @app.callback
        winners_line: outputs to "winners-output" in @app.callback
        resources_line: outputs to "resources-output" in @app.callback
        fig: outputs to "econ-graph" in @app.callback
        fig2: outputs to "breakdown-graph" in @app.callback
    """

    # -------------------- calculations based on reform level -------------------- #
    # if the "Reform level" selected by the user is federal
    if level == "federal":
        # combine taxes and benefits checklists into one list to be used to
        #  subset spmu dataframe
        taxes_benefits = taxes + benefits
        # initialize new resources column with old resources as baseline
        spmu["new_resources"] = spmu.spmtotres
        # initialize revenue at zero
        revenue = 0

        # Calculate the new revenue and spmu resources from tax and benefit change
        for tax_benefit in taxes_benefits:
            # subtract taxes and benefits that have been changed from spm unit's resources
            spmu.new_resources -= spmu[tax_benefit]
            # add that same value to revenue
            revenue += mdf.weighted_sum(spmu, tax_benefit, "spmwt")

        # if "Income taxes" = ? and "child_tax_credit" = ?
        # in taxes/benefits checklist
        if ("fedtaxac" in taxes_benefits) & ("ctc" in taxes_benefits):
            spmu.new_resources += spmu.ctc
            revenue -= mdf.weighted_sum(spmu, "ctc", "spmwt")

        if ("fedtaxac" in taxes_benefits) & ("eitcred" in taxes_benefits):
            spmu.new_resources += spmu.eitcred
            revenue -= mdf.weighted_sum(spmu, "eitcred", "spmwt")

        # Calculate the new taxes from flat tax on AGI
        tax_rate = agi_tax / 100
        spmu["new_taxes"] = np.maximum(spmu.adjginc, 0) * tax_rate
        # subtract new taxes from new resources
        spmu.new_resources -= spmu.new_taxes
        # add new revenue when new taxes are applied on spmus, multiplied by weights
        revenue += mdf.weighted_sum(spmu, "new_taxes", "spmwt")

        # Calculate the total UBI a spmu recieves based on exclusions
        spmu["numper_ubi"] = spmu.numper

        # TODO make into linear equation on one line using array of some kind
        if "children" not in include:
            # subtract the number of children from the number of
            # people in spm unit receiving ubi benefit
            spmu["numper_ubi"] -= spmu.child

        if "non_citizens" not in include:
            spmu["numper_ubi"] -= spmu.non_citizen

        if ("children" not in include) and ("non_citizens" not in include):
            spmu["numper_ubi"] += spmu.non_citizen_child

        if "adults" not in include:
            spmu["numper_ubi"] -= spmu.adult

        if ("adults" not in include) and ("non_citizens" not in include):
            spmu["numper_ubi"] += spmu.non_citizen_adult

        # Assign UBI
        ubi_population = (spmu.numper_ubi * spmu.spmwt).sum()
        ubi_annual = revenue / ubi_population
        spmu["total_ubi"] = ubi_annual * spmu.numper_ubi

        # Calculate change in resources
        spmu.new_resources += spmu.total_ubi
        spmu["new_resources_per_person"] = spmu.new_resources / spmu.numper
        # Sort by state

        # NOTE: the "target" here refers to the population being
        # measured for gini/poverty rate/etc.
        # I.e. the total population of the state/country and
        # INCLUDING those excluding form recieving ubi payments

        # state here refers to the selection from the drop down, not the reform level
        if state_dropdown == "US":
            target_spmu = spmu
        else:
            target_spmu = spmu[spmu.state == state_dropdown]

    # if the "Reform level" dropdown selected by the user is State
    if level == "state":

        # Sort by state
        if state_dropdown == "US":
            target_spmu = spmu
        else:
            target_spmu = spmu[spmu.state == state_dropdown]

        # Initialize
        target_spmu["new_resources"] = target_spmu.spmtotres
        revenue = 0

        # Change income tax repeal to state level
        if "fedtaxac" in taxes:
            target_spmu.new_resources -= target_spmu.stataxac
            revenue += mdf.weighted_sum(target_spmu, "stataxac", "spmwt")

        # Calculate change in tax revenue
        tax_rate = agi_tax / 100
        target_spmu["new_taxes"] = target_spmu.adjginc * tax_rate

        target_spmu.new_resources -= target_spmu.new_taxes
        revenue += mdf.weighted_sum(target_spmu, "new_taxes", "spmwt")

        # Calculate the total UBI a spmu recieves based on exclusions
        target_spmu["numper_ubi"] = target_spmu.numper

        if "children" not in include:
            target_spmu["numper_ubi"] -= target_spmu.child

        if "non_citizens" not in include:
            target_spmu["numper_ubi"] -= target_spmu.non_citizen

        if ("children" not in include) and ("non_citizens" not in include):
            target_spmu["numper_ubi"] += target_spmu.non_citizen_child

        if "adults" not in include:
            target_spmu["numper_ubi"] -= target_spmu.adult

        if ("adults" not in include) and ("non_citizens" not in include):
            target_spmu["numper_ubi"] += target_spmu.non_citizen_adult

        # Assign UBI
        ubi_population = (target_spmu.numper_ubi * target_spmu.spmwt).sum()
        ubi_annual = revenue / ubi_population
        target_spmu["total_ubi"] = ubi_annual * target_spmu.numper_ubi

        # Calculate change in resources
        target_spmu.new_resources += target_spmu.total_ubi
        target_spmu["new_resources_per_person"] = (target_spmu.new_resources /
                                                   target_spmu.numper)

    # NOTE: code after this applies to both reform levels

    # Merge and create target_persons -
    # NOTE: the "target" here refers to the population being
    # measured for gini/poverty rate/etc.
    # I.e. the total population of the state/country and
    # INCLUDING those excluding form recieving ubi payments
    sub_spmu = target_spmu[[
        "spmfamunit", "year", "new_resources", "new_resources_per_person"
    ]]
    target_persons = person.merge(sub_spmu, on=["spmfamunit", "year"])

    # filter demog_stats for selected state from dropdown
    baseline_demog = demog_stats[demog_stats.state == state_dropdown]

    # TODO: return dictionary of results instead of return each variable
    def return_demog(demog, metric):
        """
        retrieve pre-processed data by demographic
        args:
            demog - string one of
                ['person', 'adult', 'child', 'black', 'white',
            'hispanic', 'pwd', 'non_citizen', 'non_citizen_adult',
            'non_citizen_child']
            metric - string, one of ['pov_rate', 'pop']
        returns:
            value - float
        """
        # NOTE: baseline_demog is a dataframe with global scope
        value = baseline_demog.loc[
            (baseline_demog["demog"] == demog)
            & (baseline_demog["metric"] == metric), "value",
            # NOTE: returns the first value as a float, be careful if you redefine baseline_demog
        ].values[0]

        return value

    population = return_demog(demog="person", metric="pop")
    child_population = return_demog(demog="child", metric="pop")
    non_citizen_population = return_demog(demog="non_citizen", metric="pop")
    non_citizen_child_population = return_demog(demog="non_citizen_child",
                                                metric="pop")

    # filter all state stats gini, poverty_gap, etc. for dropdown state
    baseline_all_state_stats = all_state_stats[all_state_stats.index ==
                                               state_dropdown]

    def return_all_state(metric):
        """filter baseline_all_state_stats and return value of select metric

        Keyword arguments:
        metric - string, one of 'poverty_gap', 'gini', 'total_resources'

        returns:
            value- float
        """

        return baseline_all_state_stats[metric].values[0]

    # Calculate total change in resources
    original_total_resources = return_all_state("total_resources")
    # DO NOT PREPROCESS, new_resources
    new_total_resources = (target_spmu.new_resources * target_spmu.spmwt).sum()
    change_total_resources = new_total_resources - original_total_resources
    change_pp = change_total_resources / population

    original_poverty_rate = return_demog("person", "pov_rate")

    original_poverty_gap = return_all_state("poverty_gap")
    # define orignal gini coefficient
    original_gini = return_all_state("gini")

    # function to calculate rel difference between one number and another
    def rel_change(new, old, round=3):
        return ((new - old) / old).round(round)

    # Calculate poverty gap
    target_spmu["new_poverty_gap"] = np.where(
        target_spmu.new_resources < target_spmu.spmthresh,
        target_spmu.spmthresh - target_spmu.new_resources,
        0,
    )
    poverty_gap = mdf.weighted_sum(target_spmu, "new_poverty_gap", "spmwt")
    poverty_gap_change = rel_change(poverty_gap, original_poverty_gap)

    # Calculate the change in poverty rate
    target_persons["poor"] = (target_persons.new_resources <
                              target_persons.spmthresh)
    total_poor = (target_persons.poor * target_persons.asecwt).sum()
    poverty_rate = total_poor / population
    poverty_rate_change = rel_change(poverty_rate, original_poverty_rate)

    # Calculate change in Gini
    gini = mdf.gini(target_persons, "new_resources_per_person", "asecwt")
    gini_change = rel_change(gini, original_gini, 3)

    # Calculate percent winners
    target_persons["winner"] = (target_persons.new_resources >
                                target_persons.spmtotres)
    total_winners = (target_persons.winner * target_persons.asecwt).sum()
    percent_winners = (total_winners / population * 100).round(1)

    # -------------- calculate all of the poverty breakdown numbers -------------- #
    # Calculate the new poverty rate for each demographic
    def pv_rate(column):
        return mdf.weighted_mean(target_persons[target_persons[column]],
                                 "poor", "asecwt")

    # Round all numbers for display in hover
    def hover_string(metric, round_by=1):
        """formats 0.121 to 12.1%"""
        string = str(round(metric * 100, round_by)) + "%"
        return string

    DEMOGS = ["child", "adult", "pwd", "white", "black", "hispanic"]
    # create dictionary for demographic breakdown of poverty rates
    pov_breakdowns = {
        # return precomputed baseline poverty rates
        "original_rates":
        {demog: return_demog(demog, "pov_rate")
         for demog in DEMOGS},
        "new_rates": {demog: pv_rate(demog)
                      for demog in DEMOGS},
    }

    # add poverty rate changes to dictionary
    pov_breakdowns["changes"] = {
        # Calculate the percent change in poverty rate for each demographic
        demog: rel_change(
            pov_breakdowns["new_rates"][demog],
            pov_breakdowns["original_rates"][demog],
        )
        for demog in DEMOGS
    }

    # create string for hover template
    pov_breakdowns["strings"] = {
        demog: "Original " + demog + " poverty rate: " +
        hover_string(pov_breakdowns["original_rates"][demog]) +
        "<br><extra></extra>" + "New " + demog + " poverty rate: " +
        hover_string(pov_breakdowns["new_rates"][demog])
        for demog in DEMOGS
    }

    # format original and new overall poverty rate
    original_poverty_rate_string = hover_string(original_poverty_rate)
    poverty_rate_string = hover_string(poverty_rate)

    original_poverty_gap_billions = "{:,}".format(
        int(original_poverty_gap / 1e9))

    poverty_gap_billions = "{:,}".format(int(poverty_gap / 1e9))

    original_gini_string = str(round(original_gini, 3))
    gini_string = str(round(gini, 3))

    # --------------SECTION populates "Results of your reform:" ------------ #

    # Convert UBI and winners to string for title of chart
    ubi_string = str("{:,}".format(int(round(ubi_annual / 12))))

    # populates Monthly UBI
    ubi_line = "Monthly UBI: $" + ubi_string

    # populates 'Funds for UBI'
    revenue_line = "Funds for UBI: $" + numerize.numerize(revenue, 1)

    # populates population and revenue for UBI if state selected from dropdown
    if state_dropdown != "US":
        # filter for selected state
        state_spmu = target_spmu[target_spmu.state == state_dropdown]
        # calculate population of state recieving UBI
        state_ubi_population = (state_spmu.numper_ubi * state_spmu.spmwt).sum()

        ubi_population_line = "UBI population: " + numerize.numerize(
            state_ubi_population, 1)

        state_revenue = ubi_annual * state_ubi_population

        revenue_line = ("Funds for UBI (" + state_dropdown + "): $" +
                        numerize.numerize(state_revenue, 1))

    else:
        ubi_population_line = "UBI population: " + numerize.numerize(
            ubi_population, 1)

    winners_line = "Percent better off: " + str(percent_winners) + "%"
    resources_line = ("Average change in resources per person: $" +
                      "{:,}".format(int(change_pp)))

    # ---------- populate economic breakdown bar chart ------------- #

    # Create x-axis labels for each chart
    econ_fig_x_lab = ["Poverty rate", "Poverty gap", "Gini index"]
    econ_fig_cols = [poverty_rate_change, poverty_gap_change, gini_change]
    econ_fig = go.Figure([
        go.Bar(
            x=econ_fig_x_lab,
            y=econ_fig_cols,
            text=econ_fig_cols,
            hovertemplate=[
                # poverty rates
                "Original poverty rate: " + original_poverty_rate_string +
                "<br><extra></extra>"
                "New poverty rate: " + poverty_rate_string,
                # poverty gap
                "Original poverty gap: $" + original_poverty_gap_billions +
                "B<br><extra></extra>"
                "New poverty gap: $" + poverty_gap_billions + "B",
                # gini
                "Original Gini index: <extra></extra>" + original_gini_string +
                "<br>New Gini index: " + gini_string,
            ],
            marker_color=BLUE,
        )
    ])

    # Edit text and display the UBI amount and percent winners in title
    econ_fig.update_layout(
        uniformtext_minsize=10,
        uniformtext_mode="hide",
        plot_bgcolor="white",
        title_text="Economic overview",
        title_x=0.5,
        hoverlabel_align="right",
        font_family="Roboto",
        title_font_size=20,
        paper_bgcolor="white",
        hoverlabel=dict(bgcolor="white", font_size=14, font_family="Roboto"),
        yaxis_tickformat="%",
    )
    econ_fig.update_traces(texttemplate="%{text:.1%f}", textposition="auto")

    econ_fig.update_xaxes(
        tickangle=45,
        title_text="",
        tickfont={"size": 14},
        title_standoff=25,
        title_font=dict(size=14, family="Roboto", color="black"),
    )

    econ_fig.update_yaxes(
        tickprefix="",
        tickfont={"size": 14},
        title_standoff=25,
        title_font=dict(size=14, family="Roboto", color="black"),
    )

    # ------------------ populate poverty breakdown charts ---------------- #

    breakdown_fig_x_lab = [
        "Child",
        "Adult",
        "People<br>with<br>disabilities",
        "White",
        "Black",
        "Hispanic",
    ]

    breakdown_fig_cols = [pov_breakdowns["changes"][demog] for demog in DEMOGS]
    hovertemplate = [pov_breakdowns["strings"][demog] for demog in DEMOGS]

    breakdown_fig = go.Figure([
        go.Bar(
            x=breakdown_fig_x_lab,
            y=breakdown_fig_cols,
            text=breakdown_fig_cols,
            hovertemplate=hovertemplate,
            marker_color=BLUE,
        )
    ])

    breakdown_fig.update_layout(
        uniformtext_minsize=10,
        uniformtext_mode="hide",
        plot_bgcolor="white",
        title_text="Poverty rate breakdown",
        title_x=0.5,
        hoverlabel_align="right",
        font_family="Roboto",
        title_font_size=20,
        paper_bgcolor="white",
        hoverlabel=dict(bgcolor="white", font_size=14, font_family="Roboto"),
        yaxis_tickformat="%",
    )
    breakdown_fig.update_traces(texttemplate="%{text:.1%f}",
                                textposition="auto")

    breakdown_fig.update_xaxes(
        tickangle=45,
        title_text="",
        tickfont=dict(size=14, family="Roboto"),
        title_standoff=25,
        title_font=dict(size=14, family="Roboto", color="black"),
    )

    breakdown_fig.update_yaxes(
        tickprefix="",
        tickfont=dict(size=14, family="Roboto"),
        title_standoff=25,
        title_font=dict(size=14, family="Roboto", color="black"),
    )

    # set both y-axes to the same range
    full_econ_fig = econ_fig.full_figure_for_development(warn=False)
    full_breakdown_fig = breakdown_fig.full_figure_for_development(warn=False)
    # find the minimum of both y-axes
    global_ymin = min(
        min(full_econ_fig.layout.yaxis.range),
        min(full_breakdown_fig.layout.yaxis.range),
    )
    global_ymax = max(
        max(full_econ_fig.layout.yaxis.range),
        max(full_breakdown_fig.layout.yaxis.range),
    )

    # update the yaxes of the figure to account for both ends of the ranges
    econ_fig.update_yaxes(
        dict(range=[global_ymin, global_ymax], autorange=False))
    breakdown_fig.update_yaxes(
        dict(range=[global_ymin, global_ymax], autorange=False))

    return (
        ubi_line,
        revenue_line,
        ubi_population_line,
        winners_line,
        resources_line,
        econ_fig,
        breakdown_fig,
    )
Ejemplo n.º 13
0
### Add senior UBI to `aftertax_income` and recalculate

reform['ubi'] = senior_ubi * reform.n65
reform['aftertax_income'] = reform.aftertax_income + reform.ubi
mdf.add_weighted_metrics(reform, 'aftertax_income')

np.allclose(base.aftertax_income_m.sum(), reform.aftertax_income_m.sum())

## Analyze

Gini, FPL, distributional impact chart

### Change to Gini index

mdf.gini(base.aftertax_income, base.s006)

mdf.gini(reform.aftertax_income, reform.s006)

### Change to poverty rate

Add federal poverty line with `mdf.fpl`.

base['fpl'] = mdf.fpl(base.XTOT)
reform['fpl'] = mdf.fpl(reform.XTOT)

base['fpl_XTOT_m'] = np.where(base.aftertax_income < base.fpl,
                              base.XTOT_m, 0)
reform['fpl_XTOT_m'] = np.where(reform.aftertax_income < reform.fpl,
                                reform.XTOT_m, 0)
Ejemplo n.º 14
0
def loss_metrics(
    x: list,
    baseline_df: pd.DataFrame,
    reform_base_df: pd.DataFrame,
    budget: int,
) -> pd.Series:
    """Calculate each potential loss metric.

    :param x: List of optimization elements:
        [senior, child, dis_base, region1, region2, ..., region12]
    :type x: list
    :return: Series with five elements:
        loser_share: Share of the population who come out behind.
        losses: Total losses among losers in pounds.
        mean_pct_loss: Average percent loss across the population
            (including zeroes for people who don't experience losses).
        gini: Gini index of per-person household net income in the reform
            scenario, weighted by person weight at the household level.
    :rtype: pd.Series
    """
    senior, child, dis_base, regions = extract(x)
    reform_df = set_ubi(
        reform_base_df,
        budget,
        senior,
        child,
        dis_base,
        regions,
    )
    # Calculate loss-related loss metrics.
    change = reform_df.net_income - baseline_df.net_income
    loss = np.maximum(-change, 0)
    weight = baseline_df.household_weight * baseline_df.people
    # Calculate loser share.
    total_pop = np.sum(weight)
    losers = np.sum(weight * (loss > 0))
    loser_share = losers / total_pop
    # Calculate total losses in pounds.
    losses = np.sum(weight * loss)
    # Calculate average percent loss (including zero for non-losers).
    pct_loss = loss / baseline_df.net_income
    # Avoid infinite percent changes and backward changes due to negative
    # baseline income.
    valid_pct_loss = baseline_df.net_income > 0
    total_pct_loss = np.sum(weight[valid_pct_loss] * pct_loss[valid_pct_loss])
    mean_pct_loss = total_pct_loss / total_pop
    # Gini of income per person.
    reform_hh_net_income_pp = reform_df.net_income / baseline_df.people
    # mdf.gini requires a dataframe.
    reform_df = pd.DataFrame({
        "reform_hh_net_income_pp": reform_hh_net_income_pp,
        "weight": weight
    })
    gini = mdf.gini(reform_df, "reform_hh_net_income_pp", "weight")
    # Return Series of all metrics.
    return pd.Series({
        "loser_share": loser_share,
        "losses": losses,
        "mean_pct_loss": mean_pct_loss,
        "gini": gini,
    })
Ejemplo n.º 15
0
def ubi(
    funding_billions=0, child_percent_funding=None, child_percent_ubi=None
):
    """
    args:
        funding_billions: total annual funding for UBI program in billions USD
        child_percent_funding: percent (in whole numbers) of annual funds earmarked
        for child beneficiaries
        child_percent_ubi: proportion of child beneficiary's UBI benefit compared to adult
        beneficiary's payment

    returns:
        series of elements:
         poverty_rate: headcount poverty rate using Supplemental Poverty Measure threshold
         gini: gini coefficient of income
         poverty_gap: SPM unit poverty gap
         percent_better_off: percent of population with higher income after new transfers and taxes
         adult_ubi: annual per adult benefit in dollars
         child_ubi: annual per adult benefit in dollars
    """
    funding = funding_billions * 1e9

    if child_percent_funding is not None:
        child_percent_funding /= 100
        adult_ubi = ((1 - child_percent_funding) * funding) / adult_pop
        child_ubi = (child_percent_funding * funding) / child_pop
    else:
        child_percent_ubi /= 100
        adult_ubi = funding / (adult_pop + (child_pop * child_percent_ubi))
        child_ubi = adult_ubi * child_percent_ubi

    tax_rate = funding / total_taxable_income

    spmu["new_tax"] = tax_rate * spmu.tax_inc
    spmu["spm_ubi"] = (spmu.child * child_ubi) + (spmu.adult * adult_ubi)

    spmu["new_spm_resources"] = (
        spmu.spm_resources + spmu.spm_ubi - spmu.new_tax
    )
    spmu["new_spm_resources_pp"] = spmu.new_spm_resources / spmu.spm_numper

    # Calculate poverty gap
    poverty_gap = pov_gap(
        spmu, "new_spm_resources", "spm_povthreshold", "spm_weight"
    )

    # Merge person and spmu dataframes
    spmu_sub = spmu[["spm_id", "new_spm_resources", "new_spm_resources_pp"]]
    target_persons = pd.merge(spmu_sub, person, on=["spm_id"])

    target_persons["poor"] = (
        target_persons.new_spm_resources < target_persons.spm_povthreshold
    )
    total_poor = (target_persons.poor * target_persons.person_weight).sum()
    poverty_rate = total_poor / pop * 100

    # Calculate Gini
    gini = mdf.gini(target_persons, "new_spm_resources_pp", w="person_weight")

    # Percent winners
    target_persons["better_off"] = (
        target_persons.new_spm_resources > target_persons.spm_resources
    )
    total_better_off = (
        target_persons.better_off * target_persons.person_weight
    ).sum()
    percent_better_off = total_better_off / pop

    return pd.Series(
        {
            "poverty_rate": poverty_rate,
            "gini": gini,
            "poverty_gap": poverty_gap,
            "percent_better_off": percent_better_off,
            "adult_ubi": adult_ubi,
            "child_ubi": child_ubi,
        }
    )
Ejemplo n.º 16
0
                                       index="state",
                                       columns="sim_flag")


# Construct poverty percentage changes
def percent_change(base, new):
    return 100 * (new - base) / new


state["poverty_change_cc"] = percent_change(state.baseline,
                                            state.cc_replacement)
state["poverty_change_flat"] = percent_change(state.baseline,
                                              state.child_allowance)

# Gini coefficients
mdf.gini(person_sim, "spmftotval", "asecwt")
mdf.gini(person_sim, "resources_pp", "asecwt")
person_sim.groupby("sim_flag").apply(
    lambda x: mdf.gini(x, "spmftotval", "asecwt"))
person_sim.groupby("sim_flag").apply(
    lambda x: mdf.gini(x, "resources_pp", "asecwt"))

# Re-arrange by poverty rate
state.sort_values(by="poverty_change_flat", ascending=False)

# Interesting findings:
# Flat transfer: Roughly 10* the impact on poverty and gini coefficient
# compared to the childcare provision equivalent policy (paying costs)
# The poverty change is much larger for female-identifying people.
# The poverty change for the flat transfer is largest for Black and
# Hispanic populations ~3%, lower for White ~1.2%, and other non-hispanic ~1.8%.