Strukturelle Gravitation
Wir leiten in dieser Einheit ein strukturelles Gravitationsmodell, das sogenannte Armington-Modell, her. In der Anwendung nutzen wir eine verallgemeinerte Version des strukturellen Gravitationsmodells zur Simulation des Handelseffekts des Brexits.
Vorlesung
Anwendung
Wir nutzen nun das in der Vorlesung erarbeitete verallgemeinerte strukturelle Gravitationsmodell zur Simulation der Effekte von Handelspolitik, am Beispiel des Brexits.
Daten laden und vorbereiten
Starten Sie RStudio
und legen Sie neues Projekt an.1 Wie in der letzten Einheit benötigen wir eine Reihe von Packages:
library(pacman)
p_load(readr)
p_load(ggplot2)
p_load(scales)
p_load(ggrepel)
p_load(data.table)
p_load(magrittr)
p_load(countrycode)
p_load(lfe)
Wir nutzen heute die selben Datensätze wie in der vergangenen Woche:
- trade_data.rds: Bilaterale Handelsdaten von UN Comtrade aus dem Jahr 2015
- gravity_data.rds: Bilaterale Gravity-Variablen vom CEPII, ursprünglich aus Head & Mayer (2014)2
Laden Sie die Daten und mergen Sie die beiden data.tables
, wie in der vergangenen Woche:
# daten laden und mergen ####
data_trade = read_rds("input/trade_data.rds")
data_trade = data_trade[flow == 1, .(iso_o = partner, iso_d = reporter, value)]
data_trade = data_trade[iso_o != iso_d]
data_gravity = read_rds("input/gravity_data.rds")
data_gravity = data_gravity[year == 2015]
setnames(data_gravity, c("iso3_o", "iso3_d"), c("iso_o", "iso_d"))
data = merge(data_gravity, data_trade, by = c("iso_o", "iso_d"))
rm(data_gravity, data_trade)
In dem Gravity Datensatz befinden sich zwei Variablen, die die Mitgliedschaft des importierenden und des exportierenden Landes in der WTO kennzeichnen, gatt_o
und gatt_d
. Hieraus kann leicht eine bilaterale wto
Variable generiert werden, die signalisiert, ob beide Länder in der WTO sind, was den bilateralen Handel beeinflussen könnte:
# variablen umformen und generieren ####
data[, wto := gatt_o * gatt_d]
Für die heutige Anwendung, die Berechnung von Handelseffekten im allgemeinen Gleichgewicht mittels eines strukturellen Gravitationsmodells, muss der Datensatz “quadratisch” sein. Das bedeutet, alle Länder die als Exporteur auftauchen, müssen auch als Importeur auftauchen. Um das sicherzustellen, subsetten wir dementsprechend:
# "quadratischen" datensatz für GE ####
data = data[, .(iso_o, iso_d,
value, distw, comlang_off, colony,
comcur, fta = fta_wto, wto, eu_o, eu_d)]
data = data[complete.cases(data)]
data = data[iso_o %in% data[, unique(iso_d)] & iso_d %in% data[, unique(iso_o)]]
Gravitationsmodell schätzen
Die Daten sind nun fertig vorbereitet. Wir schätzen jetzt, wie in der vergangenen Woche ein Gravitationsmodell:
# gravity schätzung ####
reg_gen_gravity = felm(log(value) ~ log(distw) +
comlang_off + colony +
wto + comcur + fta | iso_o + iso_d, data = data)
summary(reg_gen_gravity, se = "white")
Der Output sollte in etwa so aussehen:
Call:
felm(formula = log(value) ~ log(distw) + comlang_off + colony + wto + comcur + fta | iso_o + iso_d, data = data)
Residuals:
Min 1Q Median 3Q Max
-11.5117 -1.0016 0.0713 1.1090 10.1338
Coefficients:
Estimate Std. Error t value Pr(>|t|)
log(distw) -1.48925 0.02735 -54.452 < 2e-16 ***
comlang_off 1.07030 0.05730 18.677 < 2e-16 ***
colony 0.78812 0.13440 5.864 4.61e-09 ***
wto 0.47527 0.19602 2.425 0.0153 *
comcur -0.28060 0.12465 -2.251 0.0244 *
fta 0.49266 0.05116 9.630 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 2.018 on 16216 degrees of freedom
Multiple R-squared(full model): 0.7943 Adjusted R-squared: 0.7907
Multiple R-squared(proj model): 0.2637 Adjusted R-squared: 0.2507
F-statistic(full model):218.9 on 286 and 16216 DF, p-value: < 2.2e-16
F-statistic(proj model): 967.9 on 6 and 16216 DF, p-value: < 2.2e-16
Gibt es einen Unterschied zur Schätzung der letzten Woche? Nicht wirklich: Zwar war in der letzten Woche die Rede von einem generellen Gravitationsmodell, und in dieser Woche von einem strukturellen Model, aber in der Schätzung mit Fixed Effects sind beide de-facto gleich.
Benchmark berechnen
Neben der Produktion und der Nachfrage (die jeweilige Summe über die Exporte/Importe) können wir nun aus den geschätzten Koeffizienten die bilateralen Handelskosten, das $\phi_{ij}$ berechnen:
# general equilibrium benchmark ####
data[, Y := sum(value), by = iso_o]
data[, E := sum(value), by = iso_d]
data[, phi := exp(as.matrix(data[, .(log(distw), comlang_off, colony, wto, comcur, fta)]) %*% coef(reg_gen_gravity)) ]
Multilaterale Resistanzen berechnen
# multilateral resistance terms in iteration berechnen
data[, mlr_o := 1]
data[, mlr_d := 1]
criterion = mean(data$mlr_o + data$mlr_d)
criterion_old = 1
while (abs(criterion / criterion_old - 1) > 1e-15) {
criterion_old = criterion
data[, mlr_o := sum(E / mlr_d * phi), by = iso_o]
data[, mlr_d := sum(Y / mlr_o * phi), by = iso_d]
criterion = mean(data$mlr_o + data$mlr_d)
}
rm(criterion, criterion_old)
Handelsströme ausrechnen
# generate structural gravity trade flows für benchmark
data[, value_benchmark := Y / mlr_o * E / mlr_d * phi]
Partielles Gleichgewicht
# partial equilibrium effekt ####
data[, fta_brexit := fta]
data[iso_o == "GBR" | eu_d == T, fta_brexit := F]
data[iso_d == "GBR" | eu_o == T, fta_brexit := F]
data[, phi_brexit := exp(as.matrix(data[, .(log(distw), comlang_off, colony, wto, comcur, fta_brexit)]) %*% coef(reg_gen_gravity)) ]
# generate partial equilibrium trade flows für brexit
data[, value_brexit_pe := Y / mlr_o * E / mlr_d * phi_brexit]
# bar plot partial equilibrium effect ####
data_plot = data[iso_o == "GBR"][order(-value_benchmark)][1:10]
data_plot[, partner := countrycode(iso_d, "iso3c", "country.name.de")]
data_plot = data_plot[, .(partner, value_benchmark, value_brexit_pe)]
data_plot = melt(data_plot, id.vars = "partner")
plot = ggplot(data_plot) +
theme_minimal() +
geom_bar(aes(x = reorder(partner, -value), y = value, group = variable, fill = variable),
stat = "identity", position = "dodge") +
scale_y_continuous("Exportvolumen", labels = dollar_format(accuracy = 1)) +
scale_x_discrete(NULL) +
scale_fill_discrete(NULL, labels = c("Vorhersage ohne Brexit", "Vorhersage mit Brexit")) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(plot)
ggsave(plot, filename = "output/brexit_pe.png", width = 20, height = 10, units = "cm")
rm(data_plot, plot)
Kontrafaktisches allgemeines Gleichgewicht
# general equilibrium effect für brexit ####
data[, mlr_o_brexit := 1]
data[, mlr_d_brexit := 1]
criterion = mean(data$mlr_o_brexit + data$mlr_d_brexit)
criterion_old = 1
while (abs(criterion / criterion_old - 1) > 1e-15) {
criterion_old = criterion
data[, mlr_o_brexit := sum(E / mlr_d_brexit * phi_brexit), by = iso_o]
data[, mlr_d_brexit := sum(Y / mlr_o_brexit * phi_brexit), by = iso_d]
criterion = mean(data$mlr_o_brexit + data$mlr_d_brexit)
}
rm(criterion, criterion_old)
# generate structural gravity trade flows
data[, value_brexit_ge := Y / mlr_o_brexit * E / mlr_d_brexit * phi_brexit]
# bar plot general equilibrium effect ####
data_plot = data[iso_o == "GBR"][order(-value_benchmark)][1:10]
data_plot[, partner := countrycode(iso_d, "iso3c", "country.name.de")]
data_plot = data_plot[, .(partner, value_benchmark, value_brexit_pe, value_brexit_ge)]
data_plot = melt(data_plot, id.vars = "partner")
plot = ggplot(data_plot) +
theme_minimal() +
geom_bar(aes(x = reorder(partner, -value), y = value, group = variable, fill = variable),
stat = "identity", position = "dodge") +
scale_y_continuous("Exportvolumen", labels = dollar_format(accuracy = 1)) +
scale_x_discrete(NULL) +
scale_fill_discrete(NULL, labels = c("Vorhersage ohne Brexit",
"Vorhersage mit Brexit (PE)",
"Vorhersage mit Brexit (GE)")) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(plot)
ggsave(plot, filename = "output/brexit_ge.png", width = 20, height = 10, units = "cm")
rm(data_plot, plot)
One more thing
Warum sind die geschätzten Werte hier teilweise so weit entfernt von denen aus der Realität?
data_plot = data[iso_o == "GBR"][order(-value_benchmark)][1:10]
data_plot[, partner := countrycode(iso_d, "iso3c", "country.name.de")]
data_plot = data_plot[, .(partner, value, value_benchmark)]
data_plot = melt(data_plot, id.vars = "partner")
plot = ggplot(data_plot) +
theme_minimal() +
geom_bar(aes(x = reorder(partner, -value), y = value, group = variable, fill = variable),
stat = "identity", position = "dodge") +
scale_y_continuous("Exportvolumen", labels = dollar_format(accuracy = 1)) +
scale_x_discrete(NULL) +
scale_fill_discrete(NULL, labels = c("Beobachtete Exporte",
"Geschätzte Exporte")) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(plot)
ggsave(plot, filename = "output/geschaetzte_beobachtete_exporte.png", width = 20, height = 10, units = "cm")
rm(data_plot, plot)
Dazu mehr in der nächsten Vorlesung!