Замедление при большом количестве итераций

Рейтинг: 0Ответов: 1Опубликовано: 22.03.2023

logs - pd.DataFrame() на 3 000 000 строк, некоторые строки в котором имеют вид:

Поиск в ЕРЗ пациента (IP: 11.11.11.11, ID: 99999) - ФИО: Иванов Иван Иванович, Пол: F, ДР: 1999-01-01T00:00:00Z, ЕНП: 1234567891011121 СНИЛС: 123-456-789 10.

Соответственно, я засекаю время обработки каждых 100000 строк, в результате получаю, что первые 100к строк обрабатываются за 0,96 сек., вторые - 2,25, третьи - 3,62 и т.д.

В итоге последние 100к строк обрабатываются за 93 секунды, а общее время обработки датафрейма составляет практически 20 минут. С чем связано это замедление и что можно с этим сделать? Оперативной памяти в это время загружено от силы 50%, если это важно.

logs_array = logs.to_numpy()
l = []
start_time = time.time()
start_time1 = time.time()
x = 0
for i in logs_array:
    if "ЕРЗ пациента" in i[3]:
        # print(i[3])
        infopat = i[3].split(" - ")[1].split(", ")
        s = []
        s.append(infopat[0][5:].replace("\n",""))  # ФИО
        s.append(infopat[1][-1].replace("\n",""))  # Пол
        s.append(infopat[2][4:].replace("\n",""))  # ДР
        s.append(infopat[3].split(" СНИЛС: ")[0][5:].replace("\n",""))  # ЕНП
        try:
            s.append(infopat[3].split(" СНИЛС: ")[1].replace("\n",""))  # СНИЛС
        except IndexError:
            s.append(0)
        if s not in l:
            l.append(s)
    x += 1
    if x%100000 == 0:
        print("--- %s seconds ---" % (time.time() - start_time1))
        start_time1 = time.time()
patients = pd.DataFrame(l,columns=patients1.columns.values.tolist())  
print("--- %s seconds ---" % (time.time() - start_time))

Ответы

▲ 1Принят

Тормозит скорее всего вот это место:

        if s not in l:
            l.append(s)

Проверка наличия элемента в списке имеет сложность O(n), соответственно, с ростом списка l растёт и время на эту проверку. Можете попробовать использовать в качестве l множество, если порядок элементов вам не важен, либо словарь с любым элементом в качестве значения, ключи словарей упорядочены начиная с какой-то версии питона (кажется, с 3.5 или 3.6). Тогда сложность проверки будет практически O(1) и скорость не будет падать.

А вообще лучше бы вместо цикла написать функцию, которая обрабатывает строку датафрейма нужным образом и отдаёт результат и сделать apply её на датафрейм. А из результатов потом можно дропнуть дупликаты встроенным методом пандаса.