Distanz- & Grenzpuzzle

18.05.2020

Heute geht es um zwei Puzzles in der internationalen Außenwirtschaft: Warum bleibt Distanz so relevant für den Welthandel? Und warum handeln Länder so viel mit sich selbst?

Vorlesung

Fullscreen PDF Audio


Anwendung

Gegenstand der Anwendung heute sind ebenfalls die Distanz- und Grenzpuzzles des internationalen Handels.

Daten laden und vorbereiten

Starten Sie RStudio und legen Sie neues Projekt an. Wie zuvor benötigen wir eine Reihe von Packages:

pacman::p_load(readr)
pacman::p_load(data.table)
pacman::p_load(stringr)
pacman::p_load(ggplot2)
pacman::p_load(lfe)
pacman::p_load(alpaca)

Wir nutzen zwei vorherige Datensätze. Zum einen den Datensatz mit Zeitdimension der letzten Woche, zum anderen später auch den separaten Gravity-Variablen Datensatz. Laden Sie daher diese beiden Datensatz:

Laden Sie den ersten Datensatz mittels read_rds():

# Daten laden ####
data_gravity = read_rds("input/trade_gravity.rds")

Wir reduzieren das Sample auf die Jahre ab 1960, und indizieren die Daten nach Jahren und Ländern:

data = data[year >= 1960]
setkey(data, year, iso_o, iso_d)

Der setkey-Command beschleunigt subset-Operationen später im Code.3 Wir schätzen wieder Regressionen mit fixen Effekten, diese werden wieder wie folgt generiert:

# Fixe Effekte generieren ####
data[, iso_o_year := str_c(iso_o, year)]
data[, iso_d_year := str_c(iso_d, year)]

Distanzpuzzle

Wir schauen uns zunächst die Entwicklung des Distanzkoeffizienten über die Zeit an. Dafür nutzen wir einen for-Loop, der eine Codeabschnitt für unterschiedliche Ausprägungen einer Variable evaluiert. Ein Beispiel für einen simplen Loop:

> for (i in c(1:3)) {
+     print(i)
+ }
[1] 1
[1] 2
[1] 3

In unserem Fall wird über die Jahre in den Daten iteriert — um dieselbe Gravity-Gleichung für unterschiedliche Jahre zu schätzen. Dies kann man u.A. so machen:

# Distanzpuzzle ####
years = unique(data$year)
coefs = data.table()

for (y in years) {

  print(y)

  # regressions
  reg_ols = felm(log(value) ~ log(distw) + fta + colony + comcur + comlang_off + contig |
                   iso_o_year + iso_d_year,
                 data = data[year == y & value > 0])
  reg_ppml = feglm(value ~ log(distw) + fta + colony + comcur + comlang_off + contig |
                    iso_o_year + iso_d_year,
                  family = poisson(),
                  data = data[year == y])

  # collect coefficients
  coefs = rbind(coefs,
                data.table(year = y, estimator = "OLS", t(coef(reg_ols))))
  coefs = rbind(coefs,
                data.table(year = y, estimator = "PPML", t(coef(reg_ppml))))

  # clean up
  rm(reg_ols, reg_ppml)

}

Die Daten werden also in jeder Runde auf das bestimmte Jahr mittels data = data[year == y] gesubsettet. Wir plotten nun zunächst einfach die Koeffizienten:

plot = ggplot(coefs) +
  theme_minimal() +
  geom_point(aes(x = year, y = abs(`log(distw)`), color = estimator)) +
  geom_smooth(aes(x = year, y = abs(`log(distw)`), color = estimator), se = F) +
  scale_y_continuous("Distanzelastizität") +
  scale_color_manual("Schätzer", values = c("OLS" = "red", "PPML" = "darkgreen")) +
  theme(legend.position="bottom") +
  theme(axis.title.x = element_blank())
print(plot)
ggsave(plot, filename = "output/distanzelastizitaet.png", width = 20, height = 10, units = "cm")
rm(plot, coefs)

Die rote und grüne Linie in der Grafik sehen fast identisch aus zu denen auf Folie 5 — der Distanzkoeffizient wächst über die Zeit für OLS und bleibt ziemlich ähnlich für die PPML Schätzungen.

Interner Handel

Wie Yotov (2012) soll nun der intranationale Handel integriert werden. Woher kann man hierfür Daten bekommen? Das ist normalerweise recht schwer, daher greift man meistens zu einem Trick: Alles was in einem Land produziert, aber nicht exportiert wird, wird als Proxy für den internen Handel herangezogen. Dazu aber erst gleich, zuerst laden wir die anderen Gravity-Variablen, insbesondere die Distanz, und bringen diese für unsere Anwendung in Form:

