from pathlib import Path

import numpy as np
import pandas as pd

pd.options.plotting.backend = "plotly"

from gettsim import (
    compute_taxes_and_transfers,
    set_up_policy_environment,
)

DATA = Path("/tmp/Daten_FSP/")  # noqa: S108

Präsenzphase: Verteilungsmaße anhand des SOEP#

Nachdem wir letzte Woche GETTSIM auf das Sozio-oekonomische Panel (SOEP) angewendet haben, wollen wir diese Woche Ungleichheitsmaße im SOEP berechnen.

Datensäuberung (5 Minuten)#

Die Säuberung ist identisch zu letzter Woche, Sie müssen sie nicht erneut im Detail nachvollziehen.

data_cleaned = pd.read_pickle(DATA / "gettsim_data_soep_2019.pkl")  # noqa: S301
data_cleaned["hh_id"] = data_cleaned["hh_id"].astype(int)
data_cleaned["tu_id"] = data_cleaned["tu_id"].astype(int)
data_cleaned = data_cleaned.set_index(["hh_id", "tu_id", "p_id"]).sort_index()

Einige Spalten werden recodiert, einige Spalten erhalten einen neuen Typ.

data_cleaned = data_cleaned.reset_index()
data_cleaned = data_cleaned.drop(["anz_kinder_hh"], axis=1)

# GETTSIM unterstützt nur eine tax units pro Haushalt.
data_cleaned["hh_id"] = data_cleaned["tu_id"]

# Fehlende Werte auf 0 setzen.
for c in [
    "kindergeld_hh",
    "kinderzuschlag_hh",
    "grundr_zeiten",
    "grundr_bew_zeiten",
    "bruttolohn_vorj_m",
]:
    data_cleaned[c] = data_cleaned[c].fillna(0)

# Jahresangaben runden
for c in [
    "jahr_renteneintr",
    "immobilie_baujahr_hh",
    "grundr_zeiten",
    "grundr_bew_zeiten",
]:
    data_cleaned[c] = data_cleaned[c].round(0)

# Boolean Datentyp
for c in [
    "weiblich",
    "wohnort_ost",
    "anwartschaftszeit",
]:
    data_cleaned[c] = data_cleaned[c].astype(bool)

# Integer Datentyp
for c in [
    "alter",
    "geburtsmonat",
    "geburtsjahr",
    "jahr_renteneintr",
    "m_elterngeld",
    "behinderungsgrad",
    "immobilie_baujahr_hh",
    "grundr_zeiten",
    "grundr_bew_zeiten",
]:
    data_cleaned[c] = data_cleaned[c].astype(int)

# Float Datentyp
for c in ["sozialv_pflicht_5j"]:
    data_cleaned[c] = data_cleaned[c].astype(float)

# Unbekannte Werte zu 0
for c in [
    "m_pflichtbeitrag",
    "m_freiw_beitrag",
    "m_mutterschutz",
    "m_arbeitsunfähig",
    "m_krank_ab_16_bis_24",
    "m_arbeitslos",
    "m_ausbild_suche",
    "m_schul_ausbild",
    "m_geringf_beschäft",
    "m_alg1_übergang",
    "m_ersatzzeit",
    "m_kind_berücks_zeit",
    "m_pfleg_berücks_zeit",
    "y_pflichtbeitr_ab_40",
    "kind_unterh_anspr_m",
]:
    data_cleaned[c] = 0.0

data_cleaned["bruttolohn_vorj_m"] = data_cleaned["bruttolohn_vorj_m"].replace(np.inf, 0)

data_cleaned = data_cleaned.set_index(["hh_id", "tu_id", "p_id"]).sort_index()

Äquivalenzeinkommen OECD (15 Minuten)#

Von letzter Woche übernehmen wir auch die Berechnung des Äquivalenzeinkommens der OECD.

Verfügbares Einkommen mit GETTSIM berechnen#

params_dict, policy_func_dict = set_up_policy_environment(2019)

ergebnisse_personen = compute_taxes_and_transfers(
    data=data_cleaned.reset_index(),
    functions=policy_func_dict,
    params=params_dict,
    targets=[
        "kindergeld_m_hh",
        "sozialv_beitr_m",
        "arbeitsl_geld_m",
        "arbeitsl_geld_2_m_hh",
        "kindergeld_m_tu",
        "wohngeld_m_hh",
        "kinderzuschl_m_hh",
        "eink_st_tu",
        "soli_st_tu",
    ],
)
ergebnisse_personen = ergebnisse_personen.join(
    data_cleaned.reset_index()[["bruttolohn_m", "hh_id"]],
)

