PROYECTO FINAL NETWORK ANALYSIS (001)

Alumno: Bilver Adrian Astorquiza Bustos - U.S.A Labor Market Network

Profesor: Sergio Pulido Tamayo

Fecha: 28/05/2017

INTRODUCCIÓN

Este proyecto final se propone replicar el ejercicio realizado por Mike Silva, quien analiza el Mercado de Trabajo de los Estados Unidos a partir de la identificación del flujo de trabajadores desde su lugar de residencia (RESIDENCE) hacia su destino de trabajo (WORKPLACE) por medio de la Encuesta de la Comunicad American (ACS) durante el periodo 2006 a 2010. Esta encuesta es tomada del Census Transportation Planning Products (CTTPS) http://ctpp.transportation.org/Pages/5-Year-Data.aspx el cual permite un nivel de desagregación por Estados-Condado. Sin embargo, el proyecto propuesto para el curso replica únicamente dicho flujo hasta el nivel Estados, justificado en la medida que, la solicitud para obtener la base de datos por Estados-Condados está en lista de espera 12 con el número de identificación 6661. Por tal razón, una vez disponga de la información será posible replicar con exactitud los hallazgos del autor. Lo anterior hace que este ejercicio sea interesante pues permite exhibir el aprendizaje derivado del curso. En este sentido, el presente proyecto se desarrolla de la siguiente forma:

  • Fase I: Se inicia con la descarga de la base de datos y procesamiento de la información en Python; esto con el fin de construir, de la manera más adecuada, los nodos y los edges del ejercicio. Es oportuno precisar que los datos corresponden a los agentes que tienen 16 años o más, donde el peso del vinculo (edge) estará determinado por la cantidad de trabajadores, lo que se denomina como "Weight". Adicionalmente, el procedimiento contempla un proceso de depuración de los datos y una vez se efectua, es exportado como archivo "graphml".
  • Fase II: En esta etapa se procede a importar la nueva base de datos al programa Gephi con el fin de emprender la identificación de los "Communities" por medio de la métrica "Modularity Class" , quienes representan el conjunto de Estados que demandan en mayor proporción trabajadores en los Estados Unidos. Posteriormente, se da paso a la identificación de los nodos (Estados) más importantes por cuanto la población que trabaja en ellos es más alta en comparación con los otros nodos; logrando esto a partir de la métrica Degree Centrality.
  • Conclusiones: Se presenta de manera sucinta los principales hallazgos del presente ejercicio de replica, el cual al seguir los procesos descritos por el autor citado previamente, revisten de cierto interés académico.

Fase I: Procesamiento de la información

Los datos son extraidos en su versión "pura" de la página de CTTP, los cuales contiene el número de trabajadores de acuerdo al flujo de los mismos entre su residencia y lugar de trabajo; una variable llamada "Ouput", la cual recópila la cantidad de trabajadores estimada y con un margen de error. Sin embargo, el autor considera apropiado realizar una serie intervenciones a los datos con el fin de diseñar la red, los cuales los define a partir de los dos indentificadores que se encuentran en la variable Output. Así los procedimientos seguidos son:

  • Eliminar el dato si el nodo se conecta a sí mismo
  • Definir un umbral que permita establecer el peso de la red, recordando que este será el número de trabajadores pero con la particularidad que es de más de 100 trabajadores.
  • Eliminar el dato que sea considerado poco fiable al estar el margen de error por encima del umbral definido

Expuesto lo anterior, se da paso al procesamiento de información.


In [26]:
#Importar librerias requeridas para el ejercicio
import pandas as pd
import networkx as nx
from PIL import Image

#Identificación de parámetros
estimate_over_moe_threshold = 0.5
worker_threshold = 100
dont_link_to_self = True

#Leer Base de Datos
df = pd.read_csv('Job_4393.csv', low_memory=False, skiprows=2, thousands=',')
#print (df)

In [2]:
# Cambiar la variable 'Workers 16 and Over' de string a númerico
df['Workers 16 and Over'] = pd.to_numeric(df['Workers 16 and Over'])

# Contando los nodos y los edges del ejercicio
nodes_before = len(pd.DataFrame(pd.concat([df['RESIDENCE'], df['WORKPLACE']])).drop_duplicates())
edges_before = len(df)
print('El número de nodos es' ' ' +str(nodes_before)+ ' ' 'que representan los Estados de USA')
print('El número de edges es' ' ' +str(edges_before)+ ' ' 'que representan al flujo del agente entre su ciudad de residencia y de trabajo')


El número de nodos es 52 que representan los Estados de USA
El número de edges es 4798 que representan al flujo del agente entre su ciudad de residencia y de trabajo

In [3]:
# Cambiando de formato long (columna) a wide (fila) con el fin de empezar la depuración de los datos
left = df[df['Output']=='Estimate'].drop('Output', 1).rename(columns={'Workers 16 and Over':'Estimate'})
right = df[df['Output']=='Margin of Error'].drop('Output', 1).rename(columns={'Workers 16 and Over':'Margin of Error'})
df = pd.merge(left, right, on=['RESIDENCE','WORKPLACE'])

# Eliminación de datos de acuerdo al criterio 2
df['MOE over EST'] = df['Margin of Error'] / df['Estimate']
df = df[df['MOE over EST'] <= estimate_over_moe_threshold]

# Eliminando columnas Innecesarias, las cuales son las creadas anteriormente
df = df.drop(['Margin of Error', 'MOE over EST'], 1)

# Eliminando datos pequeñas de la base datos (trabajadores por debajo de 100)
df = df[df['Estimate'] >= worker_threshold]

# Eliminando vinculos que se conectan a si mismo
if dont_link_to_self:
    df = df[df['RESIDENCE'] != df['WORKPLACE']]

In [4]:
#print (df)

In [5]:
# Creando los nodos para exportar a Gephi
nodes = pd.DataFrame(pd.concat([df['RESIDENCE'], df['WORKPLACE']])).drop_duplicates().rename(columns={0:'County'})
nodes= nodes.reset_index(drop=True)
nodes['Id'] = nodes.index

In [6]:
# Anexando los codigos de los condados FIPS a los nodos

fips = pd.read_csv('fips.csv', low_memory=False,  converters={'FIPS': str})
nodes = pd.merge(nodes, fips)
#print (nodes)
#print (df)

In [7]:
# Ahora se adiciona la columna Source
df = pd.merge(df, nodes, left_on='RESIDENCE', right_on='County')
df = df.drop(['County', 'FIPS'], 1).rename(columns={'Id':'Source'})

# Ahora se adiciona la columna Target
df = pd.merge(df, nodes, left_on='WORKPLACE', right_on='County')
df = df.drop(['County','FIPS'], 1).rename(columns={'Id':'Target'})

# Contando los nodes y los edges
nodes_after = len(nodes)
edges_after = len(df)

#print (df)

In [10]:
# Calculo de los nodos iniciales y finales despues de realizar la depuración de datos con el fin de evaluar la pérdida de información
nodes_percent = nodes_after * 100 / nodes_before
edges_percent = edges_after * 100 / edges_before
print('Tenemos ahora' ' ' +str(nodes_after)+' de los '+str(nodes_before)+' nodes con que se inició el ejercicio. Estó da una tasa de -> ('+str(nodes_percent)+'%)')
print('Tenemos ahora' ' ' +str(edges_after)+' de los '+str(edges_before)+' edges con que se inició el ejercicio. Estó da una tasa de -> ('+str(edges_percent)+'%)')


Tenemos ahora 51 de los 52 nodes con que se inició el ejercicio. Estó da una tasa de -> (98.07692307692308%)
Tenemos ahora 1048 de los 4798 edges con que se inició el ejercicio. Estó da una tasa de -> (21.84243434764485%)

In [12]:
# Creamos el Grafo en python para posteriormnte importarlo a Gephi (Este será Dirigido)
G = nx.DiGraph()

# Add in the edges
for row in df.iterrows():
    G.add_edge(row[1][3], row[1][4], weight=row[1][2])
#print(G.edges())

In [13]:
#print (nodes)

In [15]:
# Etiquetas para los nodos 
labels = nodes[['Id','County']].to_dict()
labels = labels['County']
fips = nodes[['Id','FIPS']].to_dict()
fips = fips['FIPS']
nx.set_node_attributes(G, 'label', labels)
nx.set_node_attributes(G, 'fips', fips)

In [17]:
# Exportar el grafo de construido en Python a formato graphml y el listado de edges
nx.write_graphml(G,'U.S.A Labor Market.graphml')
# Pequeña validación de que el nodo tiene asociado su respectiva etiqueta (Label)
G.node[16]['label']


Out[17]:
'Kansas'

Fase II: Importar base de datos a Gephi

Una vez finaliza el diseño del grafo en python, se procede a importarlo a Gephi y emprender la identificación de las comunidades. En ese sentido, el software arroja la existencia de siete (7) communities, las cuales fueron establecidas de acuerdo al peso (weight) del vinculo, recordando que este es el número de trabajadores. Así, los procedimientos seguidos en Gephi fueron los siguientes:

  • Importar el archivo U.S.A Labor Market.graphml
  • Calcular el Modularity Class y posteriormente emplear el Layaout Frunchterman Reingold
  • Darle relevancia a los nodos con mayores número de trabajadores a partir de la opción Degree
  • Introducir los Labels a los nodos y disminuir el tamaño de los edges
  • Configurar el grafo encontrado con la opción Preview, para posteriormente importarlo en formato png y pdf
  • Exportar la base de datos correspondientes a los nodos, los cuales guardan información de las métricas calculadas.

De esta forma, el grafo que se presenta a continuación permite visualizar los Communities, que combinado con el comando "Counter" se reporta la cantidad de nodos que conforman cada uno de los Communities; luego entonces, hace apropiado concluir de manera preliminar que existen 2 comunidades que concentran la mayor cantidad de trabajadores, siendo estas la número 4, 5 y 0 en orden descendente.


In [1]:
from PIL import Image
img = Image.open('USA Labor Market.png')
img.show()

In [23]:
# Read in the Gephi output
Gephi = pd.read_csv('U.S. Labor Market [Nodes].csv', low_memory=False,  converters={'fips': str})
Gephi = Gephi[['fips','Modularity Class']]
#print(Gephi)

In [24]:
# Cambiar la variable 'Workers 16 and Over' de string a númerico
Gephi['Modularity Class'] = pd.to_numeric(Gephi['Modularity Class'])
Communities=pd.Series(Gephi['Modularity Class'])

In [25]:
from collections import Counter
Counter(Communities)


Out[25]:
Counter({0: 8, 1: 4, 2: 5, 3: 5, 4: 12, 5: 12, 6: 5})

CONCLUSIONES

(1) Este ejercicio de replicar el flujo de trabajadores de los Estados Unidos desde su lugar de residencia hasta su lugar de trabajo es particularmente interesante por cuanto puede ser interpretado como un esfuerzo por detectar la demanda de trabajo que hacen los Estados; una vez es detectado las Communities claro está. En este sentido, se reconoce que el tamaño de la red no es muy grande (51 nodos), donde cada nodo tiene un grado promedio de apróximadamente 21, con la particularidad de que es una red dirigida y al calcular el Average Clustering Coefficient se obtiene un valor de 0.715 se puede concluir que hay una alta interconexión entre los nodos y el vecindario.

(2) La detección de los siete (7) Communities del ejercicio evidenció que existen 3 de ellos que, de acuerdo al peso del vinculo, hace posible aseverar que concentrar una mayor población trabajando, y por ende son las que demandan más manos de obra; mientras que existe uno que tiene una menor cantidad de Estados en comparación con el resto de Communities. En ese sentido, estas comunidades junto con sus estados son:

  • Communities 4 (doce Estados): Wyoming, Alaska, Nevada, Montana, Arizona, Utah, Hawaii, Idaho, Oregon, Colorado,California y Washington; siendo estas últimas tres parte de los Estados con mayor grado (Degree)
  • Communities 5 (doce Estados): North Dakotha, South Dakotha, Nebraska, Iowa, Wisconsi, Ohio, Tenesi, Kentucky, Indiana, Illinois, Michigan y Minesota; siendo este último Estado el de mayor grado (Degree)
  • Communities 0 (ocho Estados): New Mexico, Missisipi, Oklahoma, Lousiana, Missouri, Arkansas, Kansas y Texas; siendo este último Estado el de mayor grado (Degree)
  • Communities 1 (cuatro Estados): Maryland,Virginia, West Virginia y District of Columbia.

(3) Se espera replicar el ejercicio por completo una vez se cuente con la base de datos Estados-Condados; pues el autor identificó que existen 3040 nodos y 15309 edge, arrojando un total de 70 Communities; lo cual hace muy interesante observar cuales serían los condados que demandan mayor mano de obra, determinado por el número de trabajadores que conforman el peso de la red.

LIMITACIONES Y RETOS FUTUROS

(1) En principio, consideraba trabajar una red dinámica con la base de datos de CONFAMA pero ciertamente no logré darle la trasncición temporal al software Gephi y ante la restricción de tiempo, opté por seguir trabajando el ejercicio de Mieke; el cual condujo a que elevera sustancialmente mi curva de aprendizaje en Python. De igual forma, la manera en como se encontraba la base de datos no me hacia posible brindar una interpretación economica, dado que, las metricas estudiadas no se ajustan del todo bien, cuando estas son calculadas para redes bipartitas; según logré consultar en documentos publicados en la red.

(2) El mayor resto es ubicar el grafo en un mapa, el cual observé que este autor hizo por medio de la libreria "Basemap" pero por más que me documenté sobre ella no logré introducirla. Por tal razón, estaría agradecido si puede brindarme orientación sobre ello.

(3) Como transmití en númerosas ocasiones, este curso es mi primer paso para diseñar la estructura del segundo capítulo de mi tesis doctoral; el cual considero que, a estas alturas, cuento con las herramientas análiticas para realizarlo. Lo anterior se justifica que si bien quisiera replicar este ejercicio para Colombia si sería posible, pues al examinar la Gran Encuesta Integrada de hogares 2016 observé que la pregunta P388 identifica conclaridad el departamento donde el agente realiza el trabajo principalmente, mientras que en el modulo vivienda, cuento con información sobre el area metropolitana de Residencia. Si bien no son el mismo agente economico en el tiempo, puedo realizar el analisis como el replicado, ya que se si puedo obtener el número de trabajadores por Departamento. El resto será diseñar con calma esto.

                      **Terminado a las 2:32am del 29 de Mayo de 2017**