Estamos procurando por "Trolls". Algoritmo de cascalho e semelhança de cossenos



Acho que muitos nas tensas discussões na Internet enfrentaram acusações de pessoas de que são bots, trolls e pagos pelo Kremlin, Kiev ou Washington. Mas como identificar realmente aqueles ou apenas as pessoas que estão tentando transmitir ativamente sua opinião aos demais?



Pegue, por exemplo, quatro textos (comentários):



text_1 = '       ,    '
text_2 = '      ,    ,    '
text_3 = '             '
text_4 = '   ,   ,     ,    '


Do ponto de vista humano, há definitivamente uma semelhança no primeiro e no segundo comentários, eles são escritos sobre uma pessoa e caracterizam seus aspectos positivos. E também não têm nada a ver com os textos três e quatro.



Como você chega ao mesmo resultado em termos de matemática?

É piegas comparar o número de palavras idênticas em ambos os textos. Mas o problema surge imediatamente - como comparar as palavras inteligente e inteligente ? A lematização do texto nem sempre é adequada, uma vez que bibliotecas prontas não suportam muitos idiomas.



Nesses momentos, justifica-se a utilização do Algoritmo Shingle, que divide o texto em n partes, cujo tamanho é selecionado empiricamente para uma tarefa específica.



Exemplo:



Texto 1 para n = 3
['', '', '', '', '', '', '', '', '', ' ', ' ', '  ', ' ', ' ', '', '', '', '', ' ', ' ', ' ', '', '', ' ', ' ', ' ', '', '', '', '', '', '', '', '', '', '', '', '', '', ' ', ' ', ' ', '', '', '', '', ' ', ' ', ' ', '', '', '', '', '', '', '', '', '', ' ', ' ', ' ', '', '', '', ' ', ' ', ' ', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ' ', ' ', '  ', ' ', ' ', '', '', '', '', '', '', '', '', '', '', '', ' ', ' ', ' ', '', '', '', '', '', '']




Texto 1 para n = 5
['', '', '', '', '', '', '', ' ', ' ', '  ', '  ', '  ', ' ', ' ', '', '', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '', '', '', '', '', '', '', '', '', '', '', ' ', ' ', ' ', ' ', ' ', '', '', ' ', ' ', ' ', ' ', ' ', '', '', '', '', '', '', '', ' ', ' ', ' ', ' ', ' ', '', ' ', ' ', ' ', ' ', ' ', '', '', '', '', '', '', '', '', '', '', '', '', ' ', ' ', '  ', '  ', '  ', ' ', ' ', '', '', '', '', '', '', '', '', '', ' ', ' ', ' ', ' ', ' ', '', '', '', '']




Vamos calcular a similaridade do primeiro e segundo / primeiro e quarto textos para n (1,9) pela fórmula:



sim = len(set(Shingles_1) & set(Shingles_2)) / len(set(Shingles_1) | set(Shingles_2)))


ShingleSize: 1
0.9166666666666666 / 0.7857142857142857
ShingleSize: 2
0.5196078431372549 / 0.40350877192982454
ShingleSize: 3
0.3404255319148936 / 0.2375
ShingleSize: 4
0.28205128205128205 / 0.18497109826589594 
ShingleSize: 5
0.2289156626506024 / 0.13812154696132597
ShingleSize: 6
0.1896551724137931 / 0.10752688172043011
ShingleSize: 7
0.15730337078651685 / 0.07894736842105263
ShingleSize: 8
0.13333333333333333 / 0.057291666666666664
ShingleSize: 9
0.10989010989010989 / 0.04145077720207254


Uma imagem natural, com um aumento no comprimento, o número total de telhas aumenta e a proporção entre o total de telhas e o volume total diminui. Portanto, para grandes quantidades de textos, é melhor usar o comprimento das telhas de 5 a 8, e ao trabalhar com pequenas, por exemplo, tweets ou comentários - 2-4.



Mas, de volta à prática, vamos pegar os dados pré-coletados do popular portal de entretenimento russo. Link para kaggle .



Para recolher as discussões mais acaloradas, foi escolhida a etiqueta (secção) - Política, total recolhido:



  • 944 postagens políticas marcadas
  • 267.000 comentários para eles
  • dos quais mais de 100 caracteres ~ 140 mil


