1 | def cal_f1score_dp(input_sentence, pred_sentence, gold_sentence): |
2 | """ |
3 | Calculate Precision and Recall for text normalization. |
4 | Using Dynamic Programming to handle the case of length's unfit. |
5 | |
6 | TP, TN, FP, FN |
7 | TP: Những từ cần chuẩn hóa và mô hình đã chuẩn hóa đúng |
8 | TN: Những từ không cần chuẩn hóa và mô hình giữ nguyên |
9 | FP: Những từ không cần chuẩn hóa và mô hình chuẩn hóa nó (chuẩn hóa dư) |
10 | FN: Những từ cần chuẩn hóa và mô hình chuẩn hóa sai (giữ nguyên nó hoặc chuẩn hóa sai) |
11 | |
12 | Parameters: |
13 | - input_sentence: Original sentence (string). |
14 | - pred_sentence: Predicted normalized sentence (string). |
15 | - gold_sentence: Ground truth normalized sentence (string). |
16 | |
17 | Returns: |
18 | - A dictionary containing Precision, Recall, F1 score. Round 2. |
19 | """ |
20 | import numpy as np |
21 | |
22 | |
23 | input_tokens = input_sentence.split() |
24 | pred_tokens = pred_sentence.split() |
25 | gold_tokens = gold_sentence.split() |
26 | |
27 | n, m, p = len(input_tokens), len(pred_tokens), len(gold_tokens) |
28 | |
29 | |
30 | dp = np.zeros((n + 1, m + 1, p + 1)) |
31 | tp, tn, fp, fn = 0, 0, 0, 0 |
32 | |
33 | |
34 | for i in range(n + 1): |
35 | for j in range(m + 1): |
36 | for k in range(p + 1): |
37 | if i == 0 and j == 0: |
38 | dp[i][j][k] = k |
39 | elif i == 0 and k == 0: |
40 | dp[i][j][k] = j |
41 | elif j == 0 and k == 0: |
42 | dp[i][j][k] = i |
43 | |
44 | |
45 | for i in range(1, n + 1): |
46 | for j in range(1, m + 1): |
47 | for k in range(1, p + 1): |
48 | if pred_tokens[j - 1] == gold_tokens[k - 1]: |
49 | dp[i][j][k] = dp[i - 1][j - 1][k - 1] |
50 | else: |
51 | dp[i][j][k] = min( |
52 | dp[i - 1][j - 1][k - 1] + 1, |
53 | dp[i - 1][j][k] + 1, |
54 | dp[i][j - 1][k] + 1, |
55 | dp[i][j][k - 1] + 1 |
56 | ) |
57 | |
58 | |
59 | i, j, k = n, m, p |
60 | while j > 0 or k > 0: |
61 | if j > 0 and k > 0 and pred_tokens[j - 1] == gold_tokens[k - 1]: |
62 | if pred_tokens[j - 1] in input_tokens: |
63 | tn += 1 |
64 | else: |
65 | tp += 1 |
66 | j -= 1 |
67 | k -= 1 |
68 | elif j > 0 and pred_tokens[j - 1] not in gold_tokens and pred_tokens[j - 1] not in input_tokens: |
69 | fp += 1 |
70 | j -= 1 |
71 | elif k > 0 and gold_tokens[k - 1] not in pred_tokens: |
72 | if gold_tokens[k - 1] not in input_tokens: |
73 | fn += 1 |
74 | k -= 1 |
75 | else: |
76 | j -= 1 if j > 0 else 0 |
77 | |
78 | |
79 | precision = tp / (tp + fp) if tp + fp > 0 else 0 |
80 | recall = tp / (tp + fn) if tp + fn > 0 else 0 |
81 | f1 = (2 * precision * recall) / (precision + recall) if precision + recall > 0 else 0 |
82 | |
83 | return { |
84 | "precision": round(precision, 2), |
85 | "recall": round(recall, 2), |
86 | "f1 score": round(f1, 2), |
87 | "TP": tp, |
88 | "TN": tn, |
89 | "FP": fp, |
90 | "FN": fn, |
91 | } |