Python: есть ли более быстрый способ исправления орфографии, чем использование автозамены?

Я выполняю анализ настроений и имею файлы train и test csv с фреймом данных train (созданным после чтения файлов csv), который имеет столбцы text и sentiment.

Пробовал в гугл-колаб:

!pip install autocorrect
from autocorrect import spell 
train['text'] = [' '.join([spell(i) for i in x.split()]) for x in train['text']]

Но это занимает вечность, чтобы остановиться. Есть ли лучший способ автоматически исправить столбец pandas? Как это сделать?

P.S.: набор данных достаточно большой, около 5000 строк, и каждое значение train['text'] содержит около 300 слов и имеет тип str. Я не разбил train['text'] на предложения.


person Rex5    schedule 09.08.2019    source источник
comment
@tester есть варианты?   -  person Rex5    schedule 09.08.2019


Ответы (1)


Во-первых, некоторые примерные данные:

from typing import List
from autocorrect import spell
import pandas as pd
from sklearn.datasets import fetch_20newsgroups

data_train: List[str] = fetch_20newsgroups(
    subset='train',
    categories=['alt.atheism', 'talk.religion.misc', 'comp.graphics', 'sci.space'],
    shuffle=True,
    random_state=444
).data

df = pd.DataFrame({"train": data_train})

Размер корпуса:

>>> df.shape
(2034, 1)

Средняя длина документа в символах:

>>> df["train"].str.len().mean()
1956.4896755162242

Первое наблюдение: spell() (я никогда не использовал autocorrect) работает очень медленно. Только на один документ уходит 7,77 с!

>>> first_doc = df.iat[0, 0]                                                                                                                                                                                                                                 
>>> len(first_doc.split())                                                                                                                                                                                                                                   
547
>>> first_doc[:100]                                                                                                                                                                                                                                          
'From: [email protected] (David B. Mckissock)\nSubject: Gibbons Outlines SSF Redesign Guida'
>>> %time " ".join((spell(i) for i in first_doc.split()))                                                                                                                                                                                                    
CPU times: user 7.77 s, sys: 159 ms, total: 7.93 s
Wall time: 7.93 s

Так что эта функция, а не выбор между векторизованным методом Pandas или .apply(), вероятно, является вашим узким местом. Расчет обратной стороны конверта, учитывая, что длина этого документа составляет примерно 1/3 от среднего, дает общее время непараллельного расчета 7,93 * 3 * 2034 == 48 388 секунд. Не красиво.

С этой целью рассмотрите возможность параллелизации. Это задача с высокой степенью распараллеливания: примените простой вызываемый объект, привязанный к процессору, для набора документов. concurrent.futures имеет для этого простой API. На этом этапе вы можете взять структуру данных из Pandas во что-то легкое, например список или кортеж.

Пример:

>>> corpus = df["train"].tolist()  # or just data_train from above...                                                                                                                                                                                        
>>> import concurrent.futures                                                                                                                                                                                                                                
>>> import os                                                                                                                                                                                                                                                
>>> os.cpu_count()                                                                                                                                                                                                                                           
24
>>> with concurrent.futures.ProcessPoolExecutor() as executor: 
...     corrected = executor.map(lambda doc: " ".join((spell(i) for i in doc)), corpus)
person Brad Solomon    schedule 09.08.2019
comment
Я попробую это и обновлю, если это сработает в совместной работе... и, конечно же, приму соответствующее решение. И считается ли это хорошей практикой для придания облегченным структурам (с точки зрения памяти)? - person Rex5; 10.08.2019
comment
* преобразование в список или кортеж. - person Rex5; 12.08.2019
comment
Привет, мой бог!! какая конфигурация процессора у вас есть ??? Я имею в виду в сотрудничестве с Google, и мой процессор os.cpu_count возвращает 2. Проверил свойства, он говорит AMD PRO A6-9500 R5 2C + 6G? Значит, у меня не может быть больше двух вычислительных ядер, верно? Есть ли способ сделать это онлайн где-нибудь на данный момент? - person Rex5; 12.08.2019
comment
Не использовал Google Colab, но это было с Mac Pro @Rex5. Однако AWS, Azure и другие предлагают виртуальные машины, которые вы можете использовать на краткосрочной основе с вдвое или втрое больше, чем многие ядра. - person Brad Solomon; 13.08.2019