zlib圧縮を使用して、長さの異なる低品質のテキストを除外するアプローチの適応

最近、記事のSberbankに必要なのは、低品質のテキスト(技術的なジャンクやテンプレートスパム)を除外するための珍しいアプローチを生成することです。





このアプローチをもう1つのヒューリスティックで補足しました。つまり、zlibを使用してテキストを圧縮し、最も強く圧縮されたテキストと最も弱く圧縮されたテキストを破棄してから、分類を適用しました。通常のテキストに対して経験的に選択された圧縮範囲×1.2〜×8(1.2未満-ランダムな文字と技術的なジャンク、8を超える-テンプレートスパム)。 





このアプローチは確かに興味深く、採用する価値があります。しかし、高品質のテキストのzlib圧縮率は、圧縮されるテキストの長さに非線形に依存しませんか?確認しよう。





長さが50〜280文字の範囲の文のテキストコーパスを見てみましょう。





import zlib
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.optimize import curve_fit

with open('/content/test.txt', 'r', encoding='utf-8') as f:
  text = f.read()
sntc = text.split('\n')

l_sntc = []  #  
k_zlib = []  #     

for s in sntc:
  l_sntc.append(len(s))
  k_zlib.append(len(s) / len(zlib.compress(s.encode(), -1)))
      
      



高品質の文の長さが圧縮率にどのように影響するかを見てみましょう。

このため:





1.最も頻度の高い文の長さの範囲(25〜75パーセンタイル)を考えてみましょう。私たちの場合、これらは92から175文字の長さです。





mp_1 = np.percentile(np.array(l_sntc), [25, 75])
print(': ' + str(mp_1))
      
      



2. . 25 (25 + w)   75 (75 - w) (   ), w - ( 2.5 ).





  • :





w = 2.5  #   
mp_2 = np.percentile(np.array(l_sntc), [25 + w, 75 - w])
dl = int(min(mp_2[0] - mp_1[0], mp_1[1] - mp_2[1]))
print('      : ' + str(dl))
      
      



3 .





  • +- 3 :





#     
id_sntc = range(len(sntc))  #   
x = zip(l_sntc, id_sntc)
xs = sorted(x, key = lambda tup: tup[0])
l_sntc_s = [x[0] for x in xs]
id_snt_s = [x[1] for x in xs]

gr = 0  #  
k_gr = [[]]  #      
l_gr = [[]]  #     
sl0 = l_sntc_s[l_sntc_s.index(mp_1[0])] #     

nt = l_sntc_s.index(mp_1[1])
for i in range(nt, len(l_sntc_s)):
    if l_sntc_s[i] > l_sntc_s[nt]:
        nt = i
        break

for i in range(l_sntc_s.index(mp_1[0]), nt):
    if l_sntc_s[i] > sl0 + dl:
        sl0 = l_sntc_s[i]
        k_gr.append([])
        l_gr.append([])
        gr += 1
    else:
        k_gr[gr].append(k_zlib[id_snt_s[i]])
        l_gr[gr].append(l_sntc_s[i])

print(' : ' + str(gr))
      
      



20 .





3. , :





x = [0]
y = [0]

for i in range(gr + 1):
    x.append(np.percentile(np.array(l_gr[i]), 50))
    y.append(np.percentile(np.array(k_gr[i]), 50))
      
      



  • :





y = a \ cdot x ^ {b}、

x - , y - .





x = np.array(x)
y = np.array(y)

#  
def func(x, a, b):
    return a * x ** b

popt, pcov = curve_fit(func, x, y, (0.27, 0.24), maxfev=10 ** 6)
a, b = popt

print('a = {0}\nb = {1}'.format(*tuple(popt)))
print(' : ' + str(np.corrcoef(y, a * x ** b)[0][1]))
      
      



a = 0.17601951773514363, b = 0.3256903074228561, : 0.9999489378452683





:





y = 0.18 \ cdot x ^ {0.33}、

( 50 - 280 ) , . "c" "y = " ( ), , :





c = np.percentile(np.array(k_zlib), 50)

graph = plt.figure()
axes = graph.add_axes([0, 0, 1, 1])
axes.set_xlabel(' ')
axes.set_ylabel(' ')
axes.set_title('     ')
axes.plot([60, 280], [c, c], color='r')
axes.plot(range(60, 281), a * np.array(range(60, 281)) ** b, color='b')
      
      



. ~130 , ~130 - . . , .





.  , .





k_zlib_f = np.array(k_zlib) * c / (a * np.array(l_sntc) ** b)
      
      



,   :





  • 私たちの場合、センテンスはすでにテクニカルジャンクが削除されているため、例として、スパムされたセンテンスのみを除外します。





p_zlib_1 = np.percentile(np.array(k_zlib), 99.95)
p_zlib_2 = np.percentile(np.array(k_zlib_f), 99.95)

for i in range(len(sntc)):
  if k_zlib_f[i] > p_zlib_2 and k_zlib[i] <= p_zlib_1:
    print(sntc[i])
      
      



ご覧のとおり、これらは圧縮率が過小評価されている短い文です実際には、同じ長さの文はコーパスでは非常にまれです。原則として、長さの範囲は非常に重要です。





完全なラップトップコードはGitHubに投稿されています





おそらくそれは誰かのために役立つでしょう。私はこのアプローチを、技術的なジャンクやテンプレートスパムを取り除くための比較的簡単で効果的な方法として採用しました。








All Articles