code: def score_by_token(
      pred_tag_sequences,
      gold_tag_sequences,
      verbose=True,
      ignore_tags=None,
  ):
      """Score predicted tags at the token level.
  
      Args:
          pred_tags_sequences: a list of list of predicted tags for each word
          gold_tags_sequences: a list of list of gold tags for each word
          verbose: print log with results
          ignore_tags: a list or a string with a comma-separated list of tags to ignore
  
      Returns:
          Precision, recall and F1 scores, along with a confusion matrix
      """
      assert len(gold_tag_sequences) == len(
          pred_tag_sequences
      ), "Number of predicted tag sequences does not match gold sequences."
  
      ignore_tag_set = set()
      if ignore_tags:
          if isinstance(ignore_tags, str):
              ignore_tag_set.update(ignore_tags.split(","))
          else:
              ignore_tag_set.update(ignore_tags)
  
      def ignore_tag(tag):
          if tag == "O":
              return True
          if len(tag) > 2 and (tag[1] == "_" or tag[1] == "-"):
              tag = tag[2:]
          if tag in ignore_tag_set:
              return True
          return False
  
      correct_by_tag = Counter()
      guessed_by_tag = Counter()
      gold_by_tag = Counter()
      confusion = defaultdict(lambda: defaultdict(int))
  
      for gold_tags, pred_tags in zip(
          gold_tag_sequences, pred_tag_sequences
      ):
          assert len(gold_tags) == len(
              pred_tags
          ), "Number of predicted tags does not match gold."
          for g, p in zip(gold_tags, pred_tags):
              if ignore_tag(g):
                  g = "O"
              if ignore_tag(p):
                  p = "O"
              confusion[g][p] = confusion[g][p] + 1
              if g == "O" and p == "O":
                  continue
              elif g == "O" and p != "O":
                  guessed_by_tag[p] += 1
              elif g != "O" and p == "O":
                  gold_by_tag[g] += 1
              else:
                  guessed_by_tag[p] += 1
                  gold_by_tag[p] += 1
                  if g == p:
                      correct_by_tag[p] += 1
  
      prec_micro = 0.0
      if sum(guessed_by_tag.values()) > 0:
          prec_micro = (
              sum(correct_by_tag.values())
              * 1.0
              / sum(guessed_by_tag.values())
          )
      rec_micro = 0.0
      if sum(gold_by_tag.values()) > 0:
          rec_micro = (
              sum(correct_by_tag.values())
              * 1.0
              / sum(gold_by_tag.values())
          )
      f_micro = 0.0
      if prec_micro + rec_micro > 0:
          f_micro = (
              2.0 * prec_micro * rec_micro / (prec_micro + rec_micro)
          )
  
      if verbose:
          logger.info(
              "Score by token:\nPrec.\tRec.\tF1\n{:.2f}\t{:.2f}\t{:.2f}".format(
                  prec_micro * 100, rec_micro * 100, f_micro * 100
              )
          )
      return prec_micro, rec_micro, f_micro, confusion
  
imports: import sys
  import os
  import logging
  from collections import Counter, defaultdict
  from stanza.models.ner.utils import decode_from_bioes
label_desc: Use image node_id 2 for calling a global function with example usage: score_by_token(pred_tag_sequences, gold_tag_sequences, verbose, ignore_tags) and returns: prec_micro,  rec_micro,  f_micro,  confusion, False, True, True