Нужна помощь в оптимизации поиска в массиве символов с помощью NumPy

#python #numpy

#python #numpy

Вопрос:

Мне нужно сравнить два списка слов с оценками (новый и старый), чтобы найти в новом списке слова, которых нет в старом (игнорируя оценки слов), и вернуть список новых слов Python (с оценками).). Входные списки форматируются следующим образом:

 new = ['RED;25','BLUE;30','YELLOW;50','GREEN;10']
old = ['GREEN;50','YELLOW;50','PURPLE;50']
  

И выходной список должен иметь тот же формат. Код, который я разработал с использованием NumPy, является:

 import numpy as np

def find_new_words(new, old):

        n, o = np.char.array(new), np.char.array(old)
        w_n = np.char.array([i[0:i.find(';')] for i in new])
        w_o = np.char.array([i[0:i.find(';')] for i in old])
        ans = [n[np.char.find(i, w_n) == 0] for i in np.setdiff1d(w_n, w_o)]
        lst = [i for sublist in np.array(ans).tolist() for i in sublist]

        return lst
  

который возвращает правильный ответ:

 ['BLUE;30', 'RED;25']
  

для примеров списков, показанных выше.

Проблема, с которой я сталкиваюсь, заключается в том, что мои списки содержат десятки тысяч записей, и обработка этой функции занимает целую вечность (около восьми минут для старых и новых списков по 50 000 записей в каждом, что смешно). Есть мысли о том, как я могу ускорить процесс? Похоже, я просто делаю слишком много ненужных повторяющихся циклов. Я уверен, что есть более Pythonic (NumPonic ??) способ сделать это.

Заранее спасибо!

Комментарии:

1. np.char функции по существу применяют строковые методы python к элементам массива. Скорость примерно такая же, как у понимания списка. numpy не имеет собственных скомпилированных строковых методов. Возможно, было бы лучше придерживаться списков.

Ответ №1:

Переписать вашу функцию для работы со списками, а не с numpy:

 def find_wlist(new, old):
        w_n = [i[0:i.find(';')] for i in new]
        w_o = [i[0:i.find(';')] for i in old]
        d = set(w_n).difference(set(w_o))
        lst = [x for x,z in zip(new, w_n) if z in d]
        return lst
In [367]: find_wlist(new, old)
Out[367]: ['RED;25', 'BLUE;30']
  

Другой порядок, но те же результаты.

 In [368]: timeit find_new_words(new, old)
235 µs ± 2.11 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [369]: timeit find_wlist(new, old)
4.61 µs ± 127 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
  

numpy не предлагает особых, если таковые имеются, преимуществ в производительности при работе со строками, особенно при сопоставлении подобных операций.

Комментарии:

1. ты мой герой. Я пытался сделать это самостоятельно в течение недели. Ваше решение работает отлично и работает так же быстро, как смазанная молния. Большое вам спасибо за вашу помощь!