Passando para o código:



Limpando texto e dividindo em telhas:



def clean_text(text):
    text = text.split('\n')
    text = list(filter(None, text))
    text = ' '.join(text)
    text = re.sub(r"http\S+", "", text)
    text = re.sub(r'[^\w\s]', '', text)
    shingle = [text[i:i + ShingleSize] for i in range(len(text))][:-ShingleSize]
    return ','.join(shingle)


Se tomarmos apenas comentários com mais de 100 caracteres, o número de iterações de comparação será: 140.000!/((140.000-2)!2!), o que é bastante e o processamento, mesmo no modo multi-threaded, levará muito tempo.



Portanto, não compararemos em pares, mas com matrizes m * n , usando similaridade de cosseno em

que m é o número de linhas, que é opcionalmente selecionado dependendo da quantidade de RAM, en é o número de colunas, o número total de todas as telhas;



Implementação do algoritmo:



csrMatrix = []
idArray = []
textArray = []
for i in range(ChunkSize, sparse_matrix.shape[0] + ChunkSize, ChunkSize):
    temp = sparse_matrix[i - ChunkSize:i - 1]
    idArray.append(corpusId[i - ChunkSize:i - 1])
    textArray.append(OriginalCorpus[i - ChunkSize:i - 1])
    csrMatrix.append(temp)

matrixCombinations = itertools.combinations_with_replacement(range(len(csrMatrix)), 2)


Com m = 20.000 e comprimento de telha = 8, obtemos 7 matrizes de 20.000 * ≈8800.000 em tamanho e, portanto, 21 iterações de comparação. Muito melhor já.



def Sim(A, B, C, D):
    similarities = cosine_similarity(B[A[0]].astype(np.float32), B[A[1]].astype(np.float32))
    x, y = np.where(similarities > similarityPercent)
    res = []
    for k, j in zip(x, y):
        if D[A[0]][k] != D[A[1]][j]:
            res.append((D[A[0]][k], C[A[0]][k], similarities[k][j].item(), D[A[1]][j], C[A[1]][j]))
    return res

s = pool.starmap(Sim, zip(matrixCombinations, itertools.repeat(csrMatrix), itertools.repeat(textArray), itertools.repeat(idArray)))
s = [item for sublist in s for item in sublist]


Para reduzir o espaço ocupado, também usamos o tipo de dados float32. Sua precisão é suficiente para que o algoritmo funcione corretamente.



Os resultados do trabalho são inseridos no banco de dados MySQL para processamento posterior. Então, por exemplo, vamos agrupar os comentários, contando para cada um a semelhança com seus pares:



SELECT FirstText, SUM(sim) as c FROM pikabu.similarity GROUP BY FirstId ORDER BY c DESC


Melhores correspondências:



  1. O comentário foi excluído. Motivo: esta conta foi excluída.
  2. O comentário foi excluído. Motivo: insultar os usuários.
  3. O comentário foi excluído. Motivo: insultos, comunicação rude e provocações.
  4. O comentário foi excluído. Motivo: É proibido postar comentários cujo único objetivo seja causar hostilidade ou incitação à hostilidade, e comentários com apelos à violência ou assédio são proibidos.


A situação padrão para discussão política na Internet.



Descartando links, mensagens da administração e outros ruídos, vamos direto para a análise da carga semântica dos comentários:



Oito partidas
DaimosShip,2020-08-14 23:03:48,

,

DaimosShip,2020-08-14 23:05:41,

,

DaimosShip,2020-08-14 23:05:52,

,

DaimosShip,2020-08-14 23:05:26,

,

DaimosShip,2020-08-14 23:05:22,

,

DaimosShip,2020-08-14 23:07:02,

,

DaimosShip,2020-08-14 23:06:53,

,

DaimosShip,2020-08-14 23:06:18,

,



Um homem escreveu 8 mensagens idênticas no mesmo tópico em cinco minutos, sobre os eventos na Bielo-Rússia. No total, 260 mensagens deste autor foram incluídas no banco de dados, uma rápida olhada nelas deixa claro uma atitude negativa óbvia para a situação na Bielorrússia, o próprio usuário está à frente da curva e chama seus oponentes de bots como argumentos.



E seu irmão era um observador nas eleições:



DaimosShip, 2020-08-18 22:52:41

