Saltar al contenido principal

Origin GFM

El Gap Filling Module de Origen determina el origen geográfico de productos alimentarios cuando no se especifica explícitamente. Usando estadísticas comerciales de la FAO (Organización de las Naciones Unidas para la Alimentación y la Agricultura), calcula cuotas de importación y ratios de producción doméstica para estimar de dónde provienen más probablemente los ingredientes basándose en la "ubicación de cocina" (país de consumo).

Referencia Rápida

PropiedadDescripción
Se ejecuta enFoodProductFlowNode (excluyendo subdivisiones)
DependenciasLocationGapFillingWorker, AddClientNodesGapFillingWorker, InventoryConnectorGapFillingWorker, MatchProductNameGapFillingWorker, LinkTermToActivityNodeGapFillingWorker, IngredientAmountEstimatorGapFillingWorker
Entrada claveUbicación de cocina (país), términos FoodEx2 coincidentes del producto, datos comerciales de la FAO
SalidaDivisión de origen con porcentajes específicos por país, propiedades de ubicación
Fuente de datosMatriz de Comercio Detallado de FAO STAT, Estadísticas de Producción de la FAO

Cuándo se Ejecuta

El módulo se activa cuando:

  1. El nodo es un FoodProductFlowNode (no una subdivisión)
  2. No se ha especificado origen, O múltiples orígenes necesitan procesamiento
  3. Todos los GFMs dependientes han completado
  4. Los nodos de subactividad tienen cantidades de producción calculadas

Salida Clave

El módulo modifica el grafo de cálculo mediante:

  • División de Origen: Creando múltiples nodos de flujo de producto, cada uno con un país de origen específico
  • Asignación de Porcentaje: Distribuyendo cantidades basadas en estadísticas de importación y producción doméstica
  • Propiedades de Ubicación: Estableciendo códigos de país, coordenadas y términos GADM

Metodología Científica

El modelo de origen calcula la distribución de probabilidad de dónde se origina un producto basándose en:

Oferta Total = Producción Doméstica + Importaciones - Exportaciones

Para cada país de origen, la cuota se calcula como:

Cuota Doméstica = (Producción Doméstica - Exportaciones) / Oferta Total
Cuota Extranjera = 1 - Cuota Doméstica
Cuota de Importación por País = Cuota Extranjera * (Importación del País / Importación Total)

Modelo de Balance Comercial

El modelo usa datos de FAO STAT para calcular distribuciones de origen:

Cuota de Producción Doméstica

domestic_import_export_total = domestic_production + import_value - export_value

domestic_origin_share = (domestic_production - export_value) / domestic_import_export_total

Si la producción doméstica excede las exportaciones, se asume que una porción del consumo es doméstica. La porción restante se asigna a países importadores.

Distribución por País de Importación

Para orígenes extranjeros, el módulo identifica los principales países contribuyentes:

# Obtener países que cubren el 90% de las importaciones totales
m49_country_share = import_export_cache.import_countries_top90percent(
kitchen_country_m49_code, fao_code, year_column
)

for country, value in country_share.items():
country_total_percentage_share[country] = foreign_origin_share * value

El umbral del 90% reduce la complejidad computacional mientras mantiene la precisión. Para productos sin códigos FAO específicos (estadísticas por defecto), solo se usan los 10 principales países.

Manejo de Inconsistencias

Los datos comerciales de la FAO pueden tener inconsistencias. El módulo maneja estos casos:

EscenarioManejo
Exportación ≥ Doméstico + ImportaciónEstablecer "origen desconocido"
Sin datos de producción domésticaUsar solo estadísticas de importación
Sin datos comerciales para productoRecurrir a estadísticas FAO por defecto
Oferta total negativaEstablecer "origen desconocido"

Detalles de Implementación

Configuración de Datos de la FAO

El módulo usa dos conjuntos de datos principales de la FAO:

