PyDPEET 0.2.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.
- pydpeet/__init__.py +56 -0
- pydpeet/citations/__init__.py +7 -0
- pydpeet/citations/citeme.py +397 -0
- pydpeet/citations/html_writer.py +137 -0
- pydpeet/dev_utils/__init__.py +7 -0
- pydpeet/dev_utils/generate_inits/__init__.py +7 -0
- pydpeet/dev_utils/generate_inits/generate_inits.py +327 -0
- pydpeet/io/__init__.py +7 -0
- pydpeet/io/configs/__init__.py +7 -0
- pydpeet/io/configs/config.py +227 -0
- pydpeet/io/configs/const.py +1 -0
- pydpeet/io/convert.py +594 -0
- pydpeet/io/device/__init__.py +7 -0
- pydpeet/io/device/arbin_4_23_PV090331/__init__.py +7 -0
- pydpeet/io/device/arbin_4_23_PV090331/formatter.py +22 -0
- pydpeet/io/device/arbin_4_23_PV090331/mapper.py +18 -0
- pydpeet/io/device/arbin_4_23_PV090331/reader.py +68 -0
- pydpeet/io/device/arbin_8_00_PV221201/__init__.py +7 -0
- pydpeet/io/device/arbin_8_00_PV221201/formatter.py +26 -0
- pydpeet/io/device/arbin_8_00_PV221201/mapper.py +18 -0
- pydpeet/io/device/arbin_8_00_PV221201/reader.py +66 -0
- pydpeet/io/device/basytec_6_3_1_0/__init__.py +7 -0
- pydpeet/io/device/basytec_6_3_1_0/formatter.py +18 -0
- pydpeet/io/device/basytec_6_3_1_0/mapper.py +18 -0
- pydpeet/io/device/basytec_6_3_1_0/reader.py +54 -0
- pydpeet/io/device/digatron_4_20_6_236/__init__.py +7 -0
- pydpeet/io/device/digatron_4_20_6_236/formatter.py +27 -0
- pydpeet/io/device/digatron_4_20_6_236/mapper.py +18 -0
- pydpeet/io/device/digatron_4_20_6_236/reader.py +45 -0
- pydpeet/io/device/digatron_eis_4_20_6_236/__init__.py +7 -0
- pydpeet/io/device/digatron_eis_4_20_6_236/formatter.py +39 -0
- pydpeet/io/device/digatron_eis_4_20_6_236/mapper.py +18 -0
- pydpeet/io/device/digatron_eis_4_20_6_236/reader.py +42 -0
- pydpeet/io/device/neware_8_0_0_516/__init__.py +7 -0
- pydpeet/io/device/neware_8_0_0_516/formatter.py +31 -0
- pydpeet/io/device/neware_8_0_0_516/mapper.py +18 -0
- pydpeet/io/device/neware_8_0_0_516/reader.py +397 -0
- pydpeet/io/device/parstat_2_63_3/__init__.py +7 -0
- pydpeet/io/device/parstat_2_63_3/formatter.py +34 -0
- pydpeet/io/device/parstat_2_63_3/mapper.py +18 -0
- pydpeet/io/device/parstat_2_63_3/reader.py +34 -0
- pydpeet/io/device/safion_1_9/__init__.py +7 -0
- pydpeet/io/device/safion_1_9/formatter.py +25 -0
- pydpeet/io/device/safion_1_9/mapper.py +18 -0
- pydpeet/io/device/safion_1_9/reader.py +89 -0
- pydpeet/io/device/zahner/__init__.py +7 -0
- pydpeet/io/device/zahner/formatter.py +73 -0
- pydpeet/io/device/zahner/mapper.py +34 -0
- pydpeet/io/device/zahner/reader.py +46 -0
- pydpeet/io/device/zahner_new/__init__.py +7 -0
- pydpeet/io/device/zahner_new/formatter.py +72 -0
- pydpeet/io/device/zahner_new/mapper.py +50 -0
- pydpeet/io/device/zahner_new/reader.py +46 -0
- pydpeet/io/map.py +69 -0
- pydpeet/io/read.py +50 -0
- pydpeet/io/utils/__init__.py +7 -0
- pydpeet/io/utils/ext_path.py +34 -0
- pydpeet/io/utils/formatter_utils.py +429 -0
- pydpeet/io/utils/load_custom_module.py +33 -0
- pydpeet/io/utils/timing.py +36 -0
- pydpeet/io/write.py +99 -0
- pydpeet/process/__init__.py +7 -0
- pydpeet/process/analyze/__init__.py +7 -0
- pydpeet/process/analyze/average.py +297 -0
- pydpeet/process/analyze/capacity.py +208 -0
- pydpeet/process/analyze/configs/__init__.py +7 -0
- pydpeet/process/analyze/configs/battery_config.py +38 -0
- pydpeet/process/analyze/configs/ocv_config.py +177 -0
- pydpeet/process/analyze/configs/step_analyzer_config.py +178 -0
- pydpeet/process/analyze/cycle.py +63 -0
- pydpeet/process/analyze/efficiency.py +182 -0
- pydpeet/process/analyze/energy.py +51 -0
- pydpeet/process/analyze/extract/__init__.py +7 -0
- pydpeet/process/analyze/extract/dva_ica.py +224 -0
- pydpeet/process/analyze/extract/ocv.py +196 -0
- pydpeet/process/analyze/power.py +32 -0
- pydpeet/process/analyze/resistance.py +87 -0
- pydpeet/process/analyze/soc.py +418 -0
- pydpeet/process/analyze/soh.py +72 -0
- pydpeet/process/analyze/utils.py +122 -0
- pydpeet/process/merge/__init__.py +7 -0
- pydpeet/process/merge/series.py +274 -0
- pydpeet/process/sequence/__init__.py +7 -0
- pydpeet/process/sequence/configs/__init__.py +7 -0
- pydpeet/process/sequence/configs/config.py +17 -0
- pydpeet/process/sequence/step_analyzer.py +440 -0
- pydpeet/process/sequence/utils/__init__.py +7 -0
- pydpeet/process/sequence/utils/annotate/__init__.py +7 -0
- pydpeet/process/sequence/utils/annotate/annotate_primitives.py +419 -0
- pydpeet/process/sequence/utils/configs/CONFIG_Fallback.py +231 -0
- pydpeet/process/sequence/utils/configs/CONFIG_preprocessing.py +243 -0
- pydpeet/process/sequence/utils/configs/__init__.py +7 -0
- pydpeet/process/sequence/utils/console_prints/__init__.py +7 -0
- pydpeet/process/sequence/utils/console_prints/log_time.py +30 -0
- pydpeet/process/sequence/utils/postprocessing/__init__.py +7 -0
- pydpeet/process/sequence/utils/postprocessing/df_primitives_correction.py +166 -0
- pydpeet/process/sequence/utils/postprocessing/filter_df.py +168 -0
- pydpeet/process/sequence/utils/postprocessing/generate_instructions.py +297 -0
- pydpeet/process/sequence/utils/preprocessing/__init__.py +7 -0
- pydpeet/process/sequence/utils/preprocessing/calculate_thresholds.py +27 -0
- pydpeet/process/sequence/utils/processing/__init__.py +7 -0
- pydpeet/process/sequence/utils/processing/analyze_segments.py +368 -0
- pydpeet/process/sequence/utils/processing/attempt_to_merge_neighboring_segments.py +122 -0
- pydpeet/process/sequence/utils/processing/check_CV_results.py +226 -0
- pydpeet/process/sequence/utils/processing/check_power_zero_watt_segments.py +85 -0
- pydpeet/process/sequence/utils/processing/check_zero_length.py +117 -0
- pydpeet/process/sequence/utils/processing/split_in_segments.py +97 -0
- pydpeet/process/sequence/utils/processing/supress_smaller_segments.py +99 -0
- pydpeet/process/sequence/utils/processing/widen_constant_segments.py +185 -0
- pydpeet/process/sequence/utils/visualize/__init__.py +7 -0
- pydpeet/process/sequence/utils/visualize/visualize_data.py +288 -0
- pydpeet/res/__init__.py +7 -0
- pydpeet/settings.py +0 -0
- pydpeet/utils/__init__.py +7 -0
- pydpeet/utils/logging_style.py +28 -0
- pydpeet/version.py +0 -0
- pydpeet-0.2.0.dist-info/METADATA +85 -0
- pydpeet-0.2.0.dist-info/RECORD +122 -0
- pydpeet-0.2.0.dist-info/WHEEL +5 -0
- pydpeet-0.2.0.dist-info/licenses/AUTHORS.md +0 -0
- pydpeet-0.2.0.dist-info/licenses/LICENCE.md +27 -0
- pydpeet-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def typecast(
|
|
8
|
+
df: pd.DataFrame,
|
|
9
|
+
column_name: str,
|
|
10
|
+
datatype,
|
|
11
|
+
) -> pd.DataFrame:
|
|
12
|
+
"""
|
|
13
|
+
Try to typecast a column in a DataFrame to a given type.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
data_frame : pandas.DataFrame
|
|
18
|
+
DataFrame to be modified
|
|
19
|
+
column_name : str
|
|
20
|
+
Name of the column to be typecast
|
|
21
|
+
datatype : type
|
|
22
|
+
datatype to which the column should be typecast
|
|
23
|
+
|
|
24
|
+
Returns
|
|
25
|
+
-------
|
|
26
|
+
pandas.DataFrame
|
|
27
|
+
Modified DataFrame
|
|
28
|
+
"""
|
|
29
|
+
try:
|
|
30
|
+
if df is None:
|
|
31
|
+
raise ValueError(f"{df} is None")
|
|
32
|
+
if column_name is None:
|
|
33
|
+
raise ValueError(f"{column_name} is None")
|
|
34
|
+
if datatype is None:
|
|
35
|
+
raise ValueError(f"{datatype} is None")
|
|
36
|
+
if type(column_name) is not str:
|
|
37
|
+
raise ValueError(f"{column_name} is not a string")
|
|
38
|
+
if column_name not in df.columns:
|
|
39
|
+
raise ValueError(f"{column_name} is not in {df.columns}")
|
|
40
|
+
df[column_name] = df[column_name].astype(datatype)
|
|
41
|
+
except Exception:
|
|
42
|
+
logging.warning(f"Error converting column:{column_name} to {datatype.__name__}")
|
|
43
|
+
|
|
44
|
+
return df
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def testtime_hours_to_seconds_with_string_interpretation(
|
|
48
|
+
df: pd.DataFrame,
|
|
49
|
+
astype_string: bool,
|
|
50
|
+
) -> pd.DataFrame:
|
|
51
|
+
"""
|
|
52
|
+
Convert "Test_Time[s]" column from hours to seconds with string interpretation. (assumes hours are in "HH:MM:SS.MS" format)
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
data_frame : pandas.DataFrame
|
|
57
|
+
DataFrame to be modified
|
|
58
|
+
astype_string : bool, optional
|
|
59
|
+
Whether to convert the column to string type before applying the
|
|
60
|
+
conversion function. This is useful if the column contains both numeric
|
|
61
|
+
and string values.
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
pandas.DataFrame
|
|
66
|
+
Modified DataFrame
|
|
67
|
+
"""
|
|
68
|
+
try:
|
|
69
|
+
if df is None:
|
|
70
|
+
raise ValueError(f"{df} is None")
|
|
71
|
+
if not isinstance(astype_string, bool):
|
|
72
|
+
raise ValueError(f"{astype_string} is not a boolean")
|
|
73
|
+
if "Test_Time[s]" not in df.columns:
|
|
74
|
+
raise ValueError(f"Test_Time[s] is not in {df.columns}")
|
|
75
|
+
if astype_string:
|
|
76
|
+
df["Test_Time[s]"] = df["Test_Time[s]"].astype(str).apply(_time_to_seconds)
|
|
77
|
+
else:
|
|
78
|
+
df["Test_Time[s]"] = df["Test_Time[s]"].apply(_time_to_seconds)
|
|
79
|
+
except Exception:
|
|
80
|
+
logging.warning("Error fixing Test_Time[s]")
|
|
81
|
+
|
|
82
|
+
return df
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _time_to_seconds(time: str) -> float | None:
|
|
86
|
+
"""
|
|
87
|
+
Convert a time string from the format "HH:MM:SS" to a total number of seconds.
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
time : str
|
|
92
|
+
Time string to be converted, expected in the format "HH:MM:SS".
|
|
93
|
+
If the input is not in this format, attempts to convert it to a float.
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
float
|
|
98
|
+
Total time in seconds. If the input is None or cannot be split into
|
|
99
|
+
hours, minutes, and seconds, returns the input as a float.
|
|
100
|
+
|
|
101
|
+
Raises
|
|
102
|
+
------
|
|
103
|
+
ValueError
|
|
104
|
+
If the input time is None.
|
|
105
|
+
"""
|
|
106
|
+
try:
|
|
107
|
+
if time is None:
|
|
108
|
+
raise ValueError(f"{time} is None")
|
|
109
|
+
h, m, s = time.split(":")
|
|
110
|
+
return float(s) + int(m) * 60 + int(h) * 3600
|
|
111
|
+
except Exception:
|
|
112
|
+
if time is None:
|
|
113
|
+
return time
|
|
114
|
+
return float(time)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def apply_convert_to_float_if_possible(
|
|
118
|
+
df: pd.DataFrame,
|
|
119
|
+
column_name: str,
|
|
120
|
+
) -> pd.DataFrame:
|
|
121
|
+
"""
|
|
122
|
+
Apply a function to a DataFrame column that tries to convert its values to float if possible.
|
|
123
|
+
|
|
124
|
+
This function tries to convert the values to a float, and returns the value as a
|
|
125
|
+
float if successful. If not successful, the value is returned as is.
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
data_frame : pandas.DataFrame
|
|
130
|
+
DataFrame containing the column to be modified.
|
|
131
|
+
column_name : str
|
|
132
|
+
Name of the column in the DataFrame to be modified.
|
|
133
|
+
|
|
134
|
+
Returns
|
|
135
|
+
-------
|
|
136
|
+
pandas.DataFrame
|
|
137
|
+
Modified DataFrame with the column converted to float if possible.
|
|
138
|
+
"""
|
|
139
|
+
try:
|
|
140
|
+
if df is None:
|
|
141
|
+
raise ValueError("dataFrame is None")
|
|
142
|
+
if column_name is None:
|
|
143
|
+
raise ValueError("column_name is None")
|
|
144
|
+
if column_name not in df.columns:
|
|
145
|
+
raise ValueError(f"{column_name} is not in {df.columns}")
|
|
146
|
+
df[column_name] = df[column_name].apply(_convert_to_float_if_possible)
|
|
147
|
+
except Exception:
|
|
148
|
+
logging.warning(f"Error applying convert_to_float_if_possible for {column_name}")
|
|
149
|
+
|
|
150
|
+
return df
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _convert_to_float_if_possible(x) -> float:
|
|
154
|
+
"""
|
|
155
|
+
Try to convert a value to a float if possible.
|
|
156
|
+
|
|
157
|
+
This function takes a value, and tries to convert it to a float. If the
|
|
158
|
+
conversion is successful, the function returns the value as a float. If
|
|
159
|
+
not successful, the value is returned as is.
|
|
160
|
+
|
|
161
|
+
Parameters
|
|
162
|
+
----------
|
|
163
|
+
x : any
|
|
164
|
+
Value to be converted to a float if possible.
|
|
165
|
+
|
|
166
|
+
Returns
|
|
167
|
+
-------
|
|
168
|
+
any
|
|
169
|
+
Value converted to a float if possible, otherwise the original value.
|
|
170
|
+
|
|
171
|
+
"""
|
|
172
|
+
try:
|
|
173
|
+
return np.float64(x)
|
|
174
|
+
except (ValueError, TypeError):
|
|
175
|
+
return x
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def replace_empty_with_none_in_standard_columns(df: pd.DataFrame) -> pd.DataFrame:
|
|
179
|
+
"""
|
|
180
|
+
Replace empty strings with None in the columns specified in src.convert.STANDARD_COLUMNS.
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
data_frame : pandas.DataFrame
|
|
185
|
+
DataFrame to be modified
|
|
186
|
+
|
|
187
|
+
Returns
|
|
188
|
+
-------
|
|
189
|
+
pandas.DataFrame
|
|
190
|
+
Modified DataFrame
|
|
191
|
+
"""
|
|
192
|
+
from pydpeet.io.convert import STANDARD_COLUMNS
|
|
193
|
+
|
|
194
|
+
try:
|
|
195
|
+
if df is None:
|
|
196
|
+
raise ValueError("dataFrame is None")
|
|
197
|
+
if df.empty:
|
|
198
|
+
raise ValueError("dataframe is empty")
|
|
199
|
+
df[STANDARD_COLUMNS] = df[STANDARD_COLUMNS].replace("", None)
|
|
200
|
+
except Exception as e:
|
|
201
|
+
logging.warning(f"Error replacing empty with None. Reason: {e}")
|
|
202
|
+
|
|
203
|
+
return df
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def testtime_hours_to_seconds_direct(df: pd.DataFrame) -> pd.DataFrame:
|
|
207
|
+
"""
|
|
208
|
+
Convert "Test_Time[s]" column from hours to seconds.
|
|
209
|
+
|
|
210
|
+
Parameters
|
|
211
|
+
----------
|
|
212
|
+
data_frame : pandas.DataFrame
|
|
213
|
+
DataFrame to be modified
|
|
214
|
+
|
|
215
|
+
Returns
|
|
216
|
+
-------
|
|
217
|
+
pandas.DataFrame
|
|
218
|
+
Modified DataFrame
|
|
219
|
+
"""
|
|
220
|
+
try:
|
|
221
|
+
if df is None:
|
|
222
|
+
raise ValueError("dataFrame is None")
|
|
223
|
+
if "Test_Time[s]" not in df.columns:
|
|
224
|
+
raise ValueError("Test_Time[s] is not in dataFrame.columns")
|
|
225
|
+
df["Test_Time[s]"] = df["Test_Time[s]"].apply(_convert_to_hours_to_seconds_direct_if_possible)
|
|
226
|
+
except Exception as e:
|
|
227
|
+
logging.warning(f"Error fixing Test_Time[s] (converting hours to seconds). Reason: {e}")
|
|
228
|
+
|
|
229
|
+
return df
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _convert_to_hours_to_seconds_direct_if_possible(x) -> float:
|
|
233
|
+
# TODO: Docstring
|
|
234
|
+
try:
|
|
235
|
+
return np.float64(x) * 3600
|
|
236
|
+
except (ValueError, TypeError):
|
|
237
|
+
return x
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def round_testtime(df: pd.DataFrame) -> pd.DataFrame:
|
|
241
|
+
"""
|
|
242
|
+
Round the values in the "Test_Time[s]" column of the DataFrame to 5 decimal places.
|
|
243
|
+
|
|
244
|
+
Parameters
|
|
245
|
+
----------
|
|
246
|
+
data_frame : pandas.DataFrame
|
|
247
|
+
DataFrame containing the "Test_Time[s]" column to be rounded.
|
|
248
|
+
|
|
249
|
+
Returns
|
|
250
|
+
-------
|
|
251
|
+
pandas.DataFrame
|
|
252
|
+
Modified DataFrame with rounded "Test_Time[s]" values.
|
|
253
|
+
"""
|
|
254
|
+
try:
|
|
255
|
+
if df is None:
|
|
256
|
+
raise ValueError("dataFrame is None")
|
|
257
|
+
if df.empty:
|
|
258
|
+
raise ValueError("dataframe is empty")
|
|
259
|
+
if "Test_Time[s]" not in df.columns:
|
|
260
|
+
raise ValueError("Test_Time[s] is not in dataFrame.columns")
|
|
261
|
+
|
|
262
|
+
df["Test_Time[s]"] = round(df["Test_Time[s]"].astype(float), 5)
|
|
263
|
+
except Exception as e:
|
|
264
|
+
logging.warning(f"Error fixing Test_Time[s] (rounding). Reason: {e}")
|
|
265
|
+
|
|
266
|
+
return df
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def nan_to_none_in_column(
|
|
270
|
+
df: pd.DataFrame,
|
|
271
|
+
column_name: str,
|
|
272
|
+
) -> pd.DataFrame:
|
|
273
|
+
"""
|
|
274
|
+
Replace NaN values in a DataFrame column (column_name) with None.
|
|
275
|
+
|
|
276
|
+
Parameters
|
|
277
|
+
----------
|
|
278
|
+
dataFrame : pandas.DataFrame
|
|
279
|
+
DataFrame containing the column to be modified.
|
|
280
|
+
column_name : str
|
|
281
|
+
Name of the column in the DataFrame to be modified.
|
|
282
|
+
|
|
283
|
+
Returns
|
|
284
|
+
-------
|
|
285
|
+
pandas.DataFrame
|
|
286
|
+
Modified DataFrame with NaN values replaced with None.
|
|
287
|
+
"""
|
|
288
|
+
try:
|
|
289
|
+
if df is None:
|
|
290
|
+
raise ValueError("dataFrame is None")
|
|
291
|
+
if column_name is None:
|
|
292
|
+
raise ValueError("column_name is None")
|
|
293
|
+
if type(column_name) is not str:
|
|
294
|
+
raise ValueError("column_name is not a string")
|
|
295
|
+
if column_name not in df.columns:
|
|
296
|
+
raise ValueError(f"{column_name} is not in {df.columns}")
|
|
297
|
+
df[column_name] = df[column_name].replace({np.nan: None})
|
|
298
|
+
except Exception:
|
|
299
|
+
logging.warning(f"Error fixing {column_name} (replacing NaN with None)")
|
|
300
|
+
|
|
301
|
+
return df
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def move_strings_from_column_to_metadata(
|
|
305
|
+
df: pd.DataFrame,
|
|
306
|
+
column_name: str,
|
|
307
|
+
) -> pd.DataFrame:
|
|
308
|
+
"""
|
|
309
|
+
Move strings from a column into the "Meta_Data" column and replace them with None.
|
|
310
|
+
|
|
311
|
+
This function takes a DataFrame and a column name as input, and moves all strings in that column to the
|
|
312
|
+
"Meta_Data" column. The strings are joined together with a newline character and added to the existing
|
|
313
|
+
"Meta_Data" content. The original column is then replaced with None values.
|
|
314
|
+
|
|
315
|
+
Parameters
|
|
316
|
+
----------
|
|
317
|
+
data_frame : pandas.DataFrame
|
|
318
|
+
DataFrame containing the column to be modified.
|
|
319
|
+
column_name : str
|
|
320
|
+
Name of the column in the DataFrame to be modified.
|
|
321
|
+
|
|
322
|
+
Returns
|
|
323
|
+
-------
|
|
324
|
+
pandas.DataFrame
|
|
325
|
+
Modified DataFrame with strings moved to "Meta_Data" and replaced with None in the original column.
|
|
326
|
+
"""
|
|
327
|
+
concatenated_string = "\n"
|
|
328
|
+
try:
|
|
329
|
+
if df is None:
|
|
330
|
+
raise ValueError("dataFrame is None")
|
|
331
|
+
if not isinstance(column_name, str):
|
|
332
|
+
raise ValueError(f"column_name is not a string. Type is {type(column_name)}")
|
|
333
|
+
if column_name not in df.columns:
|
|
334
|
+
raise ValueError(f"{column_name} is not in {df.columns}")
|
|
335
|
+
if "Meta_Data" not in df.columns:
|
|
336
|
+
raise ValueError("Meta_Data Column doesn't exsist")
|
|
337
|
+
|
|
338
|
+
strings = df[column_name].apply(lambda x: x if isinstance(x, str) else None)
|
|
339
|
+
concatenated_string = concatenated_string.join(filter(None, strings))
|
|
340
|
+
|
|
341
|
+
df.loc[0, "Meta_Data"] = str(df.loc[0, "Meta_Data"]) + "\n\n" + concatenated_string
|
|
342
|
+
df[column_name] = df[column_name].apply(lambda x: None if isinstance(x, str) else x).astype(object)
|
|
343
|
+
df[column_name] = df[column_name].replace({np.nan: None})
|
|
344
|
+
except Exception:
|
|
345
|
+
logging.warning("Error adding Messages to Meta_Data")
|
|
346
|
+
|
|
347
|
+
return df
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def fix_time_format(
|
|
351
|
+
df: pd.DataFrame,
|
|
352
|
+
input_format: str = None,
|
|
353
|
+
) -> pd.DataFrame:
|
|
354
|
+
"""
|
|
355
|
+
Fix the format of the "Date_Time" column.
|
|
356
|
+
|
|
357
|
+
This function takes a DataFrame and an optional input format as input, and
|
|
358
|
+
attempts to convert the "Date_Time" column to a
|
|
359
|
+
datetime object using the given input format. If the input format is not
|
|
360
|
+
given, the function will try to infer the format from the data. The
|
|
361
|
+
resulting datetime object is then formatted as a string in the format
|
|
362
|
+
'%Y-%m-%d %H:%M:%S' and replaces the original column.
|
|
363
|
+
Fills empty parts with pandas.NaT.
|
|
364
|
+
|
|
365
|
+
Parameters
|
|
366
|
+
----------
|
|
367
|
+
data_frame : pandas.DataFrame
|
|
368
|
+
DataFrame containing the column to be modified.
|
|
369
|
+
input_format : str, optional
|
|
370
|
+
Format string to use when converting the column to a datetime object.
|
|
371
|
+
If not given, the function will try to infer the format from the data.
|
|
372
|
+
|
|
373
|
+
Returns
|
|
374
|
+
-------
|
|
375
|
+
pandas.DataFrame
|
|
376
|
+
Modified DataFrame with the "Date_Time" column
|
|
377
|
+
converted to the correct format.
|
|
378
|
+
"""
|
|
379
|
+
column_name = "Date_Time"
|
|
380
|
+
|
|
381
|
+
try:
|
|
382
|
+
if df is None:
|
|
383
|
+
raise ValueError("data_frame is None")
|
|
384
|
+
if not isinstance(input_format, str):
|
|
385
|
+
raise ValueError(f"input_format is not a string. Type is {type(column_name)}")
|
|
386
|
+
if column_name not in df.columns:
|
|
387
|
+
raise ValueError(f"{column_name} is not in {df.columns}")
|
|
388
|
+
if "Date_Time" not in df.columns:
|
|
389
|
+
raise ValueError("Date_Time Column doesn't exsist")
|
|
390
|
+
try:
|
|
391
|
+
df[column_name] = pd.to_datetime(df[column_name], format=input_format, errors="coerce")
|
|
392
|
+
except Exception:
|
|
393
|
+
raise ValueError("Error changing to datetime") from None
|
|
394
|
+
try:
|
|
395
|
+
df[column_name] = df[column_name].dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
396
|
+
except Exception:
|
|
397
|
+
raise ValueError("Error changing to correct order in Timeformat") from None
|
|
398
|
+
except Exception:
|
|
399
|
+
logging.warning("Error fixing timeformat Date_Time")
|
|
400
|
+
|
|
401
|
+
return df
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def absolute_time_timedate_typecast(df: pd.DataFrame) -> pd.DataFrame:
|
|
405
|
+
"""
|
|
406
|
+
Convert the "Date_Time" column in the DataFrame to a datetime object.
|
|
407
|
+
|
|
408
|
+
This function attempts to typecast the specified column in the DataFrame to a pandas datetime object.
|
|
409
|
+
|
|
410
|
+
Parameters
|
|
411
|
+
----------
|
|
412
|
+
data_frame : pandas.DataFrame
|
|
413
|
+
The DataFrame containing the column to be converted.
|
|
414
|
+
|
|
415
|
+
Returns
|
|
416
|
+
-------
|
|
417
|
+
pandas.DataFrame
|
|
418
|
+
The DataFrame with the "Date_Time" column converted to datetime objects.
|
|
419
|
+
"""
|
|
420
|
+
try:
|
|
421
|
+
if df is None:
|
|
422
|
+
raise ValueError("data_frame is None")
|
|
423
|
+
if "Date_Time" not in df.columns:
|
|
424
|
+
raise ValueError("Date_Time Column doesn't exsist")
|
|
425
|
+
df["Date_Time"] = pd.to_datetime(df["Date_Time"], errors="coerce")
|
|
426
|
+
except Exception:
|
|
427
|
+
logging.warning("Error typecasting Date_Time")
|
|
428
|
+
|
|
429
|
+
return df
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from importlib.util import (
|
|
3
|
+
module_from_spec,
|
|
4
|
+
spec_from_file_location,
|
|
5
|
+
)
|
|
6
|
+
from types import ModuleType
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def load_custom_module(
|
|
10
|
+
folder_path: str,
|
|
11
|
+
module_name: str,
|
|
12
|
+
) -> ModuleType:
|
|
13
|
+
"""
|
|
14
|
+
Loads a custom Python module from a specified folder.
|
|
15
|
+
|
|
16
|
+
Parameters:
|
|
17
|
+
folder_path (str): The path to the folder containing the module file.
|
|
18
|
+
module_name (str): The name of the module to load (without the .py extension).
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
module: The loaded Python module object.
|
|
22
|
+
|
|
23
|
+
Raises:
|
|
24
|
+
FileNotFoundError: If the module file does not exist in the specified folder.
|
|
25
|
+
"""
|
|
26
|
+
module_path = os.path.join(folder_path, f"{module_name}.py")
|
|
27
|
+
if not os.path.exists(module_path):
|
|
28
|
+
raise FileNotFoundError(f"Module {module_name}.py not found in the specified folder: {folder_path}")
|
|
29
|
+
spec = spec_from_file_location(module_name, module_path)
|
|
30
|
+
module = module_from_spec(spec)
|
|
31
|
+
spec.loader.exec_module(module)
|
|
32
|
+
|
|
33
|
+
return module
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import time
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def measure_time(func) -> Any:
|
|
7
|
+
"""
|
|
8
|
+
A decorator that measures the execution time of a function.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
func (Callable): The function whose execution time is to be measured.
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
Callable: A wrapped function that, when called, executes the original
|
|
15
|
+
function and prints the time taken to execute it.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def wrapper(*args, **kwargs) -> Any:
|
|
19
|
+
"""
|
|
20
|
+
A wrapped function that, when called, executes the original function and prints the time taken to execute it.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
*args (Any): The arguments to be passed to the original function.
|
|
24
|
+
**kwargs (Any): The keyword arguments to be passed to the original function.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Any: The result of the original function.
|
|
28
|
+
"""
|
|
29
|
+
start_time = time.perf_counter()
|
|
30
|
+
result = func(*args, **kwargs)
|
|
31
|
+
end_time = time.perf_counter()
|
|
32
|
+
logging.info(f"{func.__name__} executed in {end_time - start_time:.6f} seconds")
|
|
33
|
+
|
|
34
|
+
return result
|
|
35
|
+
|
|
36
|
+
return wrapper
|
pydpeet/io/write.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from pydpeet.io.configs.config import DataOutputFiletype
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# TODO:
|
|
10
|
+
# Adjust to accept dataframes or lists of dataframes
|
|
11
|
+
# or write dedicated wrapper for list inputs
|
|
12
|
+
def write(
|
|
13
|
+
data_input: pd.DataFrame,
|
|
14
|
+
output_path: str,
|
|
15
|
+
output_file_name: str,
|
|
16
|
+
data_output_filetype: DataOutputFiletype = DataOutputFiletype.parquet,
|
|
17
|
+
) -> None:
|
|
18
|
+
"""
|
|
19
|
+
Export the given DataFrame to the given output path.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
data_frame : pandas.DataFrame
|
|
24
|
+
DataFrame to be exported.
|
|
25
|
+
output_path : str
|
|
26
|
+
Path to the directory where the file will be saved. Must exist.
|
|
27
|
+
output_file_name : str
|
|
28
|
+
Name of the file to be saved.
|
|
29
|
+
data_output_filetype : DataOutputFiletype, optional
|
|
30
|
+
The file type to use when exporting the DataFrame. Defaults to
|
|
31
|
+
DataOutputFiletype.parquet.
|
|
32
|
+
|
|
33
|
+
Raises
|
|
34
|
+
------
|
|
35
|
+
ValueError
|
|
36
|
+
If data_frame is None, or if output_path or output_file_name are None.
|
|
37
|
+
TypeError
|
|
38
|
+
If data_frame is not a pandas.DataFrame, or if data_output_filetype is not
|
|
39
|
+
a DataOutputFiletype.
|
|
40
|
+
"""
|
|
41
|
+
if data_input is None:
|
|
42
|
+
raise ValueError("data_frame is None")
|
|
43
|
+
if not isinstance(data_input, pd.DataFrame):
|
|
44
|
+
raise TypeError(f"data_frame is not a pandas.DataFrame, but {type(data_input)}")
|
|
45
|
+
if output_path is None:
|
|
46
|
+
raise ValueError("output_path is None")
|
|
47
|
+
if not isinstance(output_path, str):
|
|
48
|
+
raise ValueError(f"output_path is not a string, but {type(output_path)}")
|
|
49
|
+
if output_file_name is None:
|
|
50
|
+
raise ValueError("output_file_name is None")
|
|
51
|
+
if not isinstance(output_file_name, str):
|
|
52
|
+
raise ValueError(f"output_file_name is not a string, but {type(output_file_name)}")
|
|
53
|
+
if data_output_filetype is None:
|
|
54
|
+
raise ValueError("data_output_filetype is None")
|
|
55
|
+
if not isinstance(data_output_filetype, DataOutputFiletype):
|
|
56
|
+
raise ValueError(f"data_output_filetype is not a DataOutputFiletype, but {type(data_output_filetype)}")
|
|
57
|
+
|
|
58
|
+
abs_path = os.path.abspath(output_path)
|
|
59
|
+
|
|
60
|
+
if not os.path.exists(abs_path):
|
|
61
|
+
os.makedirs(abs_path)
|
|
62
|
+
|
|
63
|
+
_do_export(data_input, os.path.join(abs_path, output_file_name), data_output_filetype)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _do_export(
|
|
67
|
+
df: pd.DataFrame,
|
|
68
|
+
output_path: str,
|
|
69
|
+
data_output_filetype: DataOutputFiletype,
|
|
70
|
+
) -> None:
|
|
71
|
+
"""
|
|
72
|
+
Export a DataFrame to a file in the specified format.
|
|
73
|
+
|
|
74
|
+
This function exports the given DataFrame to a file at the specified output
|
|
75
|
+
path in the format specified by data_output_filetype. The function supports
|
|
76
|
+
exporting to Parquet, CSV, and XLSX file formats.
|
|
77
|
+
|
|
78
|
+
Parameters
|
|
79
|
+
----------
|
|
80
|
+
data_frame : pandas.DataFrame
|
|
81
|
+
The DataFrame to be exported.
|
|
82
|
+
output_path : str
|
|
83
|
+
The path (excluding file extension) where the file will be saved.
|
|
84
|
+
data_output_filetype : DataOutputFiletype
|
|
85
|
+
The format in which to export the DataFrame. Can be one of
|
|
86
|
+
DataOutputFiletype.parquet, DataOutputFiletype.csv, or
|
|
87
|
+
DataOutputFiletype.xlsx.
|
|
88
|
+
"""
|
|
89
|
+
logging.info(f"exporting to {output_path}")
|
|
90
|
+
match data_output_filetype:
|
|
91
|
+
case DataOutputFiletype.parquet:
|
|
92
|
+
full_output_path = f"{output_path}_Data.parquet"
|
|
93
|
+
df.to_parquet(full_output_path, index=False, engine="pyarrow")
|
|
94
|
+
case DataOutputFiletype.csv:
|
|
95
|
+
full_output_path = f"{output_path}_Data.csv"
|
|
96
|
+
df.to_csv(full_output_path, index=False)
|
|
97
|
+
case DataOutputFiletype.xlsx:
|
|
98
|
+
full_output_path = f"{output_path}_Data.xlsx"
|
|
99
|
+
df.to_excel(full_output_path, index=False)
|