ergebnisse = (
    ergebnisse_personen.reset_index()
    .groupby("hh_id")
    .agg(
        {
            "bruttolohn_m": lambda x: x.sum(),
            "kindergeld_m_hh": lambda x: x.max(),
            "eink_st_tu": lambda x: x.max() / 12,
            "soli_st_tu": lambda x: x.max() / 12,
            "sozialv_beitr_m": lambda x: x.sum(),
            "arbeitsl_geld_2_m_hh": lambda x: x.max(),
            "arbeitsl_geld_m": lambda x: x.sum(),
            "wohngeld_m_hh": lambda x: x.max(),
            "kinderzuschl_m_hh": lambda x: x.max(),
        },
    )
)

# Variablen korrekt benennen
ergebnisse = ergebnisse.rename(
    columns={
        "eink_st_tu": "einkommensteuer_m_tu",
        "soli_st_tu": "soli_m_tu",
        "bruttolohn_m": "bruttolohn_m_hh",
        "sozialv_beitr_m": "sozialv_beitr_m_hh",
        "arbeitsl_geld_m": "arbeitsl_geld_m_hh",
    },
)

ergebnisse["verfügbares_einkommen_m_hh"] = (
    ergebnisse["bruttolohn_m_hh"]
    + ergebnisse["kindergeld_m_hh"]
    + ergebnisse["arbeitsl_geld_m_hh"]
    + ergebnisse["arbeitsl_geld_2_m_hh"]
    + ergebnisse["kinderzuschl_m_hh"]
    + ergebnisse["wohngeld_m_hh"]
    - ergebnisse["einkommensteuer_m_tu"]
    - ergebnisse["soli_m_tu"]
    - ergebnisse["sozialv_beitr_m_hh"]
)

ergebnisse
data_cleaned = data_cleaned.reset_index().set_index("hh_id")

hh_data = data_cleaned.groupby("hh_id")[
    ["sonstig_eink_m", "eink_selbst_m", "eink_vermietung_m"]
].sum()

hh_data = hh_data.join(data_cleaned["kapital_eink_m_hh"])
hh_data = hh_data.join(ergebnisse["verfügbares_einkommen_m_hh"])
hh_data = hh_data.rename(
    columns={
        "sonstig_eink_m": "sonstig_eink_m_hh",
        "eink_selbst_m": "eink_selbst_m_hh",
        "eink_vermietung_m": "eink_vermietung_m_hh",
    },
)
hh_data

Nettohaushaltseinkommen berechnen#

hh_data["einkommen_m_hh"] = hh_data[
    [
        "verfügbares_einkommen_m_hh",
        "sonstig_eink_m_hh",
        "kapital_eink_m_hh",
        "eink_selbst_m_hh",
        "eink_vermietung_m_hh",
    ]
].sum(axis=1)

Bestimmen der Gewichte#

Wir berechnen für Sie die Anzahl der Erwachsenen, Jugendliche ab 14 Jahren und Kinder im Haushalt.

anz_kinder_bis_13 = (
    data_cleaned.query("alter < 14 & kind == True").groupby("hh_id").size()
).to_frame("anz_kinder_bis_13")

anz_kinder_ab_14 = (
    data_cleaned.query("alter >= 14 & kind == True").groupby("hh_id").size()
).to_frame("anz_kinder_ab_14")

anz_erwachsene = (data_cleaned.query("kind == False").groupby("hh_id").size()).to_frame(
    "anz_erwachsene",
)

hh_data = hh_data.join(
    [
        anz_kinder_bis_13,
        anz_kinder_ab_14,
        anz_erwachsene,
    ],
)

hh_data["anz_kinder_bis_13"] = hh_data["anz_kinder_bis_13"].fillna(0).astype(int)
hh_data["anz_kinder_ab_14"] = hh_data["anz_kinder_ab_14"].fillna(0).astype(int)

hh_data

Wir haben die Funktion von letzter Woche übernommen.

def oecd_skala(data):
    """Berechne Gewichtungsfaktor für OECD-Äquivalenzskala.

    Args:
        data (pd.DataFrame): Datensatz mit Spalten für Anzahl Erwachsene und Kinder.

    Returns:
        pd.Series: Gewichtungsfaktor für OECD-Äquivalenzskala.
    """
    return (
        1
        + 0.5 * (data["anz_erwachsene"] + data["anz_kinder_ab_14"] - 1)
        + 0.3 * data["anz_kinder_bis_13"]
    )

In der folgenden Zelle wird der Gewichtungsfaktor laut OECD berechnet.

hh_data["Gewichtungsfaktor OECD"] = oecd_skala(hh_data)