# Gravity-Daten laden
data_gravity = read_rds("input/gravity_data.rds")
data_gravity = data_gravity[iso3_o == iso3_d,
                            .(iso_o = iso3_o,
                              iso_d = iso3_o,
                              distw)]
data_gravity[, fta := 0]
data_gravity[, colony := 0]
data_gravity[, comcur := 0]
data_gravity[, comlang_off := 0]
data_gravity[, contig := 0]

Nun konstruieren wir die internen Handelsflüsse wie beschrieben…

# Handelsflüsse und weitere Variablen konstruieren
data_trade = data[, .(gdp_o = unique(gdp_o), exports = sum(value)), by = .(year, iso_o)]
data_trade[, iso_d := iso_o]
data_trade[, gdp_d := gdp_o]
data_trade[, iso_o_year := str_c(iso_o, year)]
data_trade[, iso_d_year := str_c(iso_d, year)]
data_trade[, value := gdp_o - exports]
data_trade[, exports := NULL]

… mergen diese mit den internen Gravity-Variablen…

# Mergen
data_internal = merge(data_trade,
                      data_gravity,
                      by = c("iso_o", "iso_d"))
rm(data_trade, data_gravity)

und fügen die an unseren eigentlichen Datensatz dran:

# Internationalen und *Intra*-nationalen Handel zusammenfügen
data = rbind(data,
             data_internal)
rm(data_internal)

Um diese intranationalen von internationalen Handelsströmen einfach unterschieden zu können, wird eine Indikatorvariable hierfür kreiiert:

# Indikatorvariable für intranationalen Handelsstrom
data[, same_country := iso_o == iso_d]

Dadurch, dass die internen Exporte nur imputiert sind, kann es zu Datenunstimmigkeiten kommen. Daher bei solchen “Tricks” immer kontrollieren, ob auch alles seine Richtigkeit hat:

head(data)
hist(data[same_country == T]$value)

Tatsächlich scheinen einige Länder negativen Handel mit sich selbst zu führen. Das kann natürlich nicht sein, und ist im Zweifelsfall auf sogenannte Transshipments zurückzuführen.4 Diese negativen Werte sollten aus den Daten mittels NA entfernt werden:

# Negative Werte entfernen
head(data[value < 0])
data[value < 0, value := NA]

Wir schätzen nun die gleiche Spezifikation von oben noch einmal, mit dem Unterschied, dass intranationaler Handel und dessen Distanzelastizität mittels einer Interaktionsvariablen gesondert behandelt werden:

# nochmal den Loop laufen lassen
years = unique(data$year)
coefs = data.table()

for (y in years) {

  print(y)

  # regressions
  reg_ols = felm(log(value) ~ same_country : log(distw) +
                   fta + colony + comcur + comlang_off + contig |
                   iso_o_year + iso_d_year,
                 data = data[year == y & value > 0])
  reg_ppml = feglm(value ~ same_country : log(distw) +
                     fta + colony + comcur + comlang_off + contig |
                     iso_o_year + iso_d_year,
                   family = poisson(),
                   data = data[year == y])

  # collect coefficients
  coefs = rbind(coefs,
                data.table(year = y, estimator = "OLS", t(coef(reg_ols))))
  coefs = rbind(coefs,
                data.table(year = y, estimator = "PPML", t(coef(reg_ppml))))

  # clean up
  rm(reg_ols, reg_ppml)

}

Auch das können wir wieder plotten, nun aber für beide Distanzelastizitäten:

# plot!
plot = ggplot(coefs) +
  theme_minimal() +
  geom_point(aes(x = year, y = abs(`same_countryFALSE:log(distw)`), color = estimator)) +
  geom_smooth(aes(x = year, y = abs(`same_countryFALSE:log(distw)`), color = estimator), se = F) +
  geom_point(aes(x = year, y = abs(`same_countryTRUE:log(distw)`), color = estimator)) +
  geom_smooth(aes(x = year, y = abs(`same_countryTRUE:log(distw)`), color = estimator), se = F) +
  scale_y_continuous("Distanzelastizität") +
  scale_color_manual("Schätzer", values = c("OLS" = "red", "PPML" = "darkgreen")) +
  theme(legend.position="bottom") +
  theme(axis.title.x = element_blank())
print(plot)

Das Bild ist recht unübersichtlich, daher plotten wir nun, wie von Yotov (2012) vorgeschlagen, die Differenz zwischen den beiden Koeffizienten:

# Differenz zwischen beiden Koeffizienten
coefs[, difference_distance_coef := `same_countryFALSE:log(distw)` - `same_countryTRUE:log(distw)`]

