datupapi 1.108.11__py3-none-any.whl → 1.109.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -271,6 +271,9 @@ class Anomaly():
271
271
  if alert_anomalies_item else "")
272
272
 
273
273
  # 3. Alerta por items con poco histórico -------------------
274
+ items_alerta_max = np.array(items_alerta_max).astype(str)
275
+ items_alerta_media = np.array(items_alerta_media).astype(str)
276
+
274
277
  alert_insufficient_history = alerta_max > 0 or alerta_media > 0
275
278
  alert_insufficient_history_txt = (
276
279
  f"Items con menos de 24 meses en el histórico: {alerta_max}. ({', '.join(map(str, items_alerta_max))}). "
@@ -377,6 +380,7 @@ class Anomaly():
377
380
  # Aplicar LOF
378
381
  lof4.fit(item_tmp[['SuggestedForecast', 'Target']])
379
382
  probs = lof4.predict_proba(item_tmp[['SuggestedForecast', 'Target']])
383
+ # item_tmp["probabilidad"] = probs[:, 1] #Agregando probabilidad de anomalía a los items
380
384
  item_tmp = item_tmp.copy()
381
385
  item_tmp.loc[:, "probabilidad"] = probs[:, 1]
382
386
  is_out4 = probs[:, 1] > (prob_lim_item_frcst/100)
@@ -450,39 +454,57 @@ class Anomaly():
450
454
  log_forecast = log_forecast.drop(columns=drop_columns)
451
455
  print(f'Logs descargados y recortados a {log_forecast.shape[0]} ejecuciones.')
452
456
 
457
+ if log_forecast.shape[0] < 2:
458
+ print('Logs insuficientes. Las alertas dependientes de logs pasarán a estado nulo')
459
+
453
460
  #10. Cambios en el número total de items ----------------------
454
- num_actual_items = demand_item['item_id'].nunique()
455
- num_ant_items = log_forecast['Items'].iloc[-2]
456
- cambio_num_items = ((num_actual_items - num_ant_items) / num_ant_items) * 100
461
+ if log_forecast.shape[0] > 1:
462
+ num_actual_items = demand_item['item_id'].nunique()
463
+ num_ant_items = log_forecast['Items'].iloc[-2]
464
+ cambio_num_items = ((num_actual_items - num_ant_items) / num_ant_items) * 100
457
465
 
458
- #Alerta
459
- alert_items_var = True if abs(cambio_num_items) > 10 else False
460
- alert_items_var_txt = f"Variación en items: {cambio_num_items:.2f}%." if alert_items_var else ""
461
- print(f"El número de ítems únicos ha cambiado en un {cambio_num_items:.2f}%.")
466
+ #Alerta
467
+ alert_items_var = True if abs(cambio_num_items) > 10 else False
468
+ alert_items_var_txt = f"Variación en items: {cambio_num_items:.2f}%." if alert_items_var else ""
469
+ print(f"El número de ítems únicos ha cambiado en un {cambio_num_items:.2f}%.")
462
470
 
463
- #11. Cambios en el número total de ubicaciones -------------- DE UBICACIÓN
464
- if location:
465
- num_actual_loc = df_demand['location'].nunique()
466
- num_ant_loc = log_forecast['Locations'].iloc[-2]
467
- cambio_num_loc = ((num_actual_loc - num_ant_loc) / num_ant_loc) * 100
468
471
  else:
469
- cambio_num_loc = 0
472
+ alert_items_var = False
473
+ alert_items_var_txt = 'Nulo'
470
474
 
471
- #Alerta
472
- alert_loc_var = True if abs(cambio_num_loc) > limite_cambio_loc else False
473
- alert_loc_var_txt = f"Variación en ubicaciones: {cambio_num_loc:.2f}%." if alert_loc_var else ""
474
- print(f"El número de ubicaciones únicos ha cambiado en un {cambio_num_loc:.2f}%.")
475
+ #11. Cambios en el número total de ubicaciones -------------- DE UBICACIÓN
476
+ if log_forecast.shape[0] > 1:
477
+ if location:
478
+ num_actual_loc = df_demand['location'].nunique()
479
+ num_ant_loc = log_forecast['Locations'].iloc[-2]
480
+ cambio_num_loc = ((num_actual_loc - num_ant_loc) / num_ant_loc) * 100
481
+ else:
482
+ cambio_num_loc = 0
483
+
484
+ #Alerta
485
+ alert_loc_var = True if abs(cambio_num_loc) > limite_cambio_loc else False
486
+ alert_loc_var_txt = f"Variación en ubicaciones: {cambio_num_loc:.2f}%." if alert_loc_var else ""
487
+ print(f"El número de ubicaciones únicos ha cambiado en un {cambio_num_loc:.2f}%.")
488
+
489
+ else:
490
+ alert_loc_var = False
491
+ alert_loc_var_txt = 'Nulo'
475
492
 
476
493
  ##12. Aumento en el WMAPE
477
- wmape_actual = log_forecast['WMAPE'].iloc[-1]
478
- wmape_anterior = log_forecast['WMAPE'].iloc[-2]
494
+ if log_forecast.shape[0] > 1:
495
+ wmape_actual = log_forecast['WMAPE'].iloc[-1]
496
+ wmape_anterior = log_forecast['WMAPE'].iloc[-2]
479
497
 
480
- #Alerta
481
- alert_wmape_var = True if wmape_anterior < wmape_actual else False
482
- alert_wmape_var_txt = ((f"El error promedio aumentó de {wmape_anterior:.2f}% a {wmape_actual:.2f}%") if alert_wmape_var
483
- else (f"El error promedio disminuyó de {wmape_anterior:.2f}% a {wmape_actual:.2f}%"))
484
- print(f"El error pasó de {wmape_anterior:.2f}% a {wmape_actual:.2f}%")
485
- print(alert_wmape_var_txt)
498
+ #Alerta
499
+ alert_wmape_var = True if wmape_anterior < wmape_actual else False
500
+ alert_wmape_var_txt = ((f"El error promedio aumentó de {wmape_anterior:.2f}% a {wmape_actual:.2f}%") if alert_wmape_var
501
+ else (f"El error promedio disminuyó de {wmape_anterior:.2f}% a {wmape_actual:.2f}%"))
502
+ print(f"El error pasó de {wmape_anterior:.2f}% a {wmape_actual:.2f}%")
503
+ print(alert_wmape_var_txt)
504
+
505
+ else:
506
+ alert_wmape_var = False
507
+ alert_wmape_var_txt = 'Nulo'
486
508
 
487
509
  ##13. Fecha de corte
488
510
  fecha_corte = log_forecast['DateDataPrep'].iloc[-1]
@@ -497,7 +519,7 @@ class Anomaly():
497
519
 
498
520
  #####--------------------Creción tabla resumen
499
521
 
500
-
522
+
501
523
  if location:
502
524
  # Creo tabla para lo items con baja precisión
503
525
  tabla = items_baja_precision[['Item', 'Location','ItemType', 'Ranking', 'AccuracyBestFit']]
@@ -516,7 +538,7 @@ class Anomaly():
516
538
  tabla = tabla.merge(historico_meses, left_on=['Item', 'Location'], right_on=['item_id', 'location'], how='left')
517
539
  tabla.drop(columns=['item_id', 'location'], inplace=True, errors='ignore')
518
540
  tabla['Historico (Meses)'] = tabla.set_index(['Item', 'Location']).index.map(df_demand.groupby(['item_id', 'location']).size())
519
-
541
+
520
542
  else:
521
543
  # Creo tabla para lo items con baja precisión
522
544
  tabla = items_baja_precision[['Item','ItemType', 'Ranking', 'AccuracyBestFit']]
@@ -534,8 +556,15 @@ class Anomaly():
534
556
  tabla.drop(columns=['item_id'], inplace=True, errors='ignore')
535
557
  tabla['Historico (Meses)'] = tabla.set_index(['Item']).index.map(df_demand.groupby(['item_id']).size())
536
558
 
559
+
537
560
  #Añadir alertas LOF
561
+ out_if_item2['item_id'] = out_if_item2['item_id'].astype(str)
562
+ out_if_item4['Item'] = out_if_item4['Item'].astype(str)
563
+
538
564
  def obtener_alerta(item):
565
+
566
+ item = str(item)
567
+
539
568
  # Filtrar por item
540
569
  alerta_prep = out_if_item2[out_if_item2['item_id'] == item][['timestamp', 'probabilidad']].copy()
541
570
  alerta_forecast = out_if_item4[out_if_item4['Item'] == item][['Date', 'probabilidad']].copy()
@@ -554,6 +583,8 @@ class Anomaly():
554
583
  return alertas.to_dict(orient='records') if not alertas.empty else None
555
584
 
556
585
  tabla['AlertaAnomalia'] = tabla['Item'].apply(obtener_alerta)
586
+ items_con_alerta = set(out_if_item2['item_id']).union(set(out_if_item4['Item']))
587
+ print(f'Items con baja precisión con alertas de anomalías: {items_con_alerta}')
557
588
 
558
589
  #---------------------Cargando tabla resumen
559
590
  self.io.upload_csv(tabla, q_name='ResumenAlertas', datalake_path='output')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datupapi
3
- Version: 1.108.11
3
+ Version: 1.109.0
4
4
  Summary: Utility library to support Datup AI MLOps processes
5
5
  Author: Datup AI
6
6
  Author-email: ramiro@datup.ai
@@ -7,7 +7,7 @@ datupapi/distribution/src/DistributionFunctions/functions_distribution.py,sha256
7
7
  datupapi/distribution/src/Format/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  datupapi/distribution/src/Format/distribution_format.py,sha256=CFqUHTk9StDvaOvlR3yLr3NZiFY2Ao1yVXoY-IsrNWE,3964
9
9
  datupapi/evaluate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- datupapi/evaluate/anomaly.py,sha256=s_HJb_5T3xNhL26y5bsHWuS-ucbkhSGtCyF10d_iJ3I,32379
10
+ datupapi/evaluate/anomaly.py,sha256=fjIDAvEPGBJdZjVXhz7Rk90WKCR5t3Hbe6zeTKVXFlw,33506
11
11
  datupapi/evaluate/errors.py,sha256=9SRYAjwRDfEdP1EnBbfA7zoQEi4xU4qI16vBE8-jkeA,7039
12
12
  datupapi/extract/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  datupapi/extract/io.py,sha256=fYPXf-SmYyw4ywbN3SjQsdl6qBQvQz1K3i9kbpiEkkA,84343
@@ -48,7 +48,7 @@ datupapi/transform/forecasting.py,sha256=OboiVyErzWXJAv6R4fCXiPNaoVp5dNAP9F53EDq
48
48
  datupapi/transform/ranking.py,sha256=XOI0XqMx9Cy52Xjc4LCzJCNUsJZNjgrPky7nrpELr-U,7943
49
49
  datupapi/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  datupapi/utils/utils.py,sha256=pU3mXPupm-1gvODI-kPlIpOdMHa2F9lEXvqBn6t3ajc,4637
51
- datupapi-1.108.11.dist-info/METADATA,sha256=s70m4oBa9C6lShSQx4C52jSSiHZDorDMtE-NCcp9JAU,1517
52
- datupapi-1.108.11.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
53
- datupapi-1.108.11.dist-info/top_level.txt,sha256=oERwtRZu8xq2u1TDGwJwuWK0iJbH4p7x9kYECAL5So0,9
54
- datupapi-1.108.11.dist-info/RECORD,,
51
+ datupapi-1.109.0.dist-info/METADATA,sha256=v2bRsQxBoCgZAOHxv9DvZ0jReqahpI-5Cr1XTwNYpR8,1516
52
+ datupapi-1.109.0.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
53
+ datupapi-1.109.0.dist-info/top_level.txt,sha256=oERwtRZu8xq2u1TDGwJwuWK0iJbH4p7x9kYECAL5So0,9
54
+ datupapi-1.109.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.0)
2
+ Generator: setuptools (79.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5