FAO_IMPORT_EXPORT_ZIP_URL = "https://bulks-faostat.fao.org/production/Trade_DetailedTradeMatrix_E_All_Data.zip"
FAO_DOMESTIC_ZIP_URL = "https://bulks-faostat.fao.org/production/Production_Crops_Livestock_E_All_Data.zip"

Archivos de datos extraídos:

  • Trade_DetailedTradeMatrix_E_All_Data_NOFLAG.csv - Cantidades de importación/exportación por par de países
  • Production_Crops_Livestock_E_All_Data_NOFLAG.csv - Producción doméstica por país
  • Trade_DetailedTradeMatrix_E_ItemCodes.csv - Definiciones de códigos de producto de la FAO

Selección de Año

El módulo soporta años primarios y secundarios para disponibilidad de datos:

# Si faltan datos del año primario, recurrir al año secundario
if pd.isnull(domestic_production_value.values[0]):
stats_data_year_column = self.gfm_factory.secondary_year
domestic_production_value = domestic_production_row[stats_data_year_column]

Códigos FAO Especiales

Códigos FAO personalizados manejan casos extremos:

Código FAONombreDescripción
100000Producción LocalProductos como agua que son de origen local
200000Producción por DefectoProductos sin mapeos FAO específicos
300000Producción de Pescado DesconocidaProductos de pescado sin datos comerciales
400000Producción FallidaRespaldo cuando falla la estimación de origen

Modos de Procesamiento

Procesamiento de Monoproducto

Para productos de un solo ingrediente:

async def monoproduct_origin_processing(self, calc_graph: "CalcGraph") -> None:
# 1. Comprobar si el origen ya está especificado
origins_list = await self.parse_current_origins()

if len(origins_list) == 1:
return # Ya tiene origen

# 2. Obtener ubicación de cocina del código de país heredado
kitchen_country_code = get_inherited_country_code(self.node)
kitchen_country_m49_code = iso_to_m49_mapping.get(kitchen_country_code)

# 3. Encontrar código FAO para producto vía mapeo FoodEx2
fao_code_term = linked_fao_code_terms.get(foodex2_term_uids)

# 4. Calcular cuotas domésticas + importación
# 5. Aplicar división de origen al grafo

Procesamiento de Producto Combinado

Para productos con múltiples ingredientes:

async def combined_product_origin_processing(self, calc_graph: "CalcGraph") -> None:
origins_list = await self.parse_current_origins(combined_product_origin_processing=True)

# Distribución igual entre orígenes especificados
country_total_percentage_share = {
origin.country_code: 1 / len(origins_list)
for origin in origins_list
}

await self.apply_origin_split_to_graph(calc_graph, country_total_percentage_share, is_combined_product=True)

Mutación del Grafo para División de Origen

Cuando se determinan múltiples orígenes, el grafo se modifica:

async def apply_origin_split_to_graph(
self,
calc_graph: "CalcGraph",
country_total_percentage_share: dict,
is_origin_from_fao: bool = False,
...
) -> None:
# 1. Eliminar arista entre producto y subactividad
remove_edge_mutation = RemoveEdgeMutation(...)

# 2. Añadir nuevo nodo Origin-Split-Activity
activity_node = FoodProcessingActivityNode.model_construct(...)
calc_graph.apply_mutation(AddNodeMutation(...))

# 3. Crear nodos de flujo específicos por origen
for country_iso_code, percentage in country_total_percentage_share.items():
# Duplicar nodo original con nueva cantidad
calc_graph.apply_mutation(DuplicateNodeMutation(...))

# Establecer cantidad proporcional
new_amount = percentage * activity_node.production_amount.value

# Establecer propiedad de ubicación
origin_location = LocationProp.unvalidated_construct(
address=gadm_term.name,
country_code=country_iso_code,
term_uid=gadm_term.uid,
source=LocationSourceEnum.fao_stat if is_origin_from_fao else LocationSourceEnum.gadm,
)

Manejo de Origen Regional

Cuando se especifica un origen regional (como "Europa"), se expande a países componentes:

# Manejar términos regionales
if term_xid in location_to_regional_term_xid_map.values():
for region in regional_term_xid_to_region_gadm_codes_map.get(term_xid, []):
if region not in already_listed_regions:
country_code = iso_3166_map_3_to_2_letter.get(region.split(".")[0])
locations.append(LocationProp.unvalidated_construct(
country_code=country_code,
term_uid=gadm_term.uid,
location_qualifier=location_qualifier,
))

Fuentes de Datos

Base de Datos FAO STAT

La fuente de datos principal es la División de Estadística de la FAO:

Datos Comerciales: Matriz de Comercio Detallado de la FAO

  • Contiene flujos comerciales bilaterales entre países
  • Cantidades en toneladas
  • Elementos: Cantidad de Importación, Cantidad de Exportación, Valor de Importación, Valor de Exportación

Datos de Producción: Estadísticas de Producción de la FAO

  • Contiene producción doméstica por país y producto
  • Cantidades en toneladas

Mapeos de Códigos de País

El módulo usa múltiples sistemas de códigos de país:

SistemaDescripciónEjemplo
M49Códigos numéricos de la ONU756 (Suiza)
ISO 3166-1 alfa-2Códigos de dos letrasCH
ISO 3166-1 alfa-3Códigos de tres letrasCHE
GADMCódigos de base de datos geográficaCHE.1.2 (subregiones)

Mapeo FoodEx2 a FAO

Los productos se enlazan mediante el servicio de glosario:

fao_glossary_links = await glossary_link_service.get_glossary_links_by_gfm(
gap_filling_module="FAO"
)

# Mapea UIDs de términos FoodEx2 -> UID de término de código FAO
for link in fao_glossary_links:
linked_fao_code_terms[frozenset(link.term_uids)] = link.linked_term_uid

Ejemplo de Cálculo

Escenario: Determinar origen para 1 kg de tomates consumidos en Suiza (CH)

Paso 1: Identificar Producto

  • Término FoodEx2 coincidente: A0DMX (Tomates)
  • Código FAO vía enlace de glosario: 388 (Tomates)
  • País de cocina: Suiza (M49: 756)

Paso 2: Consultar Estadísticas Comerciales

Datos de la FAO para Suiza y tomates (código FAO 388):

Punto de DatosValor (toneladas)
Producción Doméstica45.000
Importaciones Totales75.000
Exportaciones Totales5.000

Paso 3: Calcular Cuotas

total_supply = 45.000 + 75.000 - 5.000 = 115.000

domestic_share = (45.000 - 5.000) / 115.000 = 0,348 (34,8%)
foreign_share = 1 - 0,348 = 0,652 (65,2%)

Paso 4: Distribuir Cuota de Importación

Principales países importadores para importaciones suizas de tomate:

PaísImportación (toneladas)% de ImportaciónCuota Final
España35.00046,7%30,4%
Italia20.00026,7%17,4%
Países Bajos10.00013,3%8,7%
Marruecos5.0006,7%4,4%
Otros5.0006,7%4,4%
Suiza (doméstico)--34,8%

Paso 5: Modificación del Grafo

El módulo crea nodos de división de origen:

Original:
Tomates (1 kg) -> Actividad -> ...

Después de Origin GFM:
Tomates (1 kg) -> Origin-Split-Activity
|-> Tomates (0,348 kg, CH) -> Actividad (copia) -> ...
|-> Tomates (0,304 kg, ES) -> Actividad (copia) -> ...
|-> Tomates (0,174 kg, IT) -> Actividad (copia) -> ...
|-> Tomates (0,087 kg, NL) -> Actividad (copia) -> ...
|-> Tomates (0,044 kg, MA) -> Actividad (copia) -> ...
|-> Tomates (0,044 kg, OTROS) -> Actividad (original) -> ...

Cada flujo específico por origen luego recibe cálculos de transporte apropiados aguas abajo.


Sistema de Caché

Caché de Importación/Exportación

