sarapy 1.3.1__py3-none-any.whl → 2.1.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.
- sarapy/dataProcessing/OpsProcessor.py +79 -118
- sarapy/dataProcessing/TLMSensorDataProcessor.py +73 -764
- sarapy/dataProcessing/TimeSeriesProcessor.py +19 -1
- sarapy/mlProcessors/FertilizerTransformer.py +16 -29
- sarapy/mlProcessors/PlantinFMCreator.py +39 -59
- sarapy/preprocessing/TransformInputData.py +123 -84
- sarapy/preprocessing/TransformToOutputData.py +16 -33
- sarapy/stats/__init__.py +1 -0
- sarapy/stats/stats.py +258 -0
- sarapy/utils/plotting.py +96 -0
- sarapy/version.py +1 -1
- {sarapy-1.3.1.dist-info → sarapy-2.1.0.dist-info}/METADATA +20 -1
- sarapy-2.1.0.dist-info/RECORD +29 -0
- sarapy-1.3.1.dist-info/RECORD +0 -26
- {sarapy-1.3.1.dist-info → sarapy-2.1.0.dist-info}/LICENCE +0 -0
- {sarapy-1.3.1.dist-info → sarapy-2.1.0.dist-info}/WHEEL +0 -0
- {sarapy-1.3.1.dist-info → sarapy-2.1.0.dist-info}/top_level.txt +0 -0
|
@@ -54,7 +54,14 @@ class TimeSeriesProcessor(BaseEstimator, TransformerMixin):
|
|
|
54
54
|
def transform(self, X: np.array):
|
|
55
55
|
"""Genera un array con los tiempos de operación, caminata, pico abierto y ratio_dCdP.
|
|
56
56
|
Args:
|
|
57
|
-
- X es un array de strings de forma (n, 2) donde la primera columna es el tiempo
|
|
57
|
+
- X es un array de strings de forma (n, 2) donde la primera columna es el tiempo
|
|
58
|
+
y la segunda columna es el tiempo de pico abierto (en segundos).
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
- Un array de numpy de forma (n, 4) donde la primera columna es
|
|
62
|
+
el tiempo de operación, la segunda columna es el tiempo de caminata,
|
|
63
|
+
la tercera columna es el tiempo de pico abierto y la cuarta columna es
|
|
64
|
+
el ratio entre el tiempo de caminata y el tiempo de pico abierto.
|
|
58
65
|
"""
|
|
59
66
|
|
|
60
67
|
if not self.is_fitted:
|
|
@@ -66,6 +73,17 @@ class TimeSeriesProcessor(BaseEstimator, TransformerMixin):
|
|
|
66
73
|
self._ratio_dCdP.reshape(-1,1))).round(2)
|
|
67
74
|
|
|
68
75
|
def fit_transform(self, X: np.array, y=None):
|
|
76
|
+
"""Genera un array con los tiempos de operación, caminata, pico abierto y ratio_dCdP.
|
|
77
|
+
Args:
|
|
78
|
+
- X es un array de strings de forma (n, 2) donde la primera columna es el tiempo
|
|
79
|
+
y la segunda columna es el tiempo de pico abierto (en segundos).
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
- Un array de numpy de forma (n, 4) donde la primera columna es
|
|
83
|
+
el tiempo de operación, la segunda columna es el tiempo de caminata,
|
|
84
|
+
la tercera columna es el tiempo de pico abierto y la cuarta columna es
|
|
85
|
+
el ratio entre el tiempo de caminata y el tiempo de pico abierto.
|
|
86
|
+
"""
|
|
69
87
|
self.fit(X)
|
|
70
88
|
return self.transform(X)
|
|
71
89
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import pickle
|
|
2
|
+
from sarapy.dataProcessing import TLMSensorDataProcessor
|
|
2
3
|
|
|
3
4
|
class FertilizerTransformer:
|
|
4
5
|
"""
|
|
@@ -31,51 +32,37 @@ class FertilizerTransformer:
|
|
|
31
32
|
self.fertilizer_grams = None ##cuando no se ha transformado ningún dato, se inicializa en None
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
def transform(self,
|
|
35
|
+
def transform(self, data):
|
|
35
36
|
"""Transforma los datos de distorsión de fertilizante a gramos.
|
|
36
37
|
|
|
37
38
|
Params:
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
Ejemplo: [12. 1. 12. 0. 0. 0. 0. 0. 0. 12.]
|
|
39
|
+
- data: Es una lista de diccionarios (como un JSON) con los datos de telemetría.
|
|
41
40
|
|
|
42
41
|
Returns:
|
|
43
42
|
- 0: Array con los valores de distorsión de fertilizante transformados a gramos.
|
|
44
43
|
"""
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
tlmDataProcessor = TLMSensorDataProcessor.TLMSensorDataProcessor(data)
|
|
45
|
+
X = tlmDataProcessor["SC_FT",:]
|
|
46
|
+
X_poly = self._poly_features.fit_transform(X.reshape(-1, 1))
|
|
47
47
|
self.fertilizer_grams = self._regresor.predict(X_poly)
|
|
48
48
|
|
|
49
49
|
##retorno con shape (n,)
|
|
50
50
|
return self.fertilizer_grams.reshape(-1,)
|
|
51
51
|
|
|
52
52
|
if __name__ == "__main__":
|
|
53
|
-
import os
|
|
54
53
|
import pandas as pd
|
|
55
|
-
import
|
|
54
|
+
import json
|
|
56
55
|
from sarapy.preprocessing import TransformInputData
|
|
57
|
-
from sarapy.mlProcessors import PlantinFMCreator
|
|
58
|
-
import sarapy.utils.getRawOperations as getRawOperations
|
|
59
|
-
tindata = TransformInputData.TransformInputData()
|
|
60
|
-
|
|
61
|
-
##cargo los archivos examples\2024-09-04\UPM001N\data.json y examples\2024-09-04\UPM001N\historical-data.json
|
|
62
|
-
data_path = os.path.join(os.getcwd(), "examples\\2024-09-04\\UPM001N\\data.json")
|
|
63
|
-
historical_data_path = os.path.join(os.getcwd(), "examples\\2024-09-04\\UPM001N\\historical-data.json")
|
|
64
|
-
raw_data = pd.read_json(data_path, orient="records").to_dict(orient="records")
|
|
65
|
-
raw_data2 = pd.read_json(historical_data_path, orient="records").to_dict(orient="records")
|
|
66
|
-
|
|
67
|
-
raw_ops = np.array(getRawOperations.getRawOperations(raw_data, raw_data2))
|
|
68
|
-
X = tindata.fit_transform(raw_ops) #transforma los datos de operaciones a un array de numpy
|
|
69
|
-
|
|
70
|
-
from sarapy.mlProcessors import FertilizerFMCreator
|
|
71
56
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
dst_ft = dst_ft.astype(int)
|
|
57
|
+
historical_data_path = "examples/2025-06-21/UPM000N/historical-data.json"
|
|
58
|
+
with open(historical_data_path, 'r') as file:
|
|
59
|
+
historical_data = json.load(file)
|
|
76
60
|
|
|
77
|
-
|
|
61
|
+
##cargo en un diccionario sarapy\preprocessing\telemetriaDataPosition.json
|
|
62
|
+
data_positions = json.load(open("sarapy/preprocessing/telemetriaDataPosition.json", 'r'))
|
|
63
|
+
transform_input_data = TransformInputData.TransformInputData()
|
|
64
|
+
transformed_data = transform_input_data.transform(historical_data)
|
|
78
65
|
|
|
79
|
-
fertransformer = FertilizerTransformer
|
|
80
|
-
gramos = fertransformer.transform(
|
|
66
|
+
fertransformer = FertilizerTransformer(regresor_file='modelos\\regresor.pkl', poly_features_file='modelos\\poly_features.pkl')
|
|
67
|
+
gramos = fertransformer.transform(transformed_data)
|
|
81
68
|
print(gramos[:10])
|
|
@@ -4,9 +4,10 @@ from sklearn.base import BaseEstimator, TransformerMixin
|
|
|
4
4
|
from sarapy.dataProcessing import TLMSensorDataProcessor, TimeSeriesProcessor, GeoProcessor
|
|
5
5
|
|
|
6
6
|
class PlantinFMCreator(BaseEstimator, TransformerMixin):
|
|
7
|
-
"""La clase FMCreator se encarga de crear la Feature Matrix (FM) a partir de los datos de telemetría.
|
|
7
|
+
"""La clase FMCreator se encarga de crear la Feature Matrix (FM) a partir de los datos de telemetría.
|
|
8
|
+
Se utilizan las clases TLMSensorDataProcessor, TimeSeriesProcessor y GeoProcessor para realizar las transformaciones necesarias.
|
|
8
9
|
|
|
9
|
-
Versión 0.
|
|
10
|
+
Versión 2.0.0
|
|
10
11
|
|
|
11
12
|
En esta versión la matriz de características está formada por las siguientes variables
|
|
12
13
|
|
|
@@ -14,6 +15,7 @@ class PlantinFMCreator(BaseEstimator, TransformerMixin):
|
|
|
14
15
|
- deltaO: delta operación
|
|
15
16
|
- ratio_dCdP: Ratio entre el delta de caminata y delta de pico abierto
|
|
16
17
|
- distances: Distancias entre operaciones
|
|
18
|
+
- inest_pt: Inestabilidad del plantín
|
|
17
19
|
"""
|
|
18
20
|
|
|
19
21
|
def __init__(self, imputeDistances = True, distanciaMedia:float = 1.8,
|
|
@@ -45,12 +47,7 @@ class PlantinFMCreator(BaseEstimator, TransformerMixin):
|
|
|
45
47
|
"""Fittea el objeto
|
|
46
48
|
|
|
47
49
|
Params:
|
|
48
|
-
- X: Es
|
|
49
|
-
- 0: tlm_spbb son los datos de telemetría.
|
|
50
|
-
- 1: date_oprc son los datos de fecha y hora de operación.
|
|
51
|
-
- 2: latitud de la operación
|
|
52
|
-
- 3: longitud de la operación
|
|
53
|
-
- 4: precision del GPS
|
|
50
|
+
- X: Es una lista de diccionarios (como un JSON) con los datos de telemetría.
|
|
54
51
|
"""
|
|
55
52
|
self.is_fitted = True
|
|
56
53
|
|
|
@@ -58,12 +55,7 @@ class PlantinFMCreator(BaseEstimator, TransformerMixin):
|
|
|
58
55
|
"""Transforma los datos de X en la matriz de características.
|
|
59
56
|
|
|
60
57
|
Params:
|
|
61
|
-
- X: Es
|
|
62
|
-
- 0: tlm_spbb son los datos de telemetría.
|
|
63
|
-
- 1: date_oprc son los datos de fecha y hora de operación.
|
|
64
|
-
- 2: latitud de la operación
|
|
65
|
-
- 3: longitud de la operación
|
|
66
|
-
- 4: precision del GPS
|
|
58
|
+
- X: Es una lista de diccionarios (como un JSON) con los datos de telemetría.
|
|
67
59
|
|
|
68
60
|
Returns:
|
|
69
61
|
- 0: feature_matrix: (deltaO, ratio_dCdP, distances)
|
|
@@ -74,40 +66,35 @@ class PlantinFMCreator(BaseEstimator, TransformerMixin):
|
|
|
74
66
|
if not self.is_fitted:
|
|
75
67
|
raise RuntimeError("El modelo no ha sido fitteado.")
|
|
76
68
|
|
|
77
|
-
##instanciamos los objetos
|
|
78
|
-
|
|
69
|
+
##instanciamos los objetos a usar
|
|
70
|
+
self.tlmDataProcessor = TLMSensorDataProcessor.TLMSensorDataProcessor(X)
|
|
79
71
|
timeProcessor = TimeSeriesProcessor.TimeSeriesProcessor()
|
|
72
|
+
tpDP = timeProcessor._dataPositions
|
|
80
73
|
geoprocessor = GeoProcessor.GeoProcessor()
|
|
81
74
|
|
|
82
|
-
|
|
83
|
-
date_oprc =
|
|
84
|
-
|
|
85
|
-
|
|
75
|
+
|
|
76
|
+
date_oprc = self.tlmDataProcessor["date_oprc",:] #datos de fecha y hora de operación
|
|
77
|
+
time_ac = self.tlmDataProcessor["TIME_AC",:] #datos de fecha y hora de operación en formato timestamp
|
|
78
|
+
lats = self.tlmDataProcessor["latitud",:] #latitudes de las operaciones
|
|
79
|
+
longs = self.tlmDataProcessor["longitud",:] #longitudes de las operaciones
|
|
80
|
+
self.dst_pt = self.tlmDataProcessor["SC_PT",:] #distorsión del plantín
|
|
81
|
+
self.inest_pt = self.tlmDataProcessor["INST_PT",:] #inest
|
|
86
82
|
# precitions = X[:,4].astype(float) #precision del GPS
|
|
87
83
|
|
|
88
|
-
##***** OBTENEMOS LOS DATOS PARA FITEAR LOS OBJETOS Y ASÍ PROCESAR LA FM *****
|
|
89
|
-
##obtengo las posiciones de los datos de tlmDataExtractor y timeProcessor
|
|
90
|
-
self._tlmdeDP = tlmDataExtractor.dataPositions #posiciones de los datos transformados de tlmDataExtractor
|
|
91
|
-
self._tpDP = timeProcessor.dataPositions #posiciones de los datos transformados de timeProcessor
|
|
92
|
-
|
|
93
|
-
##fitteamos tlmse con los datos de telemetría
|
|
94
|
-
self._tlmExtracted = tlmDataExtractor.fit_transform(tlm_spbb)
|
|
84
|
+
##***** OBTENEMOS LOS DATOS PARA FITEAR LOS OBJETOS Y ASÍ PROCESAR LA FM *****
|
|
95
85
|
|
|
96
86
|
##fitteamos timeProcessor con los datos de fecha y hora de operación y los TIMEAC
|
|
97
|
-
timeData = np.hstack((date_oprc.reshape(-1,1),
|
|
87
|
+
timeData = np.hstack((date_oprc.reshape(-1,1),time_ac.reshape(-1, 1)))
|
|
88
|
+
|
|
98
89
|
self._timeDeltas = timeProcessor.fit_transform(timeData)
|
|
99
90
|
|
|
100
91
|
##fitteamos geoprocessor con las latitudes y longitudes
|
|
101
|
-
##genero un array de puntos de la forma (n,2)
|
|
102
92
|
points = np.hstack((lats.reshape(-1,1),longs.reshape(-1,1)))
|
|
103
93
|
self._distances = geoprocessor.fit_transform(points)
|
|
104
94
|
|
|
105
|
-
self.dst_pt = self._tlmExtracted[:,self._tlmdeDP["DSTRPT"]]
|
|
106
|
-
self.inest_pt = self._tlmExtracted[:,self._tlmdeDP["INESTPT"]]
|
|
107
|
-
|
|
108
95
|
##armamos la feature matrix
|
|
109
|
-
self.featureMatrix = np.vstack((self._timeDeltas[:,
|
|
110
|
-
self._timeDeltas[:,
|
|
96
|
+
self.featureMatrix = np.vstack((self._timeDeltas[:,tpDP["deltaO"]],
|
|
97
|
+
self._timeDeltas[:,tpDP["ratio_dCdP"]],
|
|
111
98
|
self._distances)).T
|
|
112
99
|
|
|
113
100
|
return self.featureMatrix, self.dst_pt, self.inest_pt
|
|
@@ -116,12 +103,7 @@ class PlantinFMCreator(BaseEstimator, TransformerMixin):
|
|
|
116
103
|
"""Fittea y transforma los datos de X en la matriz de características.
|
|
117
104
|
|
|
118
105
|
Params:
|
|
119
|
-
- X: Es
|
|
120
|
-
- 0: tlm_spbb son los datos de telemetría.
|
|
121
|
-
- 1: date_oprc son los datos de fecha y hora de operación.
|
|
122
|
-
- 2: latitud de la operación
|
|
123
|
-
- 3: longitud de la operación
|
|
124
|
-
- 4: precision del GPS
|
|
106
|
+
- X: Es una lista de diccionarios (como un JSON) con los datos de telemetría.
|
|
125
107
|
|
|
126
108
|
Returns:
|
|
127
109
|
- 0: feature_matrix: (deltaO, ratio_dCdP, distances)
|
|
@@ -131,10 +113,10 @@ class PlantinFMCreator(BaseEstimator, TransformerMixin):
|
|
|
131
113
|
self.fit(X)
|
|
132
114
|
return self.transform(X)
|
|
133
115
|
|
|
134
|
-
@property
|
|
135
|
-
def tlmExtracted(self):
|
|
136
|
-
|
|
137
|
-
|
|
116
|
+
# @property
|
|
117
|
+
# def tlmExtracted(self):
|
|
118
|
+
# """Devuelve los datos de telemetría extraídos."""
|
|
119
|
+
# return self.tlmExtracted
|
|
138
120
|
|
|
139
121
|
@property
|
|
140
122
|
def tlmdeDP(self):
|
|
@@ -158,23 +140,21 @@ class PlantinFMCreator(BaseEstimator, TransformerMixin):
|
|
|
158
140
|
|
|
159
141
|
|
|
160
142
|
if __name__ == "__main__":
|
|
161
|
-
import os
|
|
162
143
|
import pandas as pd
|
|
163
|
-
import
|
|
144
|
+
import json
|
|
164
145
|
from sarapy.preprocessing import TransformInputData
|
|
165
|
-
from sarapy.mlProcessors import PlantinFMCreator
|
|
166
|
-
import sarapy.utils.getRawOperations as getRawOperations
|
|
167
|
-
|
|
168
|
-
fmcreator = PlantinFMCreator.PlantinFMCreator(imputeDistances=False)
|
|
169
|
-
tindata = TransformInputData.TransformInputData()
|
|
170
146
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
raw_data2 = pd.read_json(historical_data_path, orient="records").to_dict(orient="records")
|
|
147
|
+
historical_data_path = "examples/2025-06-21/UPM000N/historical-data.json"
|
|
148
|
+
with open(historical_data_path, 'r') as file:
|
|
149
|
+
historical_data = json.load(file)
|
|
150
|
+
df = pd.DataFrame(historical_data)
|
|
176
151
|
|
|
177
|
-
|
|
178
|
-
|
|
152
|
+
##cargo en un diccionario sarapy\preprocessing\telemetriaDataPosition.json
|
|
153
|
+
data_positions = json.load(open("sarapy/preprocessing/telemetriaDataPosition.json", 'r'))
|
|
154
|
+
transform_input_data = TransformInputData.TransformInputData()
|
|
155
|
+
X = transform_input_data.transform(historical_data)
|
|
156
|
+
|
|
157
|
+
fmcreator = PlantinFMCreator(imputeDistances=False)
|
|
179
158
|
|
|
180
|
-
fm, dst_pt, inest_pt = fmcreator.fit_transform(X
|
|
159
|
+
fm, dst_pt, inest_pt = fmcreator.fit_transform(X)
|
|
160
|
+
print(fm.shape) # Debería ser (n_operaciones, 3)
|
|
@@ -10,101 +10,140 @@ class TransformInputData(BaseEstimator, TransformerMixin):
|
|
|
10
10
|
|
|
11
11
|
def __init__(self):
|
|
12
12
|
"""
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Args:
|
|
16
|
-
- features_list: Lista con los nombres de las columnas a extraer de los datos recibidos de cada operación.
|
|
17
|
-
"""
|
|
18
|
-
self.is_fitted = False
|
|
19
|
-
self.positions = {"id_db_h":0,
|
|
20
|
-
"ID_NPDP":1,
|
|
21
|
-
"TLM_NPDP":2,
|
|
22
|
-
"date_oprc":3,
|
|
23
|
-
"latitud":4,
|
|
24
|
-
"longitud":5,
|
|
25
|
-
"Precision":6,
|
|
26
|
-
"FR":7,
|
|
27
|
-
"id_db_dw":8}
|
|
13
|
+
Inicializa la clase TransformToJson.
|
|
28
14
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
15
|
+
Args:
|
|
16
|
+
data_positions (dict): Diccionario con las posiciones de los datos en el formato JSON. Se utiliza para identificar
|
|
17
|
+
la posición de cada dato en el JSON transformado. Diferentes transformadores pueden tener diferentes posiciones de datos.
|
|
32
18
|
"""
|
|
33
|
-
self.
|
|
19
|
+
# self.dataPositions = TransformInputData.data_positions # Diccionario para almacenar las posiciones de los datos
|
|
20
|
+
self.data_positions = { "Date_oprc": 0, "Operacion": 1, "SC_PT": 2, "DATA_PT": 3, "INST_PT": 4, "RES_PT": 5,
|
|
21
|
+
"CLMP_PT": 6, "SC_FT": 7, "DATA_FT": 8, "INST_FT": 9, "RES_FT": 10, "CLMP_FT": 11, "SC_GYRO_Z": 12,
|
|
22
|
+
"SC_GYRO_Y": 13, "SC_GYRO_X": 14, "DATA_GYRO": 15, "INST_GYRO": 16, "CLMP_GYRO": 17, "SC_ACCEL_Z": 18,
|
|
23
|
+
"SC_ACCEL_Y": 19, "SC_ACCEL_X": 20, "DATA_ACCEL": 21, "INST_ACCEL": 22, "CLMP_ACCEL": 23, "TIME_AC": 24,
|
|
24
|
+
"OPEN_AC": 25, "Longitud_N": 26, "Latitud_N": 27, "Precision_N": 28, "N_FIX": 29, "N_SIV": 30, "N_PDOP": 31,
|
|
25
|
+
"N_NBAT": 32, "N_SBAT": 33, "N_VBAT": 34, "N_CBAT": 35, "N_CHRG": 36, "ID_NPDP": 37, "N_MODE": 38, "N_RST": 39,
|
|
26
|
+
"N_FLASH": 40, "N_CLK": 41, "N_EST_GNSS": 42, "N_EST_NFC": 43, "N_EST_RF": 44, "N_EST_IMU": 45, "N_EST_BMS": 46,
|
|
27
|
+
"EST_CDC": 47, "N_ONLINE": 48, "N_RSSI": 49, "SEND_TRY": 50, "PMST": 51, "ID_OPRR": 52, "N_DATA_ID": 53,
|
|
28
|
+
"ID_GPDP": 54, "G_MODE": 55, "G_RST": 56, "G_FLASH": 57, "G_CLK": 58, "G_EST_4G": 59, "G_EST_NFC": 60,
|
|
29
|
+
"G_EST_IMU": 61,"G_EST_BMS": 62, "G_RSSI": 63, "G_NETWORK": 64, "G_ONLINE": 65, "G_SIGNAL": 66,
|
|
30
|
+
"G_MONEY": 67, "ID_CDLL": 68,"G_DATA_ID": 69, "Longitud_G": 70, "Latitud_G": 71, "Precision_G": 72,
|
|
31
|
+
"G_FIX": 73, "G_SIV": 74, "G_PDOP": 75, "G_NBAT": 76, "G_SBAT": 77, "G_VBAT": 78, "G_CBAT": 79, "G_CHRG": 80,
|
|
32
|
+
"VUX1": 81, "VUX2": 82, "VUX3": 83, "VUX4": 84, "VUX5": 85, "VUX6": 86, "VUX7": 87, "VUX8": 88,
|
|
33
|
+
"VUX9": 89, "VUX10": 90}
|
|
34
|
+
self.dataFloat = ["latitud","longitud","Longitud_N","Latitud_N","Longitud_G","Latitud_G","date_oprc","Date_oprc"]
|
|
35
|
+
self.dataString = ["timestamp"]
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
d["ID_NPDP"],
|
|
37
|
-
''.join([bin(byte)[2:].zfill(8) for byte in d["TLM_NPDP"]]),
|
|
38
|
-
int(d["date_oprc"].timestamp()),
|
|
39
|
-
d["Latitud"],
|
|
40
|
-
d["Longitud"],
|
|
41
|
-
d["Precision"],
|
|
42
|
-
d["FR"],
|
|
43
|
-
d["id_db_dw"]] for d in X])
|
|
44
|
-
|
|
45
|
-
return self
|
|
46
|
-
|
|
47
|
-
def transform(self, X:np.array):
|
|
37
|
+
def transform(self, X):
|
|
48
38
|
"""
|
|
49
|
-
|
|
39
|
+
Método para transformar los datos en formato JSON.
|
|
50
40
|
|
|
51
41
|
Args:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
42
|
+
X: Lista de diccionario. Cada diccionario tiene la forma.
|
|
43
|
+
Ejemplo (NOTA: El salto de línea es agregado para mejorar la legibilidad):
|
|
44
|
+
[
|
|
45
|
+
{"id": 6, "receiver_timestamp": "2025-06-21T15:51:36.527825+00:00", "timestamp": "2025-06-21T15:51:01.000002+00:00", "datum": null,
|
|
46
|
+
"csv_datum": "2025-06-21T15:51:01.000002+00:00,2,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-58.0321,-33.2471,
|
|
47
|
+
1,0,0,0,0,0,0,0,0,0,1,1,1,0,1,1,0,0,0,0,1,0,0,1,1,0,3,0,0,0,0,3,0,0,0,0,0,1,0,0,0,0,0.0000,0.0000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0",
|
|
48
|
+
"longitude": null, "latitude": null, "accuracy": null, "tag_seedling": null, "tag_fertilizer": null}
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
NOTA: Cada diccionario debe tener, sí o sí, los siguientes keys (además de los que ya tiene csv_datum)
|
|
52
|
+
- 0: id_db_h (sale de "id" dentro de los datos de entrada X)
|
|
53
|
+
- 1: ID_NPDP (sale de csv_datum)
|
|
54
|
+
- 3: date_oprc (sale de csv_datum)
|
|
55
|
+
- 4: latitud (sale de csv_datum)
|
|
56
|
+
- 5: longitud (sale de csv_datum)
|
|
57
|
+
- 6: precision (sale de csv_datum)
|
|
58
|
+
- 7: FR
|
|
59
|
+
- 8: id_db_dw (sale de "Operacion" dentro de csv_datum)
|
|
69
60
|
|
|
70
61
|
Returns:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
- 7: FR
|
|
80
|
-
- 8: id_db_dw
|
|
81
|
-
"""
|
|
82
|
-
##chequeamos si se ha llamado a fit(). Sino, se arroja un error
|
|
83
|
-
if not self.is_fitted:
|
|
84
|
-
raise ValueError("TransformInputData no ha sido fitteado. Llame a fit() previamente.")
|
|
62
|
+
Lista de diccionarios con los datos transformados. Básciamente se toma csv_datum y se agrega a cada uno de los diccionarios de la lista.
|
|
63
|
+
Para esto, se usa el diccionario `dataPositions` para identificar las posiciones y qué son cada uno de los valores dentro de `csv_datum`.
|
|
64
|
+
Los diccionarios dentro de la lista no tendrán csv_datum.
|
|
65
|
+
"""
|
|
66
|
+
self.data_transformed = []
|
|
67
|
+
dict_structre = {"id_db_h":None, "id_db_dw":None, "ID_NPDP":None,
|
|
68
|
+
"date_oprc":None, "latitud":None, "longitud":None,
|
|
69
|
+
"precision":None, "FR":None, "timestamp": None}
|
|
85
70
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
71
|
+
##agrego los keys que están en dataPositions con valores None
|
|
72
|
+
for key in self.data_positions.keys():
|
|
73
|
+
dict_structre[key] = None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
for row in X:
|
|
77
|
+
# Crear un diccionario para almacenar los datos transformados
|
|
78
|
+
data_dict = dict_structre.copy()
|
|
79
|
+
# Asignar los valores de csv_datum a las posiciones correspondientes
|
|
80
|
+
csv_datum = row.get("csv_datum", "")
|
|
81
|
+
if csv_datum:
|
|
82
|
+
values = csv_datum.split(',')
|
|
83
|
+
for key, pos in self.data_positions.items():
|
|
84
|
+
if pos < len(values):
|
|
85
|
+
data_dict[key] = values[pos]
|
|
86
|
+
else:
|
|
87
|
+
data_dict[key] = None
|
|
88
|
+
|
|
89
|
+
data_dict["id_db_h"] = row.get("id", None)
|
|
90
|
+
data_dict["id_db_dw"] = data_dict.get("Operacion", None)
|
|
91
|
+
data_dict["ID_NPDP"] = data_dict.get("ID_NPDP", None)
|
|
92
|
+
##convierto Date_oprc a un objeto datetime y paso a timestamp
|
|
93
|
+
date_oprc = data_dict.get("Date_oprc", None)
|
|
94
|
+
if date_oprc:
|
|
95
|
+
try:
|
|
96
|
+
from dateutil import parser
|
|
97
|
+
data_dict["date_oprc"] = parser.isoparse(date_oprc).timestamp()
|
|
98
|
+
except Exception as e:
|
|
99
|
+
print(f"Error parsing date_oprc: {e}")
|
|
100
|
+
data_dict["date_oprc"] = None
|
|
101
|
+
else:
|
|
102
|
+
data_dict["date_oprc"] = None
|
|
103
|
+
data_dict["latitud"] = data_dict.get("Latitud_N", None)
|
|
104
|
+
data_dict["longitud"] = data_dict.get("Longitud_N", None)
|
|
105
|
+
data_dict["precision"] = data_dict.get("Precision_N", None)
|
|
106
|
+
data_dict["Date_oprc"] = data_dict.get("date_oprc", None)
|
|
107
|
+
data_dict["latitud"] = data_dict.get("Latitud_N", None)
|
|
108
|
+
data_dict["longitud"] = data_dict.get("Longitud_N", None)
|
|
109
|
+
data_dict["timestamp"] = row.get("timestamp", None)
|
|
110
|
+
# data_dict["FR"] = row.get("tag_fertilizer", None)
|
|
111
|
+
|
|
112
|
+
# Agregar el diccionario transformado a la lista
|
|
113
|
+
self.data_transformed.append(data_dict)
|
|
114
|
+
|
|
115
|
+
##convierto los datos de self.dataFloat a float y el resto a int
|
|
116
|
+
for data in self.data_transformed:
|
|
117
|
+
for key, value in data.items():
|
|
118
|
+
if key in self.dataFloat:
|
|
119
|
+
try:
|
|
120
|
+
data[key] = float(value) if value else None
|
|
121
|
+
except ValueError:
|
|
122
|
+
data[key] = None
|
|
123
|
+
elif key in self.dataString:
|
|
124
|
+
try:
|
|
125
|
+
data[key] = str(value) if value else None
|
|
126
|
+
except ValueError:
|
|
127
|
+
data[key] = None
|
|
128
|
+
else:
|
|
129
|
+
try:
|
|
130
|
+
data[key] = int(value) if value else None
|
|
131
|
+
except ValueError:
|
|
132
|
+
data[key] = None
|
|
133
|
+
|
|
134
|
+
return self.data_transformed
|
|
91
135
|
|
|
92
136
|
if __name__ == "__main__":
|
|
93
137
|
import pandas as pd
|
|
94
|
-
import
|
|
95
|
-
import os
|
|
96
|
-
from sarapy.utils.getRawOperations import getRawOperations
|
|
97
|
-
|
|
98
|
-
# features=["id_db_h","ID_NPDP","TLM_NPDP","date_oprc","latitud","longitud","Precision","FR","id_db_dw",
|
|
99
|
-
# "INESTPT","INESTFT"]
|
|
100
|
-
|
|
101
|
-
transform_input_data = TransformInputData()
|
|
102
|
-
|
|
103
|
-
#cargo "examples\\2024-05-30\\UPM007N\\data.json"
|
|
104
|
-
data = pd.read_json("examples\\2024-05-30\\UPM007N\\data.json").to_dict(orient="records")
|
|
105
|
-
historical_data = pd.read_json("examples\\2024-05-30\\UPM007N\\historical-data.json").to_dict(orient="records")
|
|
138
|
+
import json
|
|
106
139
|
|
|
107
|
-
|
|
140
|
+
historical_data_path = "examples/2025-06-21/UPM000N/historical-data.json"
|
|
141
|
+
with open(historical_data_path, 'r') as file:
|
|
142
|
+
historical_data = json.load(file)
|
|
143
|
+
df = pd.DataFrame(historical_data)
|
|
108
144
|
|
|
109
|
-
|
|
110
|
-
|
|
145
|
+
##cargo en un diccionario sarapy\preprocessing\telemetriaDataPosition.json
|
|
146
|
+
data_positions = json.load(open("sarapy/preprocessing/telemetriaDataPosition.json", 'r'))
|
|
147
|
+
transform_input_data = TransformInputData()
|
|
148
|
+
transformed_data = transform_input_data.transform(historical_data)
|
|
149
|
+
print(transformed_data[-1])
|
|
@@ -10,14 +10,11 @@ class TransformToOutputData(BaseEstimator, TransformerMixin):
|
|
|
10
10
|
- dataToTransform: array con los datos de las operaciones clasificadas.
|
|
11
11
|
Actualmente el array de dataToTransform es de (n,5) con las columnas siguientes
|
|
12
12
|
|
|
13
|
-
- 0:
|
|
14
|
-
- 1:
|
|
15
|
-
- 2:
|
|
16
|
-
- 3: tag_fertilizer
|
|
17
|
-
- 4: date_oprc
|
|
13
|
+
- 0: timestamps
|
|
14
|
+
- 1: tag_seedling
|
|
15
|
+
- 2: tag_fertilizer
|
|
18
16
|
Returns:
|
|
19
17
|
Retorna una lista de diccionarios con la siguiente estructura
|
|
20
|
-
[{"id_db_h", },]
|
|
21
18
|
"""
|
|
22
19
|
|
|
23
20
|
def __init__(self):
|
|
@@ -28,11 +25,6 @@ class TransformToOutputData(BaseEstimator, TransformerMixin):
|
|
|
28
25
|
- features_list: Lista con los nombres de las columnas a extraer de los datos recibidos de cada operación.
|
|
29
26
|
"""
|
|
30
27
|
self.is_fitted = False
|
|
31
|
-
self.positions = {"id_db_h":0,
|
|
32
|
-
"id_db_dw":1,
|
|
33
|
-
"tag_seedling":2,
|
|
34
|
-
"tag_fertilizer":3,
|
|
35
|
-
"date_oprc":4}
|
|
36
28
|
|
|
37
29
|
def fit(self, X:np.array, y = None):
|
|
38
30
|
"""
|
|
@@ -40,21 +32,16 @@ class TransformToOutputData(BaseEstimator, TransformerMixin):
|
|
|
40
32
|
- X: array con los datos de las operaciones clasificadas.
|
|
41
33
|
Actualmente el array de dataToTransform es de (n,5) con las columnas siguientes
|
|
42
34
|
|
|
43
|
-
- 0:
|
|
44
|
-
- 1:
|
|
45
|
-
- 2:
|
|
46
|
-
- 3: tag_fertilizer
|
|
47
|
-
- 4: date_oprc
|
|
35
|
+
- 0: timestamps
|
|
36
|
+
- 1: tag_seedling
|
|
37
|
+
- 2: tag_fertilizer
|
|
48
38
|
"""
|
|
49
39
|
self.is_fitted = True
|
|
50
|
-
keys = ["
|
|
40
|
+
keys = ["timestamps","tag_seedling", "tag_fertilizer"]
|
|
51
41
|
self.temp_df = pd.DataFrame(X, columns = keys)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
self.temp_df.loc[:,"date_oprc"] = date_oprc.flatten()
|
|
56
|
-
##convierto las columnas "id_db_h", "id_db_dw", "tag_seedling" a int
|
|
57
|
-
for col in ["id_db_h", "id_db_dw", "tag_seedling"]:
|
|
42
|
+
|
|
43
|
+
##convierto las columnas "timestamps", "tag_seedling" a int
|
|
44
|
+
for col in ["tag_seedling"]:
|
|
58
45
|
self.temp_df[col] = self.temp_df[col].astype(float).astype(int)
|
|
59
46
|
##convierto la columna "tag_fertilizer" a float de y redondeo a 3 decimales
|
|
60
47
|
self.temp_df["tag_fertilizer"] = self.temp_df["tag_fertilizer"].astype(float).round(3)
|
|
@@ -67,11 +54,9 @@ class TransformToOutputData(BaseEstimator, TransformerMixin):
|
|
|
67
54
|
- X: array con los datos de las operaciones clasificadas.
|
|
68
55
|
Actualmente el array de dataToTransform es de (n,5) con las columnas siguientes
|
|
69
56
|
|
|
70
|
-
- 0:
|
|
71
|
-
- 1:
|
|
72
|
-
- 2:
|
|
73
|
-
- 3: tag_fertilizer
|
|
74
|
-
- 4: date_oprc
|
|
57
|
+
- 0: timestamps
|
|
58
|
+
- 1: tag_seedling
|
|
59
|
+
- 2: tag_fertilizer
|
|
75
60
|
Returns:
|
|
76
61
|
Retorna una lista de diccionarios donde cada diccionario contiene los datos de una operación para los campos mencionados anteriormente.
|
|
77
62
|
"""
|
|
@@ -84,11 +69,9 @@ class TransformToOutputData(BaseEstimator, TransformerMixin):
|
|
|
84
69
|
- X: array con los datos de las operaciones clasificadas.
|
|
85
70
|
Actualmente el array de dataToTransform es de (n,5) con las columnas siguientes
|
|
86
71
|
|
|
87
|
-
- 0:
|
|
88
|
-
- 1:
|
|
89
|
-
- 2:
|
|
90
|
-
- 3: tag_fertilizer
|
|
91
|
-
- 4: date_oprc
|
|
72
|
+
- 0: timestamps
|
|
73
|
+
- 1: tag_seedling
|
|
74
|
+
- 2: tag_fertilizer
|
|
92
75
|
Returns:
|
|
93
76
|
Retorna una lista de diccionarios donde cada diccionario contiene los datos de una operación para los campos mencionados anteriormente.
|
|
94
77
|
"""
|
sarapy/stats/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# from stats.stats import *
|