Deixe-o mais rápido (PyMorphy2, PyMystem3 e um pouco de mágica)

Trabalho como programador, incluindo aprendizado de máquina em relação à análise de texto. Ao processar uma linguagem natural, é necessária a preparação preliminar de documentos e um dos métodos é a lematização - trazendo todas as palavras do texto para suas formas normais, levando em consideração o contexto.

Recentemente, enfrentamos o problema de grandes custos de tempo para esse processo. Em uma tarefa específica, havia mais de 100.000 documentos, cujo tamanho médio era de cerca de 1.000 caracteres e era necessário implementar o processamento em um computador local comum, e não em nosso servidor para cálculos. Não conseguimos encontrar uma solução na Internet, mas a encontramos por nós mesmos e eu gostaria de compartilhá-la - para demonstrar uma análise comparativa das duas bibliotecas de lematização mais populares deste artigo.



Pymorphy2


Um dos mais populares é o PyMorphy2 - é encontrado em quase todas as soluções que podem ser encontradas na rede. Também usamos essa biblioteca, e ela se mostrou perfeitamente, até que foi necessário fazer uma lematização para todo o banco de dados (como escrevi acima, são mais de 100 mil pequenos documentos). Para analisar esse volume de documentos, o PyMorphy2 levaria quase 10 horas, enquanto o processador carregava todo esse tempo em média cerca de 30% (Intel Core i7 7740X).

Pymystem3


Em busca de outra solução, analisamos a biblioteca do Yandex PyMystem3, mas o resultado foi quase duas vezes pior (com o tempo) do que o PyMorphy2: levaria 16 horas para processar 100 mil documentos.

Alguma mágica


Pareceu-nos estranho que a carga no processador fosse quase zero. Também era estranho que, para obter o resultado de um texto, mesmo o tamanho grande (de 3 a 4 mil caracteres), o PyMystem3 demorasse cerca de 1 segundo. Portanto, decidimos combinar os textos adicionando algum tipo de separador entre eles, pelo qual poderíamos retornar novamente a estrutura de nossa lista de documentos e fornecê-los para a lematização.

Código da solução Python:

def checkExecTimeMystemOneText(texts):
    lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)]
    txtpart = lol(texts, 1000)
    res = []
    for txtp in txtpart:
        alltexts = ' '.join([txt + ' br ' for txt in txtp])

        words = mystem.lemmatize(alltexts)
        doc = []
        for txt in words:
            if txt != '\n' and txt.strip() != '':
                if txt == 'br':
                    res.append(doc)
                    doc = []
                else:
                    doc.append(txt)

Levamos 1000 documentos cada para a união, o separador entre eles era “br” (note-se que os textos em russo e o alfabeto latino e caracteres especiais foram removidos anteriormente). Essa solução acelerou significativamente a lematização: em média, resultou em cerca de 25 minutos para todos os 100 mil documentos, a carga do processador foi de 20 a 40%. É verdade que esta solução carrega mais RAM: em média, é de cerca de 3-7 GB, mas este é um bom resultado. Se não houver memória suficiente, você poderá alterar o número de documentos a serem combinados, embora isso diminua o processamento, ainda será muito mais rápido que um texto por vez. Além disso, se a quantidade de memória permitir, você poderá aumentar esse valor e obter o resultado ainda mais rápido.

A tabela mostra uma comparação de bibliotecas durante o processamento em um computador local (Intel Core i7 7740X, 32 GB de RAM):
MétodoTempoRAM (Mb)Por cento
Pymorphy2~ 9,5 horas500 - 60025 - 30%
PyMystem3 por 1 frase~ 16 horas500 - 7000 - 1%
PyMystem3 com 1000 ofertas26 minutos2000 - 700025 - 40%

É interessante conhecer as opiniões de outros especialistas. Talvez alguém tenha encontrado uma maneira mais eficiente de poupar textos curtos?

Mikhail Kabakov, engenheiro de software sênior,
Anna Mikhailova, chefe de
mineração de dados do Codex Consortium

All Articles