Meu irmão era um observador - eles não eram permitidos em qualquer lugar




Mais 6 partidas
NoisePanzer,2017-11-20 14:58:26,

17 . , , , 80% ( !) .



NoisePanzer,2017-11-20 15:33:26,

. . ( !) . , , . ( ) , .



NoisePanzer,2017-11-20 15:26:55,

. . . ( !) . , , . ( ) , .



NoisePanzer,2017-11-21 03:51:46,

. . . ( !) . , , . ( ) , .



NoisePanzer,2017-11-21 03:52:14,

. . . ( !) . , , . ( ) , .



NoisePanzer,2017-11-21 03:53:22,

. ( !) . , , . ( ) , .



O autor é claramente um fã da literatura histórica alemã



E mais 4
Kumuj,2018-03-25 01:46:10,

, . ?



Kumuj,2018-03-25 01:53:56,

, . ?



Kumuj,2018-03-25 01:46:26,

, . ?



Kumuj,2018-03-25 01:42:29,

, . ?



O homem está procurando vestígios da fábrica de trolls. Oi colega.



Vá em frente: 6 pessoas estão citando o mesmo livro em tópicos diferentes - Cuidado, xeque-mate !!!
Strannik196,2018-03-21 23:53:00,

:"« , «-22» : , , . , — . , : , , . .— , — . — . . , . , . . :— …»"



Fynjif18,2020-09-09 13:44:56,

.— , — . — , «-22» : , , . , — . , : , , .



wakeonlan,2020-06-23 01:38:29,

«-22» : , , ** . ** , — . , : * , , .



KKirill1992,2017-06-18 00:06:30,

, "«-22»" . , , , . . - ? , ?



nezabuddha,2018-11-01 15:29:56,

ru.m.wikipedia.org/wiki/-22 . , .



ihateyou,2016-09-19 02:52:14,

, «-22» : , , . , — . , : , , . .— , — . — . . , . , . . :— … "«Empire V»"



O autor está tentando transmitir ao resto dos dados sobre o crescimento do nível de apoio à URSS
EtovamneTo,2020-08-18 01:50:22,

, , … . . , 18-24 , , 2008- 2019- , . , , « », . . , , – , ( 18-24- ). , , , , – « » ( 14 ..) «, , » ( 18 ..).https://www.levada.ru/2019/06/24/chernovik/



EtovamneTo,2020-08-18 00:50:15,

, , , , . , IQ . : . : . , 18-24 , , 2008- 2019- , . , , « », . . , , – , ( 18-24- ). , , , , – « » ( 14 ..) «, , » ( 18 ..).https://www.levada.ru/2019/06/24/chernovik/



EtovamneTo,2020-08-27 23:22:35,

. *****(). 18 . . , 18-24 , , 2008- 2019- , . , , « », . . , , – , ( 18-24- ). , , , , – « » ( 14 ..) «, , » ( 18 ..).https://www.levada.ru/2019/06/24/chernovik/



EtovamneTo,2020-09-10 03:32:13,

? ? 25. 2010 44 . 2020 274 . ? . , 18-24 https://www.levada.ru/2019/06/24/chernovik/



EtovamneTo,2020-09-09 19:00:42,

. , 18-24 , , 2008- 2019- , . , , « », . . , , – , ( 18-24- ). , , , , – « » ( 14 ..) «, , » ( 18 ..).https://www.levada.ru/2019/06/24/chernovik/



Os exemplos dados estavam na superfície. Para identificar relacionamentos mais próximos, é necessário expandir o conjunto de dados em uma ordem de magnitude, não apenas pela quantidade de informações, mas também por intervalos de tempo. Isso tornará possível identificar com mais precisão os principais tópicos em torno dos quais as discussões estão sendo construídas, seus iniciadores, analisar os registros de data e hora dos eventos e sua correlação.

Mas mesmo em tal conjunto, com análise manual detalhada, por exemplo, considerando conexões únicas, você pode encontrar algo interessante, que abre espaço para reflexão e trabalho futuro.



GitHub



PS O processamento da matriz 140.000 * 8800000 levou cerca de 7 minutos no processador rayzen 5 1600



No futuro, pretendo continuar este tópico, terei o maior prazer em receber críticas e sugestões.



All Articles