Adaptação da abordagem usando compressão zlib para filtrar textos de baixa qualidade de comprimentos diferentes

Recentemente, Sberbank no artigo All we need is generation sugeriu uma abordagem incomum para filtrar textos de baixa qualidade (lixo técnico e spam de modelo).





Complementamos essa abordagem com mais uma heurística: fizemos a compressão de textos usando zlib e descartamos os que comprimiam mais forte e mais fracamente, e então aplicamos a classificação. Faixa de compactação selecionada empiricamente para texto normal × 1,2— × 8 (menos de 1,2 - caracteres aleatórios e lixo técnico, mais de 8 - spam de modelo). 





A abordagem é certamente interessante e vale a pena ser adotada. Mas a taxa de compactação zlib em textos de qualidade não tem uma dependência não linear do comprimento do texto sendo compactado? Vamos checar.





Vamos pegar um corpus de texto de frases que variam em comprimento de 50 a 280 caracteres:





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)))
      
      



Vamos ver como o comprimento das frases de alta qualidade afeta a taxa de compressão.

Por esta:





1. Vamos pegar o intervalo de comprimentos de sentenças com a frequência mais alta (percentil 25 - 75). Em nosso caso, são comprimentos de 92 a 175 caracteres:





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)
      
      



,   :





  • em nosso caso, as frases já foram eliminadas de lixo técnico, então, como exemplo, filtramos apenas as frases com spam:





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])
      
      



Como você pode ver, essas são frases curtas para as quais a taxa de compressão foi subestimada . Na prática, frases do mesmo comprimento são bastante raras no corpus. Como regra, a gama de comprimentos é bastante significativa.





O código completo do laptop está postado no GitHub .





Talvez seja útil para alguém. Adotei essa abordagem para mim como uma maneira relativamente simples e eficaz de me livrar de lixo técnico e spam de modelo.








All Articles