def evaluation_metrics(predicted, actual, bow=True):
    """
    Input:
        predicted, actual = lists of the predicted and actual tokens
        bow: if true use bag of words assumption
    Returns:
        precision, recall, F1, Levenshtein distance
    """
    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)
Input:
        predicted, actual = lists of the predicted and actual tokens
        bow: if true use bag of words assumption
    Returns:
        precision, recall, F1, Levenshtein distance