import collections


def macro_f1(targets, predictions):
  """Macro F1."""
  # True positive, target counts, predicted counts.
  counts_by_label = collections.defaultdict(lambda: [0, 0, 0])

  for target_label, predicted_label in zip(targets, predictions):
    counts_by_label[target_label][0] += int(target_label == predicted_label)
    counts_by_label[target_label][1] += 1
    counts_by_label[predicted_label][2] += 1

  def _safe_divide(x, y):
    return x / y if y != 0 else 0.0

  def _f1(tp, tc, pc):
    p = _safe_divide(tp, pc)
    r = _safe_divide(tp, tc)
    return _safe_divide(2 * p * r, p + r)

  def _average(x):
    return _safe_divide(sum(x), len(x))

  return {
      "macro_f1": _average([_f1(*v) for v in counts_by_label.values()]) * 100.0
  }