Ускорить добавление новой строки

  1. Получаем данные с сервера
  2. Парсим
  3. Результат парсинга добавляем в виде новой строки в dataframe

Код:

def __updateDB(self):

try:
    while True:
        # получаем результат
        result = self.__client_HTTP.query(
            symbol=symbol,

        )

            # парсим запрос
            for item in result['result']:
                dfTemp.loc[item['start']] = [item['open'], candle['buds']]


except Exception as e:
    print(e)

Суть проблемы:

в результате запроса примерно 200 item, так вот, когда начинается добавление в dateframe - начинаются страшные лаги, 200 item добавляются в timeframe 11с !!! С чем это связано и как нужно добавлять корректно, чтобы все эта операция происходила быстро.

Я предполагаю, могу ошибаться, что когда я вызываю операцию добавления в dataframe:

dfTemp.loc[item['start']] = [item['open'], candle['buds']]

создается копия оригинального dataframe с новой добавленной строкой и затем новый dataframe заменяет старый.

Важное уточнение!!! изначально dataframe, до добавления новой строки, уже имеет 1,5млн+ элементов

Что я пробовал:

  1. Метод append - работает быстрее, примерно 2 сек на 200 элементов, но все же многовото
  2. Создать временный пустой dataframe и туда добавить все строки из запроса, а затем приклеить к основному dataframe, работает очень быстро, на 200 элементов тратит примерно 50мс. Но что будет когда этот же dataframe будет иметь в себе 500к элементов и более, снова сработает принцип - чем больше элементов в dataframe тем дольше будет добавлять новая строка

Ответы (2 шт):

Автор решения: CrazyElf

Вот я даже за вас небольшой эксперимент проделал. Суть в том, что скорость работы pd.concat не прямо пропорциональна размеру датафрейма. Основные затраты времени идут на создание нового датафрейма почти независимо от его размера. Именно поэтому лучше делать объединение одной операцией как можно реже, и ни в коем случае не делать это часто и в цикле.

import pandas as pd
import numpy as np
import seaborn as sns
from timeit import default_timer as timer
import matplotlib.pylab as plt

n, k, z = 1_500_000, 20, 10
df = pd.DataFrame(np.random.rand(n, k))
x = range(7)
y = []
for i in x:
    df1 = pd.DataFrame(np.random.rand(10**i, k))
    r = 0
    for j in range(z):
        t = timer()
        df2 = pd.concat([df, df1])
        r += timer() - t
    y.append(r/z)
sns.lineplot(x=[10**i for i in x], y=y)
plt.xscale('log')
plt.title('Зависимость времени присоединения от размера')
plt.xlabel('Размер присоединяемого датафрейма')
plt.ylabel('Время в секундах')

введите сюда описание изображения

Обратите внимание - шкала размера логарифмическая.

График получается довольно разный на промежуточных значениях с каждым запуском не смотря на усреднение времени, которое я делаю, но основной вывод всё-равно такой: разница по времени между добавлением датафрейма из одной строки и из миллиона строк - всего в 2 раза (!!!). Именно поэтому выгодно накапливать данные в обычных объектах питона (например, в списках), а потом делать из них единоразово датафрейм и добавлять их в исходный датафрейм через pd.concat.

Если же такой сценарий работы вам не подходит и вам нужно очень быстро добавлять именно одиночные строки данных, то, как отметил в комментарии
Алексей Р, вам лучше использовать для этого базу данных. БД для такого сценария отлично подходят. Датафреймы же в основном предназначены для анализа данных, а не для их хранения и обновления.

→ Ссылка
Автор решения: Duracell

На основе советов умных людей выше, пришел к выводу, что один из лучших вариантов для моей ситуации таков:

  1. Делаем запрос API
  2. Получаем ответ
  3. Создаем пустой временный dataframe с нужными колонками
  4. Парсим и одновременно суем в пустой dataframe нужные данные, в моем случае в виде новой строки
  5. Далее конкатенируем временный dataframe с основным
  6. Удаляем временный dataframe и снова создаем пустой dataframe с нужными колонками
  7. далее все повторяется до тех пор, пока не остановим цикл выборки

В коде будет выглядеть примерно так:

def __updateDB(self):

try:
    tempDF = pd.DataFrame(columns=['open', 'buds'])
    while True:
        # получаем результат
        result = self.__client_HTTP.query(
            symbol=symbol,

        )

            # парсим запрос
            for item in result['result']:
                tempDF.loc[item['start']] = [item['open'], candle['buds']]

             self.df = pd.concat([self.df, tempDf])
             def tempDf
             tempDF = pd.DataFrame(columns=['open', 'buds'])


except Exception as e:
    print(e)

Что происходит при добавлении строки в уже заполненный большой dataframe наглядно показал @CrazyElf, так же советую прочитать инфу, по похожей теме, которую предложил @Сергей Кох

→ Ссылка