La diversificación económica y el impacto demográfico de la migración son mayores en municipios de tamaño intermedio. La estructura económica de un municipio tiende a parecerse a la de municipios de donde recibe más migrantes.
import pandas as pd
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import ticker, dates, colors, cm
import scipy.stats as stats
import networkx as nx
plt.style.use('publish/estilo.mplstyle')
Economías más grandes tienden a estar mejor diversificadas. En el caso de economías municipales en Bolivia, con datos de la cartera de créditos a unidades económicas, esta relación forma una curva sigmoidal donde es posible distinguir 3 tipos de economías:
La siguiente gráfica muestra el crecimiento entre 2012 y 2020 del valor y diversidad de economías municipales presentes en la cartera de créditos. El primer cuadro ilustra el desplazamiento entre 2012 y 2020 y el segundo representa la diferencia en el número de actividades en el mismo periodo. Clasifico economías intermedias como aquellas donde el número de actividades es igual o mayor que 5 e igual o menor que 300. Esta clasificación se muestra en un color naranja en ambos cuadros.
creditos = pd.read_csv('data/creditos.csv')
diversidad = pd.concat([creditos[creditos.cartera > 0].groupby(['year', 'cod_ine']).subclase.count(), creditos[creditos.cartera > 0].groupby(['year', 'cod_ine']).cartera.sum()], axis=1).reset_index()
def plot_diversidad():
lincolor = '#88888f'
dfi = pd.concat([diversidad[diversidad.year == year].set_index('cod_ine')[['subclase', 'cartera']] for year in [2012, 2020]], axis=1).dropna()
dfi.columns = ['s12', 'c12', 's20', 'c20']
dfi['color'] = dfi.s20.apply(lambda x: '#f2d4c4' if x >= 50 and x <= 300 else '#a1c0ff')
dfi['delta_s'] = dfi['s20'] - dfi['s12']
dfi['delta_c'] = dfi['c20'] - dfi['c12']
f, (ax1, ax2) = plt.subplots(1,2,figsize=(20,10))
plt.subplots_adjust(wspace=.03)
for i, row in dfi.iterrows():
ax1.plot([row['c12'], row['c20']], [row['s12'], row['s20']], color=lincolor, linewidth=.8, alpha=.5, zorder=1)
for x, y, size, alpha, linewidth, color in zip(['c12', 'c20'], ['s12', 's20'], [10, 25], [.5, 1.], [0, 1], [lincolor, dfi['color']]):
ax1.scatter(dfi[x], dfi[y], color=color, s=size, edgecolor=lincolor, alpha=alpha, linewidth=linewidth, zorder=2)
ax1.set_xlim(1e2 + 1, 1e11 - 1)
ax1.annotate('Número de actividades', xy=(-.1, .5), xycoords='axes fraction', ha='right', va='center', fontsize=14, color=lincolor, rotation=90)
ax2.scatter(dfi.c20, dfi.delta_s, color=dfi.color, s=35, edgecolor=lincolor, alpha=1., linewidth=.8, zorder=2)
ax2.set_ylim(-149,149)
ax2.set_xlim(1e3 + 1,1e11 - 1)
ax2.tick_params(labelleft=False, labelright=True)
ax2.annotate('Diferencia en el número de actividades', xy=(1.1, .5), xycoords='axes fraction', ha='right', va='center', fontsize=14, color=lincolor, rotation=270)
ax2.annotate('Valor de cartera (dólares americanos, log)', xy=(-.05, -.08), xycoords='axes fraction', ha='center', va='top', fontsize=14, color=lincolor)
for ax in [ax1, ax2]:
ax.set_xscale('symlog')
ax.grid()
ax.tick_params(labelcolor=lincolor)
plot_diversidad()
¿Qué guía la trayectoria de experimentación productiva en economías municipales? Un factor importante de diversificación son las capacidades productivas de la población. Municipios que se diversifican más podrían estar experimentando mayores cambios en las capacidades de su fuerza laboral. Una fuente significativa de estos cambios podría ser la migración hacia y desde cada municipio. Encuentro que el impacto composicional de la migración respecto a características relevantes a la capacidad productiva de la fuerza laboral es mayor en municipios en un proceso de experimentación productiva. Estos municipios exhiben más movimiento de gente joven, con más años de estudio y masculina. Los siguientes cuadros ilustran el impacto de la inmigración, emigración y migración relativa sobre la composición demográfica de cada municipio presente en cuadros anteriores, con datos de migrantes entre 2007 y 2012 registrados en el Censo 2012. Valores por encima y debajo de 0 representan cambios positivos y negativos respectivamente. Los colores siguen la misma lógica, identificando a municipios intermedios.
def make_cim(tipo, drop_outliers=True):
"""
Compositional Impact of Migration
"""
df = pd.read_csv('data/migracion_cortes.csv', index_col=[0])
cortes = pd.Series(df.columns).str.replace('(_20.*|_static)', '').unique()
if tipo == 'absoluto':
dfi = pd.DataFrame({corte: (df[corte + '_2012'] - df[corte + '_2007']) for corte in cortes})
elif tipo == 'relativo':
dfi = pd.DataFrame({corte: (df[corte + '_2012'] - df[corte + '_2007']) / df[corte + '_2007'] for corte in cortes})
elif tipo == 'in':
dfi = pd.DataFrame({corte: (df[corte + '_2012'] - df[corte + '_static']) for corte in cortes})
elif tipo == 'out':
dfi = pd.DataFrame({corte: (df[corte + '_static'] - df[corte + '_2007']) for corte in cortes})
if drop_outliers:
return dfi[(np.abs(stats.zscore(dfi)) < 3).all(axis=1)]
else:
return dfi
def plot_cim():
lincolor = '#88888f'
dfi = diversidad[diversidad.year == 2020].set_index('cod_ine')[['cartera', 'subclase']]
dfi['color'] = dfi.subclase.apply(lambda x: '#f2d4c4' if x >= 50 and x <= 300 else '#a1c0ff')
f, axs = plt.subplots(3,3,figsize=(12,12), sharex=True)
plt.subplots_adjust(hspace=.1, wspace=.1)
for row, tipo in zip(axs, ['in', 'out', 'relativo']):
cim = make_cim(tipo, drop_outliers=True)[['años_estudio_25_39', 'edad', 'masculinidad']]
common = list(set(cim.index).intersection(set(cartera.index)))
for ax, corte in zip(row, cim.columns):
ax.scatter(dfi.loc[common,'cartera'], cim.loc[common, corte], alpha=.7, s=20, color=dfi.loc[common, 'color'], edgecolor=lincolor, linewidth=.8)
limit = abs(cim[corte]).max() * 1.1
ax.set_ylim(0 - limit, limit)
ax.grid()
ax.set_xscale('log')
ax.set_yticklabels([])
ax.set_xticklabels([])
ax.annotate('{:.1f}'.format(limit), xy=(.02, .98), xycoords='axes fraction', ha='left', va='top', color=lincolor, fontsize=10, alpha=1.)
ax.annotate('{:.1f}'.format(-limit), xy=(.02, .02), xycoords='axes fraction', ha='left', va='bottom', color=lincolor, fontsize=10, alpha=1.)
ax.axhline(0, color=lincolor, linestyle='--', linewidth=.8)
axs[-1][-2].annotate('Valor de cartera (dólares americanos, log)', xy=(.5, -.1), xycoords='axes fraction', ha='center', va='top', color=lincolor, fontsize=12);
for col, title in zip(range(3), ['Años de estudio\nentre la población de 25 a 39 años', 'Edad media', 'Ratio de la\npoblación masculina / femenina']):
axs[0][col].annotate(title, xy=(.5, 1.1), xycoords='axes fraction', ha='center', va='bottom', color=lincolor, fontsize=12);
for row, text in zip(range(3), ['Inmigración', 'Emigración', 'Migración']):
axs[row][-1].annotate(text, xy=(1.1, .5), xycoords='axes fraction', ha='left', va='center', color=lincolor, fontsize=18);
plot_cim()
Si la migración dirige en parte el proceso de diversificación económica, municipios con más flujo migratorio entre sí deberían producir más actividades similares. El siguiente gráfico ilustra esta relación para la cartera de créditos en 2012 y 2020, y el flujo migratorio entre 2007 y 2012. Cada punto representa la relación entre un par de municipios y los puntos claros corresponden a relaciones sólo entre municipios intermedios. Existe una relación leve pero positiva entre el % de la población de un municipio que migra hacia un municipio de destino, y el % de sus actividades que están presentes en el municipio de destino.
def make_migration_matrix(matriz_filename='data/migracion_2012.csv', expected_type=int):
"""
Produce una matriz de adyancencias entre municipios donde la
población estaba en 2007 y 2012, según el Censo de Población
y Vivienda 2012. Cada índice y columna corresponde a un código
INE y cada valor es una persona.
"""
df = pd.read_csv(matriz_filename, index_col=[0])
d = pd.read_csv('data/cod_ine_censo2012.csv', names=['cod_ine', 'municipio'])
df.index = d.cod_ine
df.columns = d.cod_ine
for col in df.columns:
df[col] = pd.to_numeric(df[col].apply(lambda x: x.replace(' ', '').replace('-', ''))).fillna(0).astype(expected_type)
return df
def make_activity_matrix(year):
dfi = creditos.groupby(['cod_ine', 'year', 'subclase'])['cartera'].sum().reset_index()
dfi = dfi[(dfi.year == year) & (dfi.cartera > 0) & (dfi.cartera.notna())][['cod_ine', 'subclase']]
c_merge = dfi.merge(dfi, on='subclase')
results = pd.crosstab(c_merge.cod_ine_x, c_merge.cod_ine_y)
np.fill_diagonal(results.values, 0)
return results
def make_actividades_compartidas(year):
actividades_matrix = make_activity_matrix(year)
g1 = nx.from_pandas_adjacency(actividades_matrix, create_using=nx.DiGraph)
actividades_compartidas = nx.convert_matrix.to_pandas_edgelist(g1).rename(columns={'weight': 'actividades_compartidas'})
actividades_por_municipio = pd.Series({cod_ine:len(dfi.unique()) for cod_ine, dfi in creditos[creditos.year == year].groupby(['cod_ine']).subclase})
actividades_compartidas['actividades_source'] = actividades_compartidas.source.map(actividades_por_municipio.to_dict())
actividades_compartidas['actividades_target'] = actividades_compartidas.target.map(actividades_por_municipio.to_dict())
actividades_compartidas['actividades_compartidas_source'] = actividades_compartidas.actividades_compartidas / actividades_compartidas.actividades_source
actividades_compartidas['actividades_compartidas_target'] = actividades_compartidas.actividades_compartidas / actividades_compartidas.actividades_target
return actividades_compartidas
def make_flujo_migratorio():
migracion_matrix = make_migration_matrix()
np.fill_diagonal(migracion_matrix.values, 0)
flujo_migratorio = nx.convert_matrix.to_pandas_edgelist(nx.from_pandas_adjacency(migracion_matrix, create_using=nx.DiGraph)).rename(columns={'weight': 'migrantes'})
flujo_migratorio['poblacion_source'] = flujo_migratorio.source.map(poblacion[2012].to_dict())
flujo_migratorio['poblacion_target'] = flujo_migratorio.target.map(poblacion[2012].to_dict())
flujo_migratorio['emigrantes_por_poblacion'] = flujo_migratorio.migrantes / flujo_migratorio.poblacion_source
flujo_migratorio['inmigrantes_por_poblacion'] = flujo_migratorio.migrantes / flujo_migratorio.poblacion_target
return flujo_migratorio
poblacion = pd.read_csv('data/poblacion.csv', index_col='cod_ine', names=['cod_ine'] + list(range(2012, 2023)), skiprows=1)
flujo_migratorio = make_flujo_migratorio()
def plot_flujo_actividades(filtro_municipios=None):
lincolor = '#88888f'
f, axs = plt.subplots(1,2,figsize=(20,10), sharey=True)
plt.subplots_adjust(wspace=.02)
for ax, year in zip(axs, [2012, 2020]):
actividades_flujos = pd.concat([make_actividades_compartidas(year).set_index(['source', 'target']), flujo_migratorio.set_index(['source', 'target'])], axis=1).dropna().reset_index()
ax.scatter(actividades_flujos.emigrantes_por_poblacion, actividades_flujos.actividades_compartidas_source, color='#a1c0ff', edgecolor=lincolor, alpha=.3, s=20, linewidth=.8)
if filtro_municipios != None:
actividades_flujos = actividades_flujos[actividades_flujos.source.isin(filtro_municipios) & (actividades_flujos.target.isin(filtro_municipios))]
ax.scatter(actividades_flujos.emigrantes_por_poblacion, actividades_flujos.actividades_compartidas_source, color='#f2d4c4', edgecolor=lincolor, alpha=1., s=20, linewidth=.8)
ax.set_xscale('log')
ax.xaxis.set_major_formatter(ticker.PercentFormatter(1,3))
ax.yaxis.set_major_formatter(ticker.PercentFormatter(1,0))
ax.set_xticks(ax.get_xticks()[3:])
ax.set_ylim(0,1)
ax.set_xlim(0.000001,.1)
ax.grid()
ax.annotate(year, xy=(.5, 1.03), xycoords='axes fraction', ha='center', va='bottom', color=lincolor, fontsize=15)
ax.tick_params(labelcolor=lincolor)
axs[0].annotate('% de actividades que el municipio de origen que comparte con el de destino', xy=(-.1, .5), xycoords='axes fraction', ha='right', va='center', fontsize=14, color=lincolor, rotation=90)
axs[1].annotate('% de la población del municipio de origen que migra al de destino (log)', xy=(-.05, -.08), xycoords='axes fraction', ha='center', va='top', fontsize=14, color=lincolor)
plot_flujo_actividades(diversidad[(diversidad.year == 2020) & (diversidad.subclase >= 50) & (diversidad.subclase <= 300)].cod_ine.tolist())
Imagino al menos dos fenómenos entrelazados en esta relación:
Queda pendiente desarrollar mejor estas hipótesis y construir una prueba más robusta de la relación encontrada.