Почему моя функция NLTK работает медленно при обработке DataFrame?

Я пытаюсь выполнить функцию с миллионами строк в наборах данных.

  1. Я читаю данные из CSV в кадре данных
  2. Я использую выпадающий список для удаления данных, которые мне не нужны
  3. Я передаю его через функцию NLTK в цикле for.

код:

def nlkt(val):
    val=repr(val)
    clean_txt = [word for word in val.split() if word.lower() not in stopwords.words('english')]
    nopunc = [char for char in str(clean_txt) if char not in string.punctuation]
    nonum = [char for char in nopunc if not char.isdigit()]
    words_string = ''.join(nonum)
    return words_string

Теперь я вызываю вышеупомянутую функцию, используя цикл for, через который проходит миллион записей. Несмотря на то, что я работаю на тяжеловесном сервере с 24-ядерным процессором и 88 ГБ оперативной памяти, я вижу, что цикл занимает слишком много времени и не использует вычислительную мощность, которая там есть.

Я вызываю вышеуказанную функцию, как это

data = pd.read_excel(scrPath + "UserData_Full.xlsx", encoding='utf-8')
droplist = ['Submitter', 'Environment']
data.drop(droplist,axis=1,inplace=True)

#Merging the columns company and detailed description

data['Anylize_Text']= data['Company'].astype(str) + ' ' + data['Detailed_Description'].astype(str)

finallist =[]

for eachlist in data['Anylize_Text']:
    z = nlkt(eachlist)
    finallist.append(z)

Приведенный выше код работает нормально, просто слишком медленно, когда у нас несколько миллионов записей. Это просто пример записи в Excel, но фактические данные будут в БД, которая будет составлять несколько сотен миллионов. Можно ли как-нибудь ускорить операцию, чтобы быстрее передавать данные через функцию - вместо этого использовать больше вычислительных мощностей?

1 ответ

Решение

Ваш оригинал nlkt() перебирает каждый ряд 3 раза.

def nlkt(val):
    val=repr(val)
    clean_txt = [word for word in val.split() if word.lower() not in stopwords.words('english')]
    nopunc = [char for char in str(clean_txt) if char not in string.punctuation]
    nonum = [char for char in nopunc if not char.isdigit()]
    words_string = ''.join(nonum)
    return words_string

Кроме того, каждый раз, когда вы звоните nlkt() Вы повторно инициализируете их снова и снова.

  • stopwords.words('english')
  • string.punctuation

Они должны быть глобальными.

stoplist = stopwords.words('english') + list(string.punctuation)

Проходя через вещи построчно:

val=repr(val)

Я не уверен, зачем тебе это нужно. Но вы могли бы легко привести колонну к str тип. Это должно быть сделано за пределами вашей функции предварительной обработки.

Надеюсь, это говорит само за себя:

>>> import pandas as pd
>>> df = pd.DataFrame([[0, 1, 2], [2, 'xyz', 4], [5, 'abc', 'def']])
>>> df
   0    1    2
0  0    1    2
1  2  xyz    4
2  5  abc  def
>>> df[1]
0      1
1    xyz
2    abc
Name: 1, dtype: object
>>> df[1].astype(str)
0      1
1    xyz
2    abc
Name: 1, dtype: object
>>> list(df[1])
[1, 'xyz', 'abc']
>>> list(df[1].astype(str))
['1', 'xyz', 'abc']

Теперь перейдем к следующей строке:

clean_txt = [word for word in val.split() if word.lower() not in stopwords.words('english')]

С помощью str.split() Это неудобно, вы должны использовать правильный токенизатор. В противном случае ваши знаки препинания могут застревать с предыдущим словом, например

>>> from nltk.corpus import stopwords
>>> from nltk import word_tokenize
>>> import string
>>> stoplist = stopwords.words('english') + list(string.punctuation)
>>> stoplist = set(stoplist)

>>> text = 'This is foo, bar and doh.'

>>> [word for word in text.split() if word.lower() not in stoplist]
['foo,', 'bar', 'doh.']

>>> [word for word in word_tokenize(text) if word.lower() not in stoplist]
['foo', 'bar', 'doh']

Также проверка на .isdigit() должны быть проверены вместе:

>>> text = 'This is foo, bar, 234, 567 and doh.'
>>> [word for word in word_tokenize(text) if word.lower() not in stoplist and not word.isdigit()]
['foo', 'bar', 'doh']

Собираем все вместе nlkt() должен выглядеть так:

def preprocess(text):
    return [word for word in word_tokenize(text) if word.lower() not in stoplist and not word.isdigit()]

И вы можете использовать DataFrame.apply:

data['Anylize_Text'].apply(preprocess)
Другие вопросы по тегам