function thres = f_cal_thres_best_f1(predicted_vector, ground_truth_vector)
% adaptive thresholding

stat_table = zeros(length(predicted_vector) - 1, 8); 
predicted_vector_sorted = sort(predicted_vector);

for k = 1 : length(predicted_vector) - 1
	% tp
	stat_table(k, 1) = nnz((predicted_vector > predicted_vector_sorted(k + 1)) .* (ground_truth_vector == 1));
	% fp
	stat_table(k, 2) = nnz((predicted_vector > predicted_vector_sorted(k + 1)) .* (ground_truth_vector == 0));
	% tn
	stat_table(k, 3) = nnz((predicted_vector < predicted_vector_sorted(k + 1)) .* (ground_truth_vector == 0));
	% fn
	stat_table(k, 4) = nnz((predicted_vector < predicted_vector_sorted(k + 1)) .* (ground_truth_vector == 1));
end

% precision = tp / (tp + fp)
stat_table(:, 5) = stat_table(:, 1) ./ (stat_table(:, 1) + stat_table(:, 2));
% recall = tp / (tp + fn)
stat_table(:, 6) = stat_table(:, 1) ./ (stat_table(:, 1) + stat_table(:, 4));
% accuracy
stat_table(:, 7) = (stat_table(:, 1) + stat_table(:, 3)) ./ sum(stat_table, 2);
% f1 = 2 * precision * recall / (precision + recall)
stat_table(:, 8) = 2 * stat_table(:, 5) .* stat_table(:, 6) ./ (stat_table(:, 5) + stat_table(:, 6));

[m, thres_idx] = max(stat_table(:, 5)); % best micro precision
if thres_idx > 1
	thres = predicted_vector_sorted(thres_idx) - (predicted_vector_sorted(thres_idx) - predicted_vector_sorted(thres_idx - 1)) / 2;
else
	thres = predicted_vector_sorted(thres_idx);
end
end