I am new to programming and I am trying to develop a machine learning approach for image segmentation (https://en.wikipedia.org/wiki/Image_segmentation) and here I want to evaluate the predicted (output) segmentation. In order to do this, I am using multiple (common) metrics (dice score, jacquard index, surface distance Hausdorff distance, diameter error and volume error).
The code works, but it really looks bad! I heard that one of the best practices is to avoid repetition in the code. For my piece I have to create multiple arrays which will all have different usage, but generating a lot of repetitions, and I am sure there might be better way to get better performance for this piece of code.
Do you have an idea of how to optimize this for speed and readability?
The details of the code:
folder = glab() : gets the name of the different folders containing the arrays that I want to open (
glab() = glob() with natural sorting)
ground_truth : loads the predicted segmentation and ground_truth to be compared
scores() : calculates the different metrics (dice score, jacquard index, sensibility and specificity) between the ground truth and prediction
surfd() : calculates the surface distance between ground truth and prediction
diam_vol : calculates the diameter/volume and error between ground truth and prediction
Since I am evaluating multiple cases I want to know the
mean() metrics to assess my model that's why I call for
np.mean() for all the values at the end.
def metrics(savedir): """3D metrics for segmentation evaluation: dice score : https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient jacquard index : https://en.wikipedia.org/wiki/Jaccard_index sensibility & specificity : https://en.wikipedia.org/wiki/Sensitivity_and_specificity diameter and volume error Surface distance : https://www.cs.ox.ac.uk/files/7732/CS-RR-15-08.pdf Hausdorff distance : https://en.wikipedia.org/wiki/Hausdorff_distance """ folder = glab(savedir+"/OutputData/*/") # array initialization np_dice = np.zeros([len(folder)]) np_jacq = np.zeros([len(folder)]) np_sens = np.zeros([len(folder)]) np_spec = np.zeros([len(folder)]) np_surf = np.zeros([len(folder)]) np_haus = np.zeros([len(folder)]) np_diam_GT = np.zeros([len(folder)]) np_diam_pred = np.zeros([len(folder)]) np_diam_err = np.zeros([len(folder)]) np_vol_GT = np.zeros([len(folder)]) np_vol_pred = np.zeros([len(folder)]) np_vol_err = np.zeros([len(folder)]) for number, folder_name in enumerate(folder): prediction = np.load(folder_name+"prediction.npy") ground_truth = np.load(folder_name+"test_label.npy") scores = scoring(ground_truth, prediction) surface_distance = surfd(prediction, ground_truth, [0.625, 0.625, 0.625], 1) diam_vol = diam(prediction, ground_truth) np_dice[number] = scores np_jacq[number] = scores np_sens[number] = scores np_spec[number] = scores np_surf[number] = surface_distance.mean() np_haus[number] = surface_distance.max() np_diam_GT[number] = diam_vol np_diam_pred[number] = diam_vol np_diam_err[number] = diam_vol np_vol_GT[number] = diam_vol np_vol_pred[number] = diam_vol np_vol_err[number] = diam_vol mean_dice = np.mean(np_dice) mean_jacq = np.mean(np_jacq) mean_sens = np.mean(np_sens) mean_spec = np.mean(np_spec) mean_surf = np.mean(np_surf) mean_haus = np.mean(np_haus) mean_diam_GT = np.mean(np_diam_GT) mean_diam_pred = np.mean(np_diam_pred) mean_diam_err = np.mean(np_diam_err) mean_vol_GT = np.mean(np_vol_GT) mean_vol_pred = np.mean(np_vol_pred) mean_vol_err = np.mean(np_vol_err) return ([mean_dice, mean_jacq, mean_sens, mean_spec, mean_surf, mean_haus, mean_diam_GT, mean_diam_pred, mean_diam_err, mean_vol_GT, mean_vol_pred, mean_vol_err])