Skip to content

Commit 6c318cd

Browse files
committed
Bug fixes
1 parent b619aea commit 6c318cd

File tree

13 files changed

+4191
-381
lines changed

13 files changed

+4191
-381
lines changed

ads/dataset/label_encoder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def fit(self, X: "pandas.DataFrame"):
5252
5353
"""
5454
for column in X.columns:
55-
if X[column].dtype.name in ["object", "category"]:
55+
if X[column].dtype.name in ["object", "category", "bool"]:
5656
X[column] = X[column].astype(str)
5757
self.label_encoders[column] = LabelEncoder()
5858
self.label_encoders[column].fit(X[column])

ads/opctl/operator/lowcode/forecast/model/arima.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def __init__(self, config: ForecastOperatorConfig, datasets: ForecastDatasets):
2929
self.local_explanation = {}
3030
self.formatted_global_explanation = None
3131
self.formatted_local_explanation = None
32+
self.constant_cols = {}
3233

3334
def set_kwargs(self):
3435
# Extract the Confidence Interval Width and convert to arima's equivalent - alpha
@@ -64,6 +65,10 @@ def _train_model(self, i, s_id, df, model_kwargs):
6465
try:
6566
target = self.original_target_column
6667
self.forecast_output.init_series_output(series_id=s_id, data_at_series=df)
68+
# If trend is constant, remove constant columns
69+
if 'trend' not in model_kwargs or model_kwargs['trend'] == 'c':
70+
self.constant_cols[s_id] = df.columns[df.nunique() == 1]
71+
df = df.drop(columns=self.constant_cols[s_id])
6772

6873
# format the dataframe for this target. Dropping NA on target[df] will remove all future data
6974
data = self.preprocess(df, s_id)
@@ -74,7 +79,7 @@ def _train_model(self, i, s_id, df, model_kwargs):
7479
X_in = data_i.drop(target, axis=1) if len(data_i.columns) > 1 else None
7580
X_pred = self.get_horizon(data).drop(target, axis=1)
7681

77-
if self.loaded_models is not None:
82+
if self.loaded_models is not None and s_id in self.loaded_models:
7883
model = self.loaded_models[s_id]
7984
else:
8085
# Build and fit model
@@ -143,17 +148,18 @@ def _build_model(self) -> pd.DataFrame:
143148
def _generate_report(self):
144149
"""The method that needs to be implemented on the particular model level."""
145150
import datapane as dp
146-
147-
sec5_text = dp.Text(f"## ARIMA Model Parameters")
148-
blocks = [
149-
dp.HTML(
150-
m.summary().as_html(),
151-
label=s_id,
152-
)
153-
for i, (s_id, m) in enumerate(self.models.items())
154-
]
155-
sec5 = dp.Select(blocks=blocks) if len(blocks) > 1 else blocks[0]
156-
all_sections = [sec5_text, sec5]
151+
all_sections = []
152+
if len(self.models) > 0:
153+
sec5_text = dp.Text(f"## ARIMA Model Parameters")
154+
blocks = [
155+
dp.HTML(
156+
m.summary().as_html(),
157+
label=s_id,
158+
)
159+
for i, (s_id, m) in enumerate(self.models.items())
160+
]
161+
sec5 = dp.Select(blocks=blocks) if len(blocks) > 1 else blocks[0]
162+
all_sections = [sec5_text, sec5]
157163

158164
if self.spec.generate_explanations:
159165
try:

ads/opctl/operator/lowcode/forecast/model/automlx.py

Lines changed: 69 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def _build_model(self) -> pd.DataFrame:
107107

108108
logger.debug(f"Time Index Monotonic: {data_i.index.is_monotonic}")
109109

110-
if self.loaded_models is not None:
110+
if self.loaded_models is not None and s_id in self.loaded_models:
111111
model = self.loaded_models[s_id]
112112
else:
113113
model = automl.Pipeline(
@@ -208,82 +208,85 @@ def _generate_report(self):
208208
)
209209
selected_models = dict()
210210
models = self.models
211-
for i, (s_id, df) in enumerate(self.full_data_dict.items()):
212-
selected_models[s_id] = {
213-
"series_id": s_id,
214-
"selected_model": models[s_id].selected_model_,
215-
"model_params": models[s_id].selected_model_params_,
216-
}
217-
selected_models_df = pd.DataFrame(
218-
selected_models.items(), columns=["series_id", "best_selected_model"]
219-
)
220-
selected_df = selected_models_df["best_selected_model"].apply(pd.Series)
221-
selected_models_section = dp.Blocks(
222-
"### Best Selected Model", dp.DataTable(selected_df)
223-
)
211+
all_sections = []
212+
213+
if len(self.models) > 0:
214+
for i, (s_id, m) in enumerate(models.items()):
215+
selected_models[s_id] = {
216+
"series_id": s_id,
217+
"selected_model": m.selected_model_,
218+
"model_params": m.selected_model_params_,
219+
}
220+
selected_models_df = pd.DataFrame(
221+
selected_models.items(), columns=["series_id", "best_selected_model"]
222+
)
223+
selected_df = selected_models_df["best_selected_model"].apply(pd.Series)
224+
selected_models_section = dp.Blocks(
225+
"### Best Selected Model", dp.DataTable(selected_df)
226+
)
224227

225-
all_sections = [selected_models_text, selected_models_section]
228+
all_sections = [selected_models_text, selected_models_section]
226229

227230
if self.spec.generate_explanations:
228-
# try:
229-
# If the key is present, call the "explain_model" method
230-
self.explain_model()
231-
232-
# Create a markdown text block for the global explanation section
233-
global_explanation_text = dp.Text(
234-
f"## Global Explanation of Models \n "
235-
"The following tables provide the feature attribution for the global explainability."
236-
)
237-
238-
# Convert the global explanation data to a DataFrame
239-
global_explanation_df = pd.DataFrame(self.global_explanation)
231+
try:
232+
# If the key is present, call the "explain_model" method
233+
self.explain_model()
240234

241-
self.formatted_global_explanation = (
242-
global_explanation_df / global_explanation_df.sum(axis=0) * 100
243-
)
244-
self.formatted_global_explanation = (
245-
self.formatted_global_explanation.rename(
246-
{self.spec.datetime_column.name: ForecastOutputColumns.DATE}, axis=1
235+
# Create a markdown text block for the global explanation section
236+
global_explanation_text = dp.Text(
237+
f"## Global Explanation of Models \n "
238+
"The following tables provide the feature attribution for the global explainability."
247239
)
248-
)
249240

250-
# Create a markdown section for the global explainability
251-
global_explanation_section = dp.Blocks(
252-
"### Global Explainability ",
253-
dp.DataTable(self.formatted_global_explanation),
254-
)
241+
# Convert the global explanation data to a DataFrame
242+
global_explanation_df = pd.DataFrame(self.global_explanation)
255243

256-
aggregate_local_explanations = pd.DataFrame()
257-
for s_id, local_ex_df in self.local_explanation.items():
258-
local_ex_df_copy = local_ex_df.copy()
259-
local_ex_df_copy["Series"] = s_id
260-
aggregate_local_explanations = pd.concat(
261-
[aggregate_local_explanations, local_ex_df_copy], axis=0
244+
self.formatted_global_explanation = (
245+
global_explanation_df / global_explanation_df.sum(axis=0) * 100
246+
)
247+
self.formatted_global_explanation = (
248+
self.formatted_global_explanation.rename(
249+
{self.spec.datetime_column.name: ForecastOutputColumns.DATE}, axis=1
250+
)
262251
)
263-
self.formatted_local_explanation = aggregate_local_explanations
264252

265-
local_explanation_text = dp.Text(f"## Local Explanation of Models \n ")
266-
blocks = [
267-
dp.DataTable(
268-
local_ex_df.div(local_ex_df.abs().sum(axis=1), axis=0) * 100,
269-
label=s_id,
253+
# Create a markdown section for the global explainability
254+
global_explanation_section = dp.Blocks(
255+
"### Global Explainability ",
256+
dp.DataTable(self.formatted_global_explanation),
270257
)
271-
for s_id, local_ex_df in self.local_explanation.items()
272-
]
273-
local_explanation_section = (
274-
dp.Select(blocks=blocks) if len(blocks) > 1 else blocks[0]
275-
)
276258

277-
# Append the global explanation text and section to the "all_sections" list
278-
all_sections = all_sections + [
279-
global_explanation_text,
280-
global_explanation_section,
281-
local_explanation_text,
282-
local_explanation_section,
283-
]
284-
# except Exception as e:
285-
# logger.warn(f"Failed to generate Explanations with error: {e}.")
286-
# logger.debug(f"Full Traceback: {traceback.format_exc()}")
259+
aggregate_local_explanations = pd.DataFrame()
260+
for s_id, local_ex_df in self.local_explanation.items():
261+
local_ex_df_copy = local_ex_df.copy()
262+
local_ex_df_copy["Series"] = s_id
263+
aggregate_local_explanations = pd.concat(
264+
[aggregate_local_explanations, local_ex_df_copy], axis=0
265+
)
266+
self.formatted_local_explanation = aggregate_local_explanations
267+
268+
local_explanation_text = dp.Text(f"## Local Explanation of Models \n ")
269+
blocks = [
270+
dp.DataTable(
271+
local_ex_df.div(local_ex_df.abs().sum(axis=1), axis=0) * 100,
272+
label=s_id,
273+
)
274+
for s_id, local_ex_df in self.local_explanation.items()
275+
]
276+
local_explanation_section = (
277+
dp.Select(blocks=blocks) if len(blocks) > 1 else blocks[0]
278+
)
279+
280+
# Append the global explanation text and section to the "all_sections" list
281+
all_sections = all_sections + [
282+
global_explanation_text,
283+
global_explanation_section,
284+
local_explanation_text,
285+
local_explanation_section,
286+
]
287+
except Exception as e:
288+
logger.warn(f"Failed to generate Explanations with error: {e}.")
289+
logger.debug(f"Full Traceback: {traceback.format_exc()}")
287290

288291
model_description = dp.Text(
289292
"The AutoMLx model automatically preprocesses, selects and engineers "

0 commit comments

Comments
 (0)