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
| Propiedad | Descripción |
|---|---|
| Se ejecuta en | FoodProductFlowNode (excluyendo subdivisiones) |
| Dependencias | LocationGapFillingWorker, AddClientNodesGapFillingWorker, InventoryConnectorGapFillingWorker, MatchProductNameGapFillingWorker, LinkTermToActivityNodeGapFillingWorker, IngredientAmountEstimatorGapFillingWorker |
| Entrada clave | Ubicación de cocina (país), términos FoodEx2 coincidentes del producto, datos comerciales de la FAO |
| Salida | División de origen con porcentajes específicos por país, propiedades de ubicación |
| Fuente de datos | Matriz de Comercio Detallado de FAO STAT, Estadísticas de Producción de la FAO |
Cuándo se Ejecuta
El módulo se activa cuando:
- El nodo es un
FoodProductFlowNode(no una subdivisión) - No se ha especificado origen, O múltiples orígenes necesitan procesamiento
- Todos los GFMs dependientes han completado
- 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:
| Escenario | Manejo |
|---|---|
| Exportación ≥ Doméstico + Importación | Establecer "origen desconocido" |
| Sin datos de producción doméstica | Usar solo estadísticas de importación |
| Sin datos comerciales para producto | Recurrir a estadísticas FAO por defecto |
| Oferta total negativa | Establecer "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ísesProduction_Crops_Livestock_E_All_Data_NOFLAG.csv- Producción doméstica por paísTrade_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 FAO | Nombre | Descripción |
|---|---|---|
100000 | Producción Local | Productos como agua que son de origen local |
200000 | Producción por Defecto | Productos sin mapeos FAO específicos |
300000 | Producción de Pescado Desconocida | Productos de pescado sin datos comerciales |
400000 | Producción Fallida | Respaldo 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:
| Sistema | Descripción | Ejemplo |
|---|---|---|
| M49 | Códigos numéricos de la ONU | 756 (Suiza) |
| ISO 3166-1 alfa-2 | Códigos de dos letras | CH |
| ISO 3166-1 alfa-3 | Códigos de tres letras | CHE |
| GADM | Códigos de base de datos geográfica | CHE.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 Datos | Valor (toneladas) |
|---|---|
| Producción Doméstica | 45.000 |
| Importaciones Totales | 75.000 |
| Exportaciones Totales | 5.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ís | Importación (toneladas) | % de Importación | Cuota Final |
|---|---|---|---|
| España | 35.000 | 46,7% | 30,4% |
| Italia | 20.000 | 26,7% | 17,4% |
| Países Bajos | 10.000 | 13,3% | 8,7% |
| Marruecos | 5.000 | 6,7% | 4,4% |
| Otros | 5.000 | 6,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
-
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.
-
Matriz de Comercio Detallado de la FAO. Datos Comerciales. Flujos comerciales bilaterales para productos agrícolas.
-
Base de Datos BACI (Alternativa). CEPII BACI. Base de datos de comercio internacional con seguimiento de origen mejorado.
-
Base de Datos GADM. Áreas Administrativas Globales. Límites geográficos y regiones administrativas.
-
Clasificación FoodEx2. EFSA FoodEx2. Sistema de clasificación de alimentos de la Autoridad Europea de Seguridad Alimentaria.