Ускорить добавление новой строки
- Получаем данные с сервера
- Парсим
- Результат парсинга добавляем в виде новой строки в
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млн+ элементов
Что я пробовал:
- Метод
append- работает быстрее, примерно 2 сек на 200 элементов, но все же многовото - Создать временный пустой
dataframeи туда добавить все строки из запроса, а затем приклеить к основномуdataframe, работает очень быстро, на 200 элементов тратит примерно 50мс. Но что будет когда этот жеdataframeбудет иметь в себе 500к элементов и более, снова сработает принцип - чем больше элементов вdataframeтем дольше будет добавлять новая строка
Ответы (2 шт):
Вот я даже за вас небольшой эксперимент проделал. Суть в том, что скорость работы 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.
Если же такой сценарий работы вам не подходит и вам нужно очень быстро добавлять именно одиночные строки данных, то, как отметил в комментарии
Алексей Р, вам лучше использовать для этого базу данных. БД для такого сценария отлично подходят. Датафреймы же в основном предназначены для анализа данных, а не для их хранения и обновления.
На основе советов умных людей выше, пришел к выводу, что один из лучших вариантов для моей ситуации таков:
- Делаем запрос
API - Получаем ответ
- Создаем пустой временный
dataframeс нужными колонками - Парсим и одновременно суем в пустой
dataframeнужные данные, в моем случае в виде новой строки - Далее конкатенируем временный
dataframeс основным - Удаляем временный
dataframeи снова создаем пустойdataframeс нужными колонками - далее все повторяется до тех пор, пока не остановим цикл выборки
В коде будет выглядеть примерно так:
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, так же советую прочитать инфу, по похожей теме, которую предложил @Сергей Кох
