訓練資料去重:近似重複比完全重複更麻煩
完全相同的樣本好抓,改了兩個字的近似重複才是讓評測分數虛高的元凶。
資料集裡的重複會造成兩個問題:訓練時過度強調某些樣本,以及訓練與測試集之間的洩漏,讓分數看起來比實際好。
兩層去重
- 精確去重:雜湊比對,快且無爭議,先做這層。
- 近似去重:MinHash 加 LSH,找出改動少量文字的樣本。
from datasketch import MinHash, MinHashLSH
def sig(text, num_perm=128):
m = MinHash(num_perm=num_perm)
for i in range(len(text) - 4): # 中文用 5-gram
m.update(text[i:i+5].encode('utf-8'))
return m
lsh, keep = MinHashLSH(threshold=0.8, num_perm=128), []
for i, t in enumerate(texts):
s = sig(t)
if lsh.query(s):
continue # 與既有樣本高度相似
lsh.insert(str(i), s)
keep.append(i)門檻怎麼定
0.8 是常見起點。太高會漏掉真正的重複,太低會誤刪合法的相似樣本(例如同一種格式的不同資料)。務必人工抽看一批被刪掉的樣本,確認刪對了。
跨集合去重最重要
訓練集內部的重複只是效率問題;訓練集與測試集之間的重複是評測失效。切分之後一定要再做一次跨集合比對。
# 切分後檢查洩漏
leak = [t for t in test_set if lsh_train.query(sig(t))]
print(f'測試集有 {len(leak)}/{len(test_set)} 筆與訓練集近似重複')記錄去重前後的數量與被刪樣本的抽樣清單。資料集的每一次處理都要留痕,否則日後無法解釋分數變化。