code: def evaluation_metrics(predicted, actual, bow=True):
      
      if bow:
          p = set(predicted)
          a = set(actual)
  
          true_positive = 0
          for token in p:
              if token in a:
                  true_positive += 1
      else:
          # shove actual into a hash, count up the unique occurances of each token
          # iterate through predicted, check which occur in actual
          from collections import defaultdict
          act = defaultdict(lambda: 0)
          for token in actual:
              act[token] += 1
  
          true_positive = 0
          for token in predicted:
              if act[token] > 0:
                  true_positive += 1
                  act[token] -= 1
  
          # for shared logic below
          p = predicted
          a = actual
  
      try:
          precision = true_positive / len(p)
      except ZeroDivisionError:
          precision = 0.0
      try:
          recall = true_positive / len(a)
      except ZeroDivisionError:
          recall = 0.0
      try:
          f1 = 2.0 * (precision * recall) / (precision + recall)
      except ZeroDivisionError:
          f1 = 0.0
  
      # return (precision, recall, f1, dameraulevenshtein(predicted, actual))
      return (precision, recall, f1)
docs: Input:
          predicted, actual = lists of the predicted and actual tokens
          bow: if true use bag of words assumption
      Returns:
          precision, recall, F1, Levenshtein distance