# plot!
plot = ggplot(coefs) +
  theme_minimal() +
  geom_point(aes(x = year, y = abs(difference_distance_coef), color = estimator)) +
  geom_smooth(aes(x = year, y = abs(difference_distance_coef), color = estimator), se = F) +
  scale_y_continuous("Distanzelastizität") +
  scale_color_manual("Schätzer", values = c("OLS" = "red", "PPML" = "darkgreen")) +
  theme(legend.position="bottom") +
  theme(axis.title.x = element_blank())
print(plot)
ggsave(plot, filename = "output/distanzelastizitaet_differenz.png", width = 20, height = 10, units = "cm")
rm(plot, coefs)

Voila!

Grenzpuzzle

Zuletzt nun zum Grenzpuzzle: Wie kommt es, dass Länder so viel mit sich selbst handeln? Wie in der Vorlesung schauen wir uns den Effekt für das ganze Sample an, sowie für OECD Mitgliedsstaaten. Hierzu generieren wir zunächst einen Dummy für die OECD Mitgliedschaft eines Landes:

# OECD Mitglied?
data[, oecd := iso_o %in% c("CAN", "USA", "GBR", "DEN", "ICE",
                            "NOR", "TUR", "ESP", "PRT", "FRA",
                            "IRL", "BEL", "DEU", "GRC", "SWE",
                            "CHE", "AUT", "NLD", "LUX", "ITA",
                            "JPN", "FIN", "AUS", "NZL", "MEX",
                            "CZE", "HUN", "POL", "KOR", "SLV")]

und lassen dann den Loop noch einmal in leicht geänderter Fassung durchlaufen:

# nochmal den Loop laufen lassen, diesmal nur PPML aber mit zwei unterschiedlichen Samples
years = unique(data$year)
coefs = data.table()

for (y in years) {

  print(y)

  # regressions
  reg_ppml = feglm(value ~ log(distw) + fta + colony + comcur + comlang_off + contig + same_country |
                     iso_o_year + iso_d_year,
                   family = poisson(),
                   data = data[year == y])
  reg_ppml_oecd = feglm(value ~ log(distw) + fta + colony + comcur + contig + same_country |
                                 iso_o_year + iso_d_year,
                               family = poisson(),
                               data = data[year == y & oecd == 1])

    # collect coefficients
  coefs = rbind(coefs,
                data.table(year = y, estimator = "PPML", t(coef(reg_ppml))), fill = T)
  coefs = rbind(coefs,
                data.table(year = y, estimator = "PPML (OECD Mitglied)", t(coef(reg_ppml_oecd))), fill = T)

  # clean up
  rm(reg_ppml, reg_ppml_oecd)

}

# plot
plot = ggplot(coefs) +
  theme_minimal() +
  geom_point(aes(x = year, y = same_countryTRUE, color = estimator)) +
  geom_smooth(aes(x = year, y = same_countryTRUE, color = estimator), se = F) +
  scale_y_continuous("Grenzeffekt") +
  scale_color_manual("Schätzer", values = c("PPML (OECD Mitglied)" = "blue", "PPML" = "darkgreen")) +
  theme(legend.position="bottom") +
  theme(axis.title.x = element_blank())
print(plot)
ggsave(plot, filename = "output/grenzpuzzle.png", width = 20, height = 10, units = "cm")
rm(plot)

Und tatsächlich: Zwar geht der Grenzeffekt für alle Länder zurück, aber er ist auch am Ende des Datensatzes, 2006, noch beträchtlich. Länder handeln im Durchschnitt exp(2.68) = 14,59 Mal so viel mit sich selbst, im Vergleich zu anderen Ländern. Der Effekt ist über die Zeit deutlich geringer für OECD Länder, jedoch ist die jährliche Verringerung des geschätzten Koeffizienten geringer, so dass am Ende in 2006 ein sehr ähnlicher Grenzeffekt herauskommt: exp(2.53) = 12,55.


  1. Head, K., Mayer, T. & Ries, J. (2010), “The erosion of colonial trade linkages after independence”. Journal of International Economics, 81(1):1-14 ↩︎

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

  3. Einige der heutigen Berechnungen können ein paar Minuten dauern. Falls diese zu lange dauern, können Sie das Sample weiter einschränken, z.B. auf Jahre seit 1990. ↩︎

  4. Die Niederlande sind hierfür ein gutes Beispiel: Der Hafen von Rotterdam ist Ausgangspunkt für viele Fahrten von Frachtschiffen, so dass hier viele Exporte scheinbar ihren Ursprung haben, obwohl dieser eigentlich ein anderes Land als die Niederlande ist. ↩︎