Bestimmen des Äquivalenzeinkommens#

hh_data["Nettoäquivalenzeinkommen OECD"] = (
    hh_data["einkommen_m_hh"] / hh_data["Gewichtungsfaktor OECD"]
)
hh_data

Aufgabe 1: Armutsrisikoquote (45 Minuten)#

Wir generieren zunächst eine Indikatorvariable, die angibt, ob ein Haushalt dem Armutsrisiko unterliegt.

Armutsgefährdungsindikator#

hh_data["armutsgefährdet"] = hh_data["Nettoäquivalenzeinkommen OECD"] < 0.6 * hh_data[
    "Nettoäquivalenzeinkommen OECD"
].quantile(0.5)
hh_data.loc[hh_data["Nettoäquivalenzeinkommen OECD"].isna(), "armutsgefährdet"] = np.nan

Berechnen Sie dann zunächst die deutschlandweite Armutsrisikoquote.

Armutsrisikoquote deutschlandweit#

Wir schätzen die Armutsrisikoquote in Deutschland auf ca. 19%. Das ist höher als wenn man das volle Sample mit den vollständigen Einkommensdaten verwendet. Zum Vergleich: https://www.armuts-und-reichtumsbericht.de/DE/Indikatoren/Armut/Armutsrisikoquote/A01-Indikator-Armutsrisikoquote.html

Sozioökonomischen Faktoren der Bezugsperson#

Schauen Sie sich dann die Risikoquote getrennt nach unterschiedlichen sozioökonomischen Faktoren der Bezugsperson (Head of Household) an:

  • Alter der Bezugsperson

  • Anzahl der Kinder unter 13 Jahren

  • Bildungsstand der Bezugsperson

  • Alleinerziehend

  • Ost-West

bezugsperson_data = (
    data_cleaned.query("hh_position == 'Household head'")
    .join(hh_data, rsuffix="_data_hh")
    .reset_index()
    .set_index(["hh_id", "p_id"])
)
bezugsperson_data

Alter der Bezugsperson#

bezugsperson_data["alter"].describe()

Um einen Bargraphen erstellen zu können, teilen wir das Alter in Gruppen auf.

bezugsperson_data["alter_kat"] = np.where(
    bezugsperson_data["alter"].isin(range(18, 26)),
    "18-25",
    np.where(
        bezugsperson_data["alter"].isin(range(26, 66)),
        "26-65",
        np.where(bezugsperson_data["alter"].isin(range(66, 101)), "66-100", np.nan),
    ),
)
bezugsperson_data["alter_kat"].value_counts()
plot_data = (
    bezugsperson_data.groupby("alter_kat")["armutsgefährdet"]
    .mean()
    .to_frame()
    .reset_index()
)
plot_data.plot.bar(x="armutsgefährdet", y="alter_kat", orientation="h")

Anzahl Kinder unter 13 Jahren#

Ignorieren Sie die Werte für Familien mit sehr vielen Kindern. Normalerweise würden wir hier eine Kategorie “4+ Kinder” bilden, aber das ist nicht Lernziel der Aufgabe.

Bildungsstand der Bezugsperson#

Alleinerziehend#

Wohnort Ost/West#

Interpretieren Sie die Ergebnisse. Welche der Charakteristika stehen in der stärksten Beziehung zum Armutsrisiko in Deutschland?

Glauben Sie, dass dieser Beziehung ein kausaler Mechansimus unterliegt? Warum? Warum nicht?

Aufgabe 2: Weitere Ungleichheitsmaße (30 Minuten)#

Wählen Sie ihre zwei Lieblingsmaße zur Messung von Ungleichheit aus der Selbstlernphase. Berechnen und visualisieren Sie diese anhand der SOEP-Daten.

Über- oder unterschätzen wir die Ungleichheit systematisch in Deutschland, wenn wir sie anhand des SOEP berechnen? Begründen Sie Ihre Antwort.

Nehmen Sie hierbei an, dass die Maße, die Sie verwendet haben, die “korrekten” Maße zur Quantifizierung von Ungleichheit sind. Die Frage zielt nicht auf Unterschiede in den Maßen ab.

Aufgabe 3: Pentabilities (10min)#

Bitte bewerten Sie die Beiträge zur Gruppenarbeit in der Pentabilities-App. Bitte vergeben Sie über alle 5 Dimensionen hinweg Punkte für die Verhaltensweisen, welche Sie heute beobachten konnten. Denken Sie bitte daran, sowohl die Beiträge der Kommiliton:innen Ihrer Gruppe als auch Ihre eigenen zu bewerten.