Strukturelle Gravitation

04.05.2020

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

Fullscreen PDF Audio


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:

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!


  1. Sie können natürlich auch ein Projekt für die gesamte Vorlesung haben und lediglich neue Code Dateien je Einheit anlegen. ↩︎

  2. Head, K. and T. Mayer, (2014), “Gravity Equations: Toolkit, Cookbook, Workhorse.” Handbook of International Economics, Vol. 4,eds. Gopinath, Helpman, and Rogoff, Elsevier. ↩︎