Library for Sarapico Metadata processing
Project description
SARAPY
Library for processing SARAPICO project metadata of AMG SA.
Versión 6.1.0
Se corrigen tres crashes en el procesamiento de operaciones. El más grave rompía el
pipeline completo a partir de la segunda llamada a processOperations() sobre una misma
instancia de OpsProcessor — es decir, el modo de uso en streaming/producción. No se había
detectado porque los scripts de análisis (test/mergingdata.py) crean un OpsProcessor nuevo
en cada iteración.
OpsProcessor.updateOperationsDict()ya no mutanewSample. Antes hacíasample_ops = newSample(misma referencia) y luegosample_ops += last_op, dondelast_opes un dict: en Pythonlista += dictappendea las claves como strings, corrompiendo la muestra. A partir de la 2da llamada el pipeline fallaba conAttributeError: 'str' object has no attribute 'keys'al construir el DataFrame.- La última operación de la muestra anterior ahora se antepone (no se appendea), que es lo
que el recorte
classified_ops[1:]declassifyForPlantin()siempre asumió. updateAfterAwake()pasa a ejecutarse antes de ese recorte: su máscara deN_MODEse arma sobresample_opscompleto, y aplicarla después producíaIndexError: boolean index did not match indexed array.FertilizerTransformer.transform()ya no rompe conSC_FTnulo.TransformInputDatadejaNonecuando elcsv_datumviene corto, y ese valor llegaba comoNaNaPolynomialFeatures(ValueError: Input X contains NaN). Ahora esas operaciones se devuelven comoNaN— manteniendo el shape(n,)alineado con la entrada — y se loguea un warning con la cantidad de ops afectadas.FertilizerTransformer.__init__()re-lanza si no puede cargar los.pkl. Antes capturabaFileNotFoundError, logueaba y seguía, dejando_regresor/_poly_featuressin asignar; el error aparecía mucho después comoAttributeErrorlejos de la causa. Además ahora se capturan todos los errores de carga (pickle corrupto, mismatch de versión de sklearn), no sólo el archivo faltante.FertilizerTransformer.transform()usa.transform()en lugar de.fit_transform()sobre elPolynomialFeaturescargado. Re-fitear el artefacto en cada llamada lo mutaba y anulaba el sentido de picklearlo. Los gramos estimados no cambian.- Nuevo guard en
processOperations(): verifica quetimestamps,pl_clasyft_gramstengan el mismo largo antes delnp.column_stack, con un mensaje explícito en vez de un error opaco de numpy.
Los resultados no cambian para el camino de una sola llamada a processOperations() (que es
el que venía funcionando): con last_oprc=None no hay fila antepuesta ni recorte.
Además:
- El bloque
if __name__ == "__main__"deOpsProcessor.pyahora reporta, por nodo, el uso de fertilizante en gramos: total (contando ops 0 y 1), promedio por operación válida (sólo ops etiquetadas como 1) y fertilizante perdido (suma sobre ops etiquetadas como 0, con su porcentaje). El total es igual en los tres modos de clasificación — los gramos salen deSC_FTy no dependen de la etiqueta de plantín —; lo que cambia es cómo se reparte entre válido y perdido, así que la métrica debe leerse siempre junto al modo. - El mismo bloque imprime los valores crudos del sensor de fertilizante (
SC_FT): mínimo, máximo y promedio por nodo. - Se agregan
CLAUDE.mdyAGENTS.md(en inglés) con la arquitectura de la librería, las trampas conocidas y la política de versionado.
Versión 6.0.0
El RFID no leído (4294967295) pasa a ser una operación normal. La electrónica emite el
sentinel 0xFFFFFFFF en ID_OPRR / ID_CDLL cuando no logra leer el RFID. Hasta la 5.1.0 la
librería interpretaba eso como operación inválida; ahora se interpreta como lo que es: la
operación es real y se clasifica igual que cualquier otra, y lo único que se desconoce es la
identidad del operario.
Esto cambia los resultados. En examples/ el sentinel aparece en el 4,54% de las ops
(11.644 / 256.384, siempre en ID_OPRR, nunca en ID_CDLL) y hay 61 de 149 nodo/día donde
está en el 100% de las operaciones. Antes, en esos nodo/día no se detectaba ni un lagarto y
las distancias salían enteramente NaN.
Cambios de API (breaking):
LagartoDetector.detect_lagartos,HardClassifier.label_ops_by_distance,DistanceMetrics.compute_distances_by_tagy sus wrappers*_from_rowsya no aceptanworker_codes/work_crew_codes. La clasificación es puramente geométrica.PlantinClassifier.classifyya no aceptaworker_codes/work_crew_codes.- Se elimina el flag
hard_use_rfiddeOpsProcessor. Su único efecto era forzartag_seedling = 1en las lecturas fallidas, que es lo contrario de la política nueva. HardClassifier.classify_from_rowsya no aceptause_rfid.valid_maskahora esFalsesólo por ausencia de coordenadas (antes también por RFID).- Nuevo helper
sarapy.dataProcessing.is_rfid_unread(code): predicado de reporte para contar lecturas fallidas. No interviene en ninguna decisión de clasificación.
Versión 5.1.0
- Se ajustan los umbrales por defecto de detección de lagartos a los valores que mejores
resultados dieron en el barrido de
test/comparacion_medias_1s.py(preset "Intermedio"):lagarto_min_dist_mpasa de0.8/1.0a1.5ylagarto_min_seq_lende3a2(lagarto_same_place_m=0.8ylagarto_max_dist_m=Nonese mantienen). El cambio se aplica a los defaults deLagartoDetector.detect_lagartos,PlantinClassifier.classifyyOpsProcessor._classifyHard, y a los ejemplos detest/checking_lagartos.py. - Empíricamente, en estos datasets la palanca dominante es
lagarto_min_dist_m;lagarto_min_seq_lencasi no mueve el resultado. NO bajarlagarto_min_seq_lena1(re-etiquetaría todo cero aislado).
##argumentos del método PlantinClassifier.classify() — umbrales de lagarto recomendados
kwargs_classifier = {"proba_threshold":0.45,
"use_proba_ma":False,
"proba_ma_window":10,
"update_samePlace":True,
"update_dstpt":True,
"umbral_proba_dstpt":0.5,
"umbral_bajo_dstpt":1.5,
"use_ma":True,
"dstpt_ma_window":62,
"use_min_dstpt":False,
"factor":0.1,
"detect_lagartos": True,
"label_lagartos_as_1": False,
"lagarto_min_dist_m": 1.5,
"lagarto_same_place_m": 0.8,
"lagarto_min_seq_len": 2,
"lagarto_max_dist_m": None, # None = sin tope; p.ej. 15.0 descarta saltos de GPS
"useRatioStats":False,
"std_weight":1.,
"useDistancesStats":False,
"ratio_dcdp_umbral":0.1,
"dist_umbral":1.,
}
Cómo clasificar: ML, ML + re-etiquetado de lagartos, y Hard
OpsProcessor expone tres modos de clasificación de plantín. El modo se elige con tres
flags que se pasan a processOperations(...) (o dentro de kwargs_classifier):
| Modo | use_hard_classifier |
detect_lagartos |
label_lagartos_as_1 |
|---|---|---|---|
| ML (solo el clasificador entrenado) | False |
False |
False |
| ML + re-etiquetado de lagartos | False |
True |
True |
| Hard + re-etiquetado de lagartos | True |
True |
True |
Nota: con
use_hard_classifier=Truelas etiquetas salen delHardClassifier(reglas, sólo distancia) y el ML NO se ejecuta — el Hard reemplaza al ML, no se combinan. El agrupamiento "mismo lugar" es intrínseco al Hard (el flagupdate_samePlacesólo afecta al camino ML). El re-etiquetado de lagartos se aplica en cualquiera de los dos caminos cuandodetect_lagartosylabel_lagartos_as_1están enTrue.
Usando los kwargs_fmcreator / kwargs_hard / kwargs_classifier de los bloques de arriba:
import json
from sarapy.dataProcessing.OpsProcessor import OpsProcessor
op = OpsProcessor(
classifier_file="modelos/pipeline_rf.pkl",
regresor_file="modelos/regresor_v2.pkl",
poly_features_file="modelos/poly_features_v2.pkl",
**kwargs_hard, **kwargs_fmcreator,
)
with open("examples/2026-02-25/UPM047N/historical-data.json") as f:
samples = json.load(f)
# Los tres modos se arman sobreescribiendo los flags sobre kwargs_classifier.
# (Se mergea en un solo dict para no pasar el mismo argumento dos veces.)
# 1) Sólo ML
out_ml = op.processOperations(
samples,
**{**kwargs_classifier, "use_hard_classifier": False,
"detect_lagartos": False, "label_lagartos_as_1": False},
)
# 2) ML + re-etiquetado de lagartos
out_ml_lag = op.processOperations(
samples,
**{**kwargs_classifier, "use_hard_classifier": False,
"detect_lagartos": True, "label_lagartos_as_1": True},
)
# 3) Hard + re-etiquetado de lagartos (el Hard reemplaza al ML)
out_hard = op.processOperations(
samples,
**{**kwargs_classifier, "use_hard_classifier": True,
"detect_lagartos": True, "label_lagartos_as_1": True},
)
# processOperations devuelve una lista de dicts (una por operación):
# [{"timestamp": ..., "tag_seedling": 0/1, "tag_fertilizer": gramos (float)}, ...]
Si no se pasa ningún flag, los valores por defecto de
OpsProcessorsonuse_hard_classifier=True,detect_lagartos=Trueylabel_lagartos_as_1=True(modo Hard + re-etiquetado de lagartos). Ojo: el bloquekwargs_classifierde arriba traelabel_lagartos_as_1=False, así que si lo pasás tal cual el re-etiquetado de lagartos queda apagado salvo que lo sobreescribas (como en los ejemplos).
Versión 5.0.0
- Se implementa HardClassifier.
## argumentos de PlantinFMCreator
kwargs_fmcreator = {"imputeDistances":True, "distanciaMedia":1.8, "umbral_precision":0.3,
"dist_mismo_lugar":0.8, "max_dist":100,
"umbral_ratio_dCdP":2, "deltaO_medio":4,
"impute_ratiodcdp": True, "umbral_impute_ratiodcdp": -0.5,
"deltaO_ma": True, "deltaO_ma_window": 26}
##argumentos del método PlantinClassifier.classify() (clasificador VIEJO / ML)
label_lagartos_as_1 = True
kwargs_classifier = {"proba_threshold":0.45,
"use_proba_ma":False,
"proba_ma_window":10,
"update_samePlace":True,
"update_dstpt":True,
"umbral_proba_dstpt":0.5,
"umbral_bajo_dstpt":1.5,
"use_ma":True,
"dstpt_ma_window":62,
"use_min_dstpt":False,
"factor":0.1,
"detect_lagartos": True,
"label_lagartos_as_1": label_lagartos_as_1,
"lagarto_min_dist_m": 0.8,
"lagarto_same_place_m": 0.8,
"lagarto_min_seq_len": 3,
"lagarto_max_dist_m": None, # None = sin tope; p.ej. 15.0 descarta saltos de GPS
"useRatioStats":False,
"std_weight":1.,
"useDistancesStats":False,
"ratio_dcdp_umbral":0.1,
"dist_umbral":1.,
}
##argumentos del HardClassifier (clasificador NUEVO / sólo distancia)
kwargs_hard = {"umbral_mismo_lugar": 0.8, "dist_max": 5.0}
Version 4.0.0
-
Se implementa mejora en la detección de lagartos.
-
Las keys nuevas que se recomienda usar en
kwargs_classifierson:kwargs_fmcreator = {"imputeDistances":True, "distanciaMedia":1.8, "umbral_precision":0.3, "dist_mismo_lugar":0.8, "max_dist":100, "umbral_ratio_dCdP":2, "deltaO_medio":4, "impute_ratiodcdp": True, "umbral_impute_ratiodcdp": -0.5, "deltaO_ma": True, "deltaO_ma_window": 26}
##argumentos del método PlantinClassifier.classify() label_lagartos_as_1 = False kwargs_classifier = {"proba_threshold":0.45, "use_proba_ma":False, "proba_ma_window":10, "update_samePlace":True, "update_dstpt":True, "umbral_proba_dstpt":0.5, "umbral_bajo_dstpt":1.5, "use_ma":True, "dstpt_ma_window":62, "use_min_dstpt":False, "factor":0.1, "detect_lagartos": True, "label_lagartos_as_1": label_lagartos_as_1, "lagarto_min_dist_m": 0.8, "lagarto_same_place_m": 0.8, "lagarto_min_seq_len": 3, "lagarto_max_dist_m": None, # None = sin tope; p.ej. 15.0 descarta saltos de GPS "useRatioStats":False, "std_weight":1., "useDistancesStats":False, "ratio_dcdp_umbral":0.1, "dist_umbral":1., }
Version 3.4.0
- Se reescribe la detección de lagartos en
PlantinClassifierusando el algoritmo basado en distancias definido en docs/lagartos_plan.md (antes sólo se miraban corridas de ceros en las etiquetas). Ahora un lagarto es una secuencia de>= lagarto_min_seq_lenoperaciones consecutivas no plantadas (0) separadas por> lagarto_min_dist_m, tratando las operaciones de "mismo lugar" (< lagarto_same_place_m) como transparentes. - La detección corre siempre (
detect_lagartos=True) y almacena los lagartos detectados en el atributoPlantinClassifier.lagartos(lista de dicts:start,end,indices,length,mean_dist). El flaglabel_lagartos_as_1decide si las operaciones del lagarto se re-etiquetan a1. - Se eliminan los métodos viejos (
_find_lagartos,_split_run,detect_and_fix_lagartos,_fix_short_lagartos,_chek_low_dstpt) y las keysfix_lagartos/umbrales_lagartos.
Version 3.3.0
-
Se agrega feature para la detección y arreglo de operaciones dentro de lagartos.
-
Los keys para FMCreator y Classifier quedan así:
## argumentos de PlantinFMCreator kwargs_fmcreator = {"imputeDistances":True, "distanciaMedia":1.8, "umbral_precision":0.3, "dist_mismo_lugar":0.2, "max_dist":100, "umbral_ratio_dCdP":2, "deltaO_medio":4, "impute_ratiodcdp": True, "umbral_impute_ratiodcdp": -0.5, "deltaO_ma": True, "deltaO_ma_window": 26} ##argumentos del método PlantinClassifier.classify() kwargs_classifier = {"proba_threshold":0.45, "use_proba_ma":False, "proba_ma_window":10, "update_samePlace":True, "update_dstpt":True, "umbral_proba_dstpt":0.5, "umbral_bajo_dstpt":1.5, "use_ma":True, "dstpt_ma_window":62, "use_min_dstpt":False, "factor":0.1, "fix_lagartos": False, "umbrales_lagartos": (1,5), "useRatioStats":False, "std_weight":1., "useDistancesStats":False, "ratio_dcdp_umbral":0.1, "dist_umbral":1., }
Version 3.2.0
- Se modifica función para detectar operaciones en el mismo lugar de tal forma de no considerar efectos temporales.
Version 3.1.1
- Se vuelve a generar archivos de regresor_v2 y poly_features_v2 porque quedó mal cargado.
Version 3.1.0
- Se actualiza regresor para estimar fertilizante.
- Actualización de archivos para instalar la libería.
Version 3.0.0
-
Se mejora la forma de obtener valores de media movil para todas las variables en las que se usa.
-
Se corrigen bugs debido a nodos con pocas operaciones.
-
Se corrigen errores a la hora de pasar parámetros a los métodos de algunas clases.
-
Se configuran parámetros de fmcreator y plantin_classifier para el reetiquetado, los mismos son:
kwargs_fmcreator = {"imputeDistances":True, "distanciaMedia":1.8, "umbral_precision":0.3, "dist_mismo_lugar":0.2, "max_dist":100, "umbral_ratio_dCdP":2, "deltaO_medio":4, "impute_ratiodcdp": True, "umbral_impute_ratiodcdp": -0.5, "deltaO_ma": True, "deltaO_ma_window": 26} ##argumentos del método PlantinClassifier.clasiffy() kwargs_classifier = {"proba_threshold":0.4, "use_proba_ma":False, "proba_ma_window":10, "update_samePlace":True, "update_dstpt":True, "umbral_proba_dstpt":0.5, "umbral_bajo_dstpt":1.5, "use_ma":True, "dstpt_ma_window":62, "use_min_dstpt":False, "factor":0.1, "useRatioStats":False, "std_weight":1., "useDistancesStats":False, "ratio_dcdp_umbral":0.1, "dist_umbral":0.5, }
Version 2.3.0
- Se agregan funcionalidades.
- Se corrigen errores menores.
Version 2.2.0
- Se agrega baseDeltaP en PlantinFMCreator para poder dividir el timestamp de la electrónica por 10, ya que se envía en décimas de segundo.
Version 2.1.1
- Se corrige error de tiepo en TransformToOutputData.
Version 2.1.0
- Se modifica TransformInputdata para poder obtener el timestamp en newSample de OpsProcessor. Se modifica transformOutputData para entregar los datos en base a la solicitud de #43. Se modifica OpsProcessor para poder obtener los datos de salida según solicitud en #43. Close #43.
Version 2.0.0
- Se realizan cambios en TransformInputData para que convierta los datos de telemetría a la forma de lista de diccionarios, como un JSON, para que sea más fácil de usar y entender. Además, a futuro, se espera que los datos de la electrónica se puedan enviar en este formato.
- Se realizan cambios en TLMSensorDataProcessor para que pueda recibir los datos de telemetría como una lista de diccionarios. La clase permite obtener los datos como un numpy array, o indexar por filas y columnas de forma similar a un DataFrame de pandas (de hecho se usa pandas para esto).
- Se generan cambios en PlantinFMCreator para que pueda recibir los datos de telemetría como una lista de diccionarios, y se usa TLMSensorDataProcessor para procesar los datos y obtener la matriz de características, la cual es la misma que antes.
- Se generan cambios en FertilizerTransformer para que pueda recibir los datos de telemetría como una lista de diccionarios, y se usa TLMSensorDataProcessor para procesar los datos y obtener la matriz de características, la cual es la misma que antes.
- Se generan cambios en OpsProcessor para poder trabajar con el formato nuevo de datos.
Los detalles de los cambios son comentados en el issue #37.
Version 1.4.0b1
- Se empieza a trabajar sobre librería estadística para poder detectar sensores saturados.
- Se empieza a trabajar sobre actualización para trabajar con los datos en la nueva modalidad luego de la migración.
Version 1.3.1
- Se modifica PlantinClassifier para tomar el umbral máximo de dst_pt en 4 y no en 7.
Version 1.3.0
- Se agrega funcionalidad para estimar la cantidad de gramos de fertilizante en base al nivel de distorsión de fertilizante arrojado por la electrónica. Se implementa mlProcessor.FertlizerFMCreator y mlProcessor.FertilizerTransformer. Además se modifican las clases OpsProcessor y TransformToOutputData para poder usar estas nuevas clases.
Version 1.2.6
- Se agrega línea dentro de clase OpsProcessor.
Version 1.1.6
- Se modifica PlantinClassifier para mejorar el NO conteo de plantines en OSP.
Version 1.1.5
- Se quita print de función update.
Version 1.1.4
- Se implementa actualización de operaciones con bandera MODE en 1. Se hacen operaciones de plantin iguales a 0 para todas las operaciones con MODE = 1.
Version 1.1.3
- Se modifica GeoProcessor para no tener problemas con valores de latitud y longitud fuera de rangos.
Version 1.1.2
- Se modifica TimeSeriesProcessor.transform() para poder usar la modificación realizada en 1.1.1.
Version 1.1.1
- Se modifica TimeSeriesProcessor.compute_ratio_dCdP() dado que la versión de vectorize al parecer no funcionaba correctamente en ciertos casos.
Version 1.1.0
Versión 1.1 estable para trabajarse en servidor.
- Se implementa nueva estrategia para la clasificación de plantines.
Version 1.0.1
- Se agrega init.py dentro del mpdulo utils.
Version 1.0.0
- Se crean clases TransformInputData y TransformToOuputData dentro del módulo proprocessing. Se crean utils.
Version 0.4.9
- Se cierra la versión 0.4.8 y se crea la versión 0.4.9 para actualizar repositorio, diagrama de clases a esta versión y la Licencia de uso.
Version 0.4.8
- Se importa pandas en OpsProcessor.py ya que no estaba.
Version 0.4.7
- Se agregan modificaciòn en método OpsProcessor.transformInputData() y se agrega OpsProcessor.transformToOutputData().
Version 0.4.6
- Se agrega función OpsProcessor.transformInputData() para convertir la lista de diccionarios entregadas por el decoder a un array de strings necesarios para procesar y clasificar los datos.
Version 0.4.5
- Se modifica clase PlantinClassifier para que ahora tome un clasificador y lo use para clasificar operaciones.
- Se modifica OpsProcessor para poder obtener clasificaciones (y no matrices de características de plantin como se venía probando).
Version 0.4.4
- Se modifica fit() de PlantinFMCreator.
Version 0.4.3
- Se agrega fit() dentro de transform() de PlantinFMCreator.
Version 0.4.2
- Se agrega **kwargs en OpsProcessor, PlantinClassifier y PlantinFMCreator para poder setear los atributos de PlantinFMCreator desde las clases que lo usen.
Version 0.4.1
- Se corrigen problemas de importaciones circulares.
Version 0.4.0
- Se implementa OpsProcessor.
- Se implementa PlanntinClassifier.
- Se corrige salida de transform() y fit_transform() de GeoProcessor.
- Se mueve PlantinFMCreator a mlProcessors
- Se cambia nombre de TLMSensorDataCreator a TLMSensorDataProcessor
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sarapy-6.1.0.tar.gz.
File metadata
- Download URL: sarapy-6.1.0.tar.gz
- Upload date:
- Size: 99.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
64ccf77857fbd2f67c8bc8f1075363b153dd922d728c4cacca03831085ccd9e8
|
|
| MD5 |
cd2b810e16fb1474f3be6e3297168585
|
|
| BLAKE2b-256 |
480be72dae2f8ecf5f7ac89288addc15939cee1518a1e7a1c70630e4d56238ed
|
File details
Details for the file sarapy-6.1.0-py3-none-any.whl.
File metadata
- Download URL: sarapy-6.1.0-py3-none-any.whl
- Upload date:
- Size: 111.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12284bd2a65be4b81b3c077a2967ebe57160d30088307759ff04f0faf9cbf3fb
|
|
| MD5 |
6ff0ef2f7824018abad03677e23a306e
|
|
| BLAKE2b-256 |
63b89edb57ca62bcec8bd83a7dc9f64f6c61e6dad8b80e94cbacf8aed613b800
|