text: # -*- coding: utf-8 -*-
  """epf_microdata_transform v0.0.1
  
  Automatically generated by Colaboratory.
  
  Original file is located at
      https://colab.research.google.com/drive/1X-aSibIKdP5XcIgwGAEX7ExjxPFau7zy
  
  # Procesamiento de microdatos de la Encuesta de Presupuestos Familiares
  ### Procedimiento para la transformacióón de los archivos de Microdatos descargados de la web del INE para su conversión en archivos CSV
  Nota: Con posterioridad, se pueden subir estos archivos a un servidor cloud para convertirlo en una base de datos analítica que permita explorar los datos mediante SQL
  
  #### Explicamos paso a paso la ejecutión del procesado de archivos:
  Procedimiento:
  1. Conectamos Drive (Paso 1) con el archivo y carpeta compartida "aca_folder"
  2. Introducimos los archivos ZIP previamente descargados desde la web del INE en la carpeta Drive "zip_microdatos"
  3. Ejecutamos todas las celdas que hay a continuación hasta el final
  4. Encontraremos los archivos CSV en la carpeta Drive "epf_folder", separados por hogar y gastos. 
  
  Dentro de cada ZIP descargado de la web del INE, en el apartado de datos habrá ficheros relativos a Hogares, Gastos y Miembros. Para este proceso de transformación, no consideramos los datos de Miembros ya que en el análisis previo al presente no se consideró para su estudio.
  
  Al tratarse de dos archivos relacionados, se ha elaborado un directorio de carpetas separando todos los archivos relativos a Hogar y Gastos. Para poder relacionarlos entre sí y facilitar su indexado, se elabora un ID combinando la fecha de la encuesta con la variable NUMERO, que es el id anual que proporciona el INE.
  
  
  **Paso 1:** Ejecutamos la celda haciendo click en el síímbolo de play (▶️) que aparece a la izquierda (colocar ratón por encima para visualizarlo).
  
  Conectamos con nuestro Drive para acceder el conjunto de carpetas que alojan nuestros datos y donde, después, se volcarán los resultados. Aparecerá un enlace. Hay que hacer click, aceptar los términos y copiar la clave para pegarla en la casilla.
  Una vez hecho, pulsar Enter.
  
  **Paso 2:** Haciendo click en la segunda casilla, pulsar el comando **Ctrl + F9**
  """
  
  from google.colab import drive
  drive.mount('/content/drive')
  
  import zipfile, os, shutil, json
  from datetime import date
  import pandas as pd
  import re
  
  #Rutas y directorios
  
  ascii_path = '/content/drive/My Drive/aca_folder/ascii_docs'
  zips_path = '/content/drive/My Drive/aca_folder/zip_microdatos'
  zips_2_path = '/content/drive/My Drive/aca_folder/zip_microdatos/second_zip_files'
  datos_zip = os.path.join(zips_path, 'datos')
  
  destination_path = os.path.join('/content/drive/My Drive/aca_folder', 'epf_folder')
  directory_gastos = os.path.join(destination_path,'tablas_gastos')
  directory_hogar = os.path.join(destination_path,'tablas_hogar')
  
  if not os.path.exists(destination_path):
      try:
          os.makedirs(destination_path)
      except OSError as e:
          if e.errno != errno.EEXIST:
              raise
  
  if not os.path.exists(directory_gastos) and not os.path.exists(directory_hogar):
      try:
          os.makedirs(directory_gastos)
          os.makedirs(directory_hogar)
          os.makedirs(datos_zip)
          os.makedirs(zips_2_path)
      except OSError as e:
          if e.errno != errno.EEXIST:
              raise
  if len(os.listdir(zips_2_path)) != 0:
    try:
      for filename in os.listdir(zips_2_path):
        os.remove(filename) 
    except OSError:
        pass
  
  #Definimos las funciones a emplear para extraer documentos ASCII de los ficheros comprimidos que nos descargamos del INE
  
  def unzip(source_filename, dest_dir):
      with zipfile.ZipFile(source_filename) as zf:
          for member in zf.infolist():
              words = member.filename.split('/')
              path = dest_dir
              for word in words[:-1]:
                  while True:
                      drive, word = os.path.splitdrive(word)
                      head, word = os.path.split(word)
                      if not drive:
                          break
                  if word in (os.curdir, os.pardir, ''):
                      continue
                  path = os.path.join(path, word)
              zf.extract(member, path)
  
  def safe_unzip(zip_file, extractpath='.'):
      with zipfile.ZipFile(zip_file, 'r') as zf:
          for member in zf.infolist():
              abspath = os.path.abspath(os.path.join(extractpath, member.filename))
              if abspath.startswith(os.path.abspath(extractpath)) and abspath.endswith(".zip"):
                  zf.extract(member, extractpath)
  
  # Archivos auxiliares
  
  # Diccionario con la información de nombre de columnas y posición dentro del archivo ASCII FWF (Fixed Width File). De este tipo de archivo, 
  # extraemos la columna y valores correspondientes en base a unas "coordenadas" que facilitan en un fichero para SPSS que viene descargado en el fichero disreg.zip
  
  # El diccinario se ha realizado ad hoc para los datos de la EPF.
  # To do: Implantar algoritmo que lea ese archivo con las coordoneadas SPSS y las añada al diccionario. 
  # Hay que tener en cuenta que se suma 1 al inicio de cada tupla[0] y comprobar que la tupla[1] encaje con el inicio de la siguiente.
  
  with open('/content/drive/My Drive/aca_folder/epf_fwf_info.json', 'r') as f:
    epf_fwf_info = json.load(f)
  
  # Extraemos los archivos zips de los ficheros descargados del INE
  # Los archivos del INE se estructuran en la siguiente arquitectura:
  # --datos_2018.zip
  #   |__datos_epf2018.zip
  #   |           |_______Fichero de usuario de gastos a2018
  #   |           |_______Fichero de usuario de hogar a2018
  #   |           |_______Fichero de usuario de miembros a2018
  #   |
  #   |__disreg_epf2018.zip
  #               |______Inputs 2018.txt
  #               |______Inputs SPSS 2018.txt
  #
  ########
  # NOTA #
  ########
  #
  # En 2019 el formato cambia para tener esta estructura:
  #--datos_2019.zip
  #  |___datos_2019
  #      |__________Fichero de usuario de gastos a2019
  #      |__________Fichero de usuario de gastos a2019
  #      |__________Fichero de usuario de gastos a2019
  #      |__________Inputs 2018.txt
  #      |__________Inputs SPSS 2018.txt
  
  
  try:
    for zips in os.listdir(zips_path):
      unzip(os.path.join(zips_path, zips), zips_2_path)
  except:
    print("Algo ha ido mal con la extracción del primer nivel")
   # Extraes los archivos zip de segundo nivel pero exclusivamente los que contienen los datos (x2 porque los ficheros de 2011-2014) están doblemente comprimidos
  try:
    for zips in os.listdir(zips_2_path):
      for date in range(2006, int(today.strftime("%Y"))):  
        if zips.endswith(f'epf{date}.zip') and not zips.startswith('disreg'):
          unzip(os.path.join(zips_2_path, zips), datos_zip)
  
    for zips in os.listdir(datos_zip):
      for date in range(2006, int(today.strftime("%Y"))):  
        if zips.endswith(f'epf{date}.zip') and not zips.startswith('disreg'):
          unzip(os.path.join(datos_zip, zips), datos_zip)
  except:
    print("Algo ha salido mal. Revisar archivos de los directorios operativos dentro de zip_microdatos")
  
  #Indexas todo el directorio hacia abajo para extraer los archivos descomprimidos y añadirles su root
  # de esta forma tiene la ruta terminada para poder moverlos a ascii_docs
  try:
    ascii_files = set([os.path.join(root, i) for root, dirs, files in os.walk(zips_path) for i in files if i.startswith("Fichero de usuario de hogar") or i.startswith("Fichero de usuario de gastos")])
    for i in ascii_files:
      shutil.move(i, ascii_path)
  except:
    print("La recuperacióón de los ficheros ASCII ha ido mal. Revisar listado de archivos recuperados o funcióón shutil.move")
  
  
  
  filelist = os.listdir(ascii_path)
  
  try:
  
    for file in filelist:
      if "gastos" in file:
        file_date = file.split(" ")[-1]
        date = int(re.split('(\d+)',file_date)[1])
        path = ascii_path
        # For all listed files in directory, we extract name and date, then we apply transformation of features
        # according to specefications detailed by INE dcumentation
        
        if date < 2016:
            file_name = os.path.join(path, file)
            df = pd.read_fwf(os.path.join(path, file), names=epf_fwf_info["col_names_gastos_2006"], header=None, colspecs=epf_fwf_info["colspecs_gastos_2006"])
            df["ID"] = df["ANOENC"].astype(int).astype(str) + df["NUMERO"].astype(int).astype(str) # We also create a custom ID so we can merge all file in a single table after on the DataBase
            df["ANOENC"] = df["ANOENC"].astype(int)
            df["NUMERO"] = df["NUMERO"].astype(int)
            
            # Before dumping the csv, we must standarize the whole dataframe so we avoid issues when uploading to the
            # database server
            columnas_extra = [i for i in set(epf_fwf_info["col_names_gastos_2006"]+epf_fwf_info["col_names_gastos_2016"]) if i not in set(list(df.columns))]
            df_aux = pd.concat([df, pd.DataFrame(columns=columnas_extra)], sort=True)
            
            df_aux.to_csv(os.path.join(directory_gastos,f'gastos_epf_{date}.csv'), index=False)
        else:
            file_name = os.path.join(path, file)
            df = pd.read_fwf(os.path.join(path, file), names=epf_fwf_info["col_names_gastos_2016"], header=None, colspecs=epf_fwf_info["colspecs_gastos_2016"])
            df["ID"] = df["ANOENC"].astype(int).astype(str) + df["NUMERO"].astype(int).astype(str)
            df["ANOENC"] = df["ANOENC"].astype(int)
            df["NUMERO"] = df["NUMERO"].astype(int)
            columnas_extra = [i for i in set(epf_fwf_info["col_names_gastos_2006"]+epf_fwf_info["col_names_gastos_2016"]) if i not in set(list(df.columns))]
            df_aux = pd.concat([df, pd.DataFrame(columns=columnas_extra)], sort=True)
            
            df_aux.to_csv(os.path.join(directory_gastos,f'gastos_epf_{date}.csv'), index=False)
      if "hogar" in file:
        file_date = file.split(" ")[-1]
        date = int(re.split('(\d+)',file_date)[1])
        # For all listed files in directory, we extract name and date, then we apply transformation of features
        # according to specefications detailed by INE dcumentation
        
        if date < 2016:
            file_name = os.path.join(path, file)
            df = pd.read_fwf(os.path.join(path, file), names=epf_fwf_info["col_names_hogar_2006"], header=None, colspecs=epf_fwf_info["colspecs_hogar_2006"])
            df["ID"] = df["ANOENC"].astype(int).astype(str) + df["NUMERO"].astype(int).astype(str)
            df["ANOENC"] = df["ANOENC"].astype(int)
            df["NUMERO"] = df["NUMERO"].astype(int)
            
            # Before dumping the csv, we must standarize the whole dataframe so we avoid issues when uploading to the
            # database server
            columnas_extra = [i for i in set(epf_fwf_info["col_names_hogar_2006"]+epf_fwf_info["col_names_hogar_2016"]) if i not in set(list(df.columns))]
            df_aux = pd.concat([df, pd.DataFrame(columns=columnas_extra)], sort=True)
            
            df_aux.to_csv(os.path.join(directory_hogar,f'hogar_epf_{date}.csv'), index=False)
        else:
            file_name = os.path.join(path, file)
            df = pd.read_fwf(os.path.join(path, file), names=epf_fwf_info["col_names_gastos_2016"], header=None, colspecs=epf_fwf_info["colspecs_gastos_2016"])
            df["ID"] = df["ANOENC"].astype(int).astype(str) + df["NUMERO"].astype(int).astype(str)
            df["ANOENC"] = df["ANOENC"].astype(int)
            df["NUMERO"] = df["NUMERO"].astype(int)
            columnas_extra = [i for i in set(epf_fwf_info["col_names_hogar_2006"]+epf_fwf_info["col_names_hogar_2016"]) if i not in set(list(df.columns))]
            df_aux = pd.concat([df, pd.DataFrame(columns=columnas_extra)], sort=True)
            
            df_aux.to_csv(os.path.join(directory_hogar,f'hogar_epf_{date}.csv'), index=False)
  except:
    print("Algo ha ido mal durante la transformacióón de ficheros (bucle dentro de la carpeta ASCII). Buena suerte")
  
  print("El proceso ha finalizado con éxito. Los archivos se encuentran en formato CSV en la carpeta epf_folder/hogar y epf_folder/gastos")
  
  