-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_sent_eval_changes.py
More file actions
221 lines (186 loc) · 8.47 KB
/
Copy pathtest_sent_eval_changes.py
File metadata and controls
221 lines (186 loc) · 8.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
"""
测试句子级评估脚本的修改
"""
import re
# 复制需要测试的函数
SPAN_RE = re.compile(r"<(AI|HUMAN)>(.*?)</\1>", re.IGNORECASE | re.DOTALL)
def split_sentences(text):
"""
切分句子,处理多种边界情况:
1. 版本号:V3.70, 7.82
2. 小数:3.14, 1.5
3. 列表编号:1.xxx 2.xxx(在句子开头或逗号后)
4. 逗号连接的长句:中间的"."不切分
"""
if not text:
return []
text = str(text).replace("\r", "").replace("\n", "").strip()
if not text:
return []
sentences = []
start = 0
terminals = {"。", "!", "?", "!", "?", "."}
for idx, ch in enumerate(text):
if ch not in terminals:
continue
# 特殊处理英文句号"."
if ch == "." and idx > 0 and idx + 1 < len(text):
prev_char = text[idx - 1]
next_char = text[idx + 1]
# 1. 小数或版本号:前后都是数字(3.14)或前是字母数字后是数字(V3.70)
if (prev_char.isdigit() and next_char.isdigit()) or \
(prev_char.isalnum() and next_char.isdigit()):
continue
# 2. 列表编号:如果从上一个切分点到当前位置只有"数字.",说明是列表编号
# 例如:"xxx。1.yyy" 或开头的"1.yyy"
segment_before = text[start:idx+1].strip()
# 检查是否为纯数字+.的格式(列表编号)
if segment_before and all(c.isdigit() or c == '.' for c in segment_before) and \
prev_char.isdigit() and len(segment_before) <= 3:
# 这是列表编号,不切分
continue
# 3. 逗号连接的长句:如果"."后面不是空格、大写字母或典型的句子开头,可能不是句子结尾
# 检查下一个字符是否是中文且前面的文本较短(很可能是名称或短语的一部分)
if next_char != ' ' and not next_char.isupper() and '\u4e00' <= next_char <= '\u9fff':
# 如果"."前面的文本很短(<15字符)且包含逗号,可能是短语的一部分
segment_check = text[max(0, idx-15):idx+1]
if (',' in segment_check or ',' in segment_check) and len(segment_check) < 20:
continue
seg = text[start: idx + 1].strip()
if seg:
sentences.append(seg)
start = idx + 1
tail = text[start:].strip()
if tail:
sentences.append(tail)
return sentences
def normalize_tagged_output(text):
if text is None:
return ""
s = str(text).strip()
s = re.sub(r"<\s*ai\s*>", "<AI>", s, flags=re.IGNORECASE)
s = re.sub(r"<\s*/\s*ai\s*>", "</AI>", s, flags=re.IGNORECASE)
s = re.sub(r"<\s*human\s*>", "<HUMAN>", s, flags=re.IGNORECASE)
s = re.sub(r"<\s*/\s*human\s*>", "</HUMAN>", s, flags=re.IGNORECASE)
return s
def extract_sentence_labels_from_tagged(tagged_text):
"""
从带标签的文本中提取句子-标签对。
如果一个标签内包含多个句子,则每个句子都分配相同的标签。
"""
tagged_text = normalize_tagged_output(tagged_text)
pairs = []
for m in SPAN_RE.finditer(tagged_text):
label = m.group(1).upper()
span_text = m.group(2).strip()
if span_text:
# 将span_text切分成句子,每个句子都分配相同的标签
sentences = split_sentences(span_text)
for sent in sentences:
if sent.strip():
pairs.append((sent.strip(), label))
return pairs
# 测试1:版本号不被切分
print("=" * 70)
print("测试1:版本号不被切分")
print("=" * 70)
text1 = "这是V3.70版本。下一个是V4.0。"
result1 = split_sentences(text1)
print(f"输入: {text1}")
print(f"输出: {result1}")
print(f"预期: ['这是V3.70版本。', '下一个是V4.0。']")
print(f"通过: {result1 == ['这是V3.70版本。', '下一个是V4.0。']}")
print()
# 测试2:小数点不被切分
print("=" * 70)
print("测试2:小数点不被切分")
print("=" * 70)
text2 = "价格是3.14元。总共5.5个。"
result2 = split_sentences(text2)
print(f"输入: {text2}")
print(f"输出: {result2}")
print(f"预期: ['价格是3.14元。', '总共5.5个。']")
print(f"通过: {result2 == ['价格是3.14元。', '总共5.5个。']}")
print()
# 测试3:一个标签包含两句话
print("=" * 70)
print("测试3:一个标签包含两句话")
print("=" * 70)
tagged3 = "<AI>英雄方面还有WD的毒镖、刀阵以及DH能够对有魔法护盾的空军进行攻击(像龙鹰,出冰龙就无法吸引了)。POM的强击光环能够增加远程攻击力,并且以上所述的所有兵种(除了角鹰)的攻击力都得到了加强。</AI>"
result3 = extract_sentence_labels_from_tagged(tagged3)
print(f"输入: {tagged3}")
print(f"输出: {result3}")
print(f"句子数: {len(result3)}")
print(f"每个句子的标签:")
for sent, label in result3:
print(f" {label}: {sent}")
print(f"预期: 2个句子,都标记为AI")
print(f"通过: {len(result3) == 2 and all(label == 'AI' for _, label in result3)}")
print()
# 测试4:评估逻辑
print("=" * 70)
print("测试4:评估逻辑(位置不同但标签相同算对)")
print("=" * 70)
gold_tagged = "<AI>英雄方面还有WD的毒镖、刀阵以及DH能够对有魔法护盾的空军进行攻击(像龙鹰,出冰龙就无法吸引了)。POM的强击光环能够增加远程攻击力,并且以上所述的所有兵种(除了角鹰)的攻击力都得到了加强。</AI>"
pred_tagged = "<AI>英雄方面还有WD的毒镖、刀阵以及DH能够对有魔法护盾的空军进行攻击(像龙鹰,出冰龙就无法吸引了)。</AI><AI>POM的强击光环能够增加远程攻击力,并且以上所述的所有兵种(除了角鹰)的攻击力都得到了加强。</AI>"
gold_pairs = extract_sentence_labels_from_tagged(gold_tagged)
pred_pairs = extract_sentence_labels_from_tagged(pred_tagged)
print(f"Gold pairs: {gold_pairs}")
print(f"Pred pairs: {pred_pairs}")
# 模拟评估逻辑
gold_dict = {}
for sent, label in gold_pairs:
if sent not in gold_dict:
gold_dict[sent] = label
pred_dict = {}
for sent, label in pred_pairs:
if sent not in pred_dict:
pred_dict[sent] = label
correct = 0
total = len(gold_dict)
for sent, true_label in gold_dict.items():
pred_label = pred_dict.get(sent)
if pred_label == true_label:
correct += 1
print(f"✓ 匹配: {sent[:30]}... -> {true_label}")
else:
print(f"✗ 不匹配: {sent[:30]}... -> Gold:{true_label}, Pred:{pred_label}")
print(f"\n准确率: {correct}/{total} = {correct/total if total > 0 else 0:.2%}")
print(f"预期: 2/2 = 100% (虽然切分位置不同,但两句话的标签都正确)")
print(f"通过: {correct == total}")
print()
# ==================== 新增测试 ====================
print("=" * 70)
print("测试5: 列表编号处理")
print("=" * 70)
# 用户提供的失败案例
text_list = "1.伤情稳定后可以申请伤残鉴定,一般是3到6个月。2.按照事故责任比例承担赔偿责任。"
result_list = split_sentences(text_list)
print(f"输入: {text_list}")
print(f"切分结果: {result_list}")
print(f"句子数量: {len(result_list)}")
print(f"期望: 2个句子(不应该在数字后的'.'处切分)")
print(f"通过: {len(result_list) == 2 and result_list[0] == '1.伤情稳定后可以申请伤残鉴定,一般是3到6个月。'}")
print()
# 测试更多列表情况
text_list2 = "操作步骤:1.打开设置。2.选择隐私。3.点击恢复。"
result_list2 = split_sentences(text_list2)
print(f"输入: {text_list2}")
print(f"切分结果: {result_list2}")
print(f"句子数量: {len(result_list2)}")
print(f"期望: 4个句子('操作步骤:' + 3个列表项)")
print()
print("=" * 70)
print("测试6: 逗号连接长句(.不总是句子结尾)")
print("=" * 70)
text_comma = "新世界商城一楼有个专卖柜台.但是因为店主怕压货,所以现货不多,你要从他的购车指南中选好,定货.老板才给你进货.稍麻烦了些,但质量有保证,价格比银座要便宜多了,品种也全,是好孩子的."
result_comma = split_sentences(text_comma)
print(f"输入: {text_comma}")
print(f"切分结果: {result_comma}")
print(f"句子数量: {len(result_comma)}")
print(f"期望: <=2个句子(不应该过度切分)")
print(f"通过: {len(result_comma) <= 2}")
print()
print("=" * 70)
print("所有测试完成!")
print("=" * 70)