I'm trying to create a custom loss function in keras that takes grouped MAE and then averages it.
I have a training and a validation set (obtained by randomly splitting the training data): (X_train, y_train), (X_val, y_val)
X_train and X_val contain around 80 numeric features, and 2 one-hot encoded features from a categorical variable with 3 categories, say "a", "b", and "c".
y_train and y_val contain two numeric outputs.
I'm trying to create a neural network model with a custom loss function that instead of taking overall MAE, takes MAE by groups and then averages it.
My current attempt at loss function looks like:
def avg_mae(grouping_col_train, grouping_col_val):
def custom_loss(y_true, y_pred):
grouping_col = grouping_col_val
if len(y_true) == len(grouping_col_train):
grouping_col = grouping_col_train
df = pd.DataFrame({
"geid": grouping_col,
"y_true": y_true,
"y_pred": y_pred
})
return np.mean(df.groupby("geid").apply(lambda x: mean_absolute_error(x["y_true"], x["y_pred"])))
return custom_loss
The reason this does not work is because I'm taking batches during training:
model.fit(X_train,
y_train,
epochs=500,
batch_size=2**16,
validation_data=(X_val, y_val),
callbacks=[callback],
verbose=1)
How do I pass the grouping column in the loss function for the batches? Also how to group average in the validation data as well?
Here's some code and output to explain the difference between overall MAE and grouped average MAE:
df = pd.DataFrame({
"y_true": np.random.randn(20000),
"y_pred": np.random.randn(20000),
"grouping_col": ["a"] * 8000 + ["b"] * 1000 + ["c"] * 11000
})
overall_mae = mean_absolute_error(df["y_true"], df["y_pred"])
print("overall_mae:", overall_mae)
grouped_mae = df.groupby(["grouping_col"]).apply(lambda x: mean_absolute_error(x["y_true"], x["y_pred"]))
print("\ngrouped_mae:")
print(grouped_mae)
avg_grouped_mae = np.mean(grouped_mae)
print("\navg_grouped_mae:", avg_grouped_mae)
Output:
overall_mae: 1.1325261117842
grouped_mae:
grouping_col
a 1.141619
b 1.069323
c 1.131659
dtype: float64
avg_grouped_mae: 1.1142004357897866