Перемножить значения внутри списков ячеек датафрейма
Можно ли обойтись без циклов и доп. библиотеки math что б перемножить значения внутри списков? В колонках asks и bids нужно перемножить левое число на правое и применить фильтр >30.Так же подскажите почему метод dt.time добавляет нули к миллисекундам, можно ли убрать нули или вообще оставить только время с точностью до секунды?
import pandas as pd
import math
# не переносить столбцы в консоли
pd.options.display.expand_frame_repr = False
arr_asks = []
arr_bids = []
all_amount = []
data = {'action': 'snapshot',
'arg': {'channel': 'books5', 'instId': 'DCKUSDT', 'instType': 'SPOT'},
'data': [{'asks': [['0.05040', '34.09'],
['0.05045', '210.31'],
['0.05064', '34.09'],
['0.05075', '31.00'],
['0.05077', '70.02']],
'bids': [['0.05008', '7749.89'],
['0.05007', '199.72'],
['0.04992', '635.05'],
['0.04991', '70.02'],
['0.04984', '93.42']],
'checksum': 0,
'ts': '1707929251792'}],
'ts': 1707929251792}
df = pd.json_normalize(data, 'data', 'arg')
df['arg'] = df['arg'].str['instId']
asks = df['asks']
bids = df['bids']
for i in asks[0]:
for j in i:
fl = float(j)
arr_asks.append(fl)
if len(arr_asks) == 2:
elem = math.prod(arr_asks)
arr_asks.clear()
all_amount.append(elem)
for i in bids[0]:
for j in i:
fl = float(j)
arr_bids.append(fl)
if len(arr_bids) == 2:
elem = math.prod(arr_bids)
all_amount.append(elem)
arr_bids.clear()
df1 = (pd.DataFrame(all_amount,
columns=['amount'])
.assign(Time_ms=df.iloc[0]['ts'], Ticker=df.iloc[0]['arg'])).query('amount >30')
df1['Time_ms'] = pd.to_datetime(df1['Time_ms'],unit='ms').dt.time
print(df1)
результат должен быть такой:
amount Time_ms Ticker
5 388.114491 16:47:19.552 DCKUSDT
7 31.701696 16:47:19.552 DCKUSDT
или такой:
amount Time_ms Ticker
5 388.114491 16:47:19 DCKUSDT
7 31.701696 16:47:19 DCKUSDT
Ответы (2 шт):
Автор решения: user453575457
→ Ссылка
Вы можете средствами pandas выполнить функцию на двух колонках, например перемножение двух колонок выглядит так:
def f(x):
return x[0]*x[1]
df.apply(f, axis=1)
Автор решения: Алексей Р
→ Ссылка
- "Взрываем" списки списков в столбцах 'asks', 'bids' - получаем несколько строк со списками по 2 элемента. Предположил, что списки в 'asks', 'bids' одинаковой длины, поэтому "взорвал" синхронно. Далее преобразуем 'asks', 'bids' во фреймы, чтобы получить по 2 столбца, их переводим во float и перемножаем и сохраняем обратно как 'asks', 'bids'. После чего, чтобы выбрать из двух столбцов >30, "расплавляем" (melt) фрейм и фильтруем. Выбираем нужные столбцы и печатаем.
- Доли секунд обнуляем
dt.floor('s'). - При преобразовании ts обратите внимание на FutureWarning: The behavior of 'to_datetime' with 'unit' when parsing strings is deprecated. In a future version, strings will be parsed as datetime strings, matching the behavior without a 'unit'. To retain the old behavior, explicitly cast ints or floats to numeric type before calling to_datetime.. Но если перевести ts предварительно в числовой тип
pd.to_numeric(df['ts']), получается не16:47:19, а16:47:31
df = pd.json_normalize(data, 'data', 'arg')
df['Ticker'] = df['arg'].str['instId']
df['Time_ms'] = pd.to_datetime(df['ts'], unit='ms').dt.floor('s').dt.time
df = df.explode(['asks', 'bids'], ignore_index=True)
df[['asks', 'bids']] = df[['asks', 'bids']].apply(lambda x: pd.DataFrame(x.tolist()).astype(float).prod(axis=1))
df = df.melt(id_vars=['Ticker', 'Time_ms'], value_vars=['asks', 'bids'], value_name='amount').query('amount>30')[['amount', 'Time_ms', 'Ticker']]
print(df)
amount Time_ms Ticker
5 388.114491 16:47:19 DCKUSDT
7 31.701696 16:47:19 DCKUSDT