最近、記事の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))
:
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
:
( 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])
ご覧のとおり、これらは圧縮率が過小評価されている短い文です。実際には、同じ長さの文はコーパスでは非常にまれです。原則として、長さの範囲は非常に重要です。
おそらくそれは誰かのために役立つでしょう。私はこのアプローチを、技術的なジャンクやテンプレートスパムを取り除くための比較的簡単で効果的な方法として採用しました。