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.