Los datos comerciales se almacenan en caché en formato MessagePack para rendimiento:

class ImportExportCache:
def import_export_value(self, m49_code: int, fao_code: int, year_column: str) -> tuple[int, int]:
"""Devuelve sumas de importación y exportación desde caché."""
return self.import_export_data[(m49_code, fao_code)][year_column]

def import_countries_top90percent(self, m49_code: int, fao_code: int, year_column: str) -> dict:
"""Devuelve cuota relativa de importación entre países que cubren el 90% superior."""
return self.import_export_data["top90"][(m49_code, fao_code)][year_column]

Estructura de Archivos de Caché

temp_data/origin_gfm/
├── domestic_df_{suffix}.hdf5 # Producción doméstica (HDF5)
├── import_export_cache_{suffix}.msgpack # Datos comerciales preagregados
├── item_codes_{suffix}.csv # Códigos de producto de la FAO
├── import_export_{version}.zip # Archivo fuente
└── domestic_{version}.zip # Archivo fuente

Integración con Google Drive

Los archivos de caché se sincronizan con Google Drive para acceso compartido:

def download_file_from_google_drive(self, drive_service: Resource, filename: str, file_id: str):
"""Descargar archivo de caché desde Google Drive si no está disponible localmente."""

def upload_cache_file_to_google_drive(self, drive_service: Resource, filename: str):
"""Subir archivo de caché regenerado a Google Drive."""

Limitaciones Conocidas

Calidad de Datos

  • Efecto Rotterdam: Bienes reexportados a través de centros comerciales (Países Bajos, Bélgica) pueden aparecer como originarios de esos países en lugar de los orígenes reales
  • Vacíos de Datos de la FAO: Algunos productos carecen de estadísticas comerciales, recurriendo a estimación de origen por defecto
  • Balances Inconsistentes: Algunas combinaciones país/producto tienen exportaciones que exceden producción + importaciones
  • Retraso Temporal: La publicación de datos de la FAO típicamente tiene un retraso de 1-2 años respecto a la fecha actual

Vacíos de Cobertura

  • Productos de Pescado: Datos comerciales limitados de la FAO para pescado; usa "origen desconocido" con transporte por defecto
  • Productos Procesados: Alimentos procesados complejos pueden no tener mapeos FAO directos
  • Productos Regionales: Productos como agua local o artículos especiales usan código de "producción local"

Suposiciones del Modelo

  • Distribución Igual: Cuando se especifican múltiples orígenes por el usuario sin porcentajes, reciben cuotas iguales
  • Ubicación de Cocina Requerida: La estimación de origen requiere un país de consumo conocido
  • Límite de 10 Países Principales: Las estadísticas FAO por defecto solo usan los 10 principales países de importación para limitar la complejidad del grafo
  • Umbral de Cobertura del 90%: Fuentes de importación menores por debajo del 10% de cuota acumulativa se excluyen

Restricciones de Procesamiento

  • Exclusión de No Alimentos: Productos coincidentes con términos FoodEx2 no alimentarios (EAT-0002, EAT-0000) se omiten
  • Manejo de Subdivisiones: Los nodos de subdivisión se procesan de manera diferente (omitidos por Origin GFM)
  • Productos Combinados: Los orígenes regionales en productos combinados no se expanden para evitar explosión del grafo

Referencias

  1. División de Estadística de la FAO. Base de Datos FAOSTAT. Organización de las Naciones Unidas para la Alimentación y la Agricultura.

  2. Matriz de Comercio Detallado de la FAO. Datos Comerciales. Flujos comerciales bilaterales para productos agrícolas.

  3. Base de Datos BACI (Alternativa). CEPII BACI. Base de datos de comercio internacional con seguimiento de origen mejorado.

  4. Base de Datos GADM. Áreas Administrativas Globales. Límites geográficos y regiones administrativas.

  5. Clasificación FoodEx2. EFSA FoodEx2. Sistema de clasificación de alimentos de la Autoridad Europea de Seguridad Alimentaria.