Оптимизация и поиск максимального значения в пределах Pandas Df путем объединения значений строк - PullRequest
1 голос
/ 18 апреля 2020

У меня есть следующее df:

level   type  price1    price2
5250    A   0.233   0.2865
5250    B   0.004   0.006
5500    A   0.197   0.2545
5500    B   0.0055  0.0075
5750    A   0.1615  0.223
5750    B   0.0075  0.009
6000    A   0.127   0.1925
6000    B   0.0105  0.0125
6250    A   0.1215  0.1635
6250    B   0.0135  0.0165
6500    A   0.099   0.136
6500    B   0.021   0.024
6750    A   0.071   0.085
6750    B   0.03    0.0325
7000    A   0.052   0.0555
7000    B   0.044   0.047
7250    A   0.036   0.0395
7250    B   0.063   0.0675
7500    A   0.024   0.0275
7500    B   0.086   0.091
7750    A   0.0165  0.019
7750    B   0.111   0.161
8000    A   0.0105  0.0135
8000    B   0.118   0.1915
8250    A   0.0085  0.0105
8250    B   0.137   0.224
8500    A   0.0055  0.008
8500    B   0.1835  0.257
8750    A   0.0045  0.0065
8750    B   0.2035  0.291
9000    A   0.0035  0.0055
9000    B   0.002   1.956

Я делю df на df_A и df_B на основе столбца type. Далее я хочу найти объединенные уровни / строки, чтобы максимизировать следующее:

sum = buy_A + buy_B - sell_A - sell_B 

, где

buy_A = df_A.loc[row, 'price2']
buy_B = df_B.loc[row, 'price2']
sell_A = df_A.loc[row, 'price1']
sell_B = df_B.loc[row, 'price1']

Я использую здесь row для ясности, но в моем сценарии row должно быть равно значению столбца level. У меня есть ограничение. Для buy_A и sell_B значение level должно быть равно, а для sell_A и buy_B значение level должно быть равно. В том числе это приводит к:

buy_A = float(df_A.loc[(df_A['level'] == level_1), 'price2'])
buy_B = float(df_B.loc[(df_B['level'] == level_2), 'price2'])
sell_A = float(df_A.loc[(df_A['level'] == level_1), 'price1'])
sell_B = float(df_B.loc[(df_B['level'] == level_2), 'price1'])

В основном, для вышеупомянутого df я получаю следующую матрицу:

enter image description here

I хотел бы вернуть значение максимального значения в матрице и соответствующие уровни.

Мой сценарий:

import pandas as pd
import numpy as np
from scipy.optimize import minimize


def obj(x, df):
   df_A = df.loc[(df['type'] == 'A')]
   df_B = df.loc[(df['type'] == 'B')]
   sum = df_A['price1'] + df_B['price1'] - df_A['price2'] - df_B['price2']
   return -1 * sum


if __name__ == "__main__":
   df = pd.read_csv('quotes.csv')
   guess = 0
   solver = minimize(obj, args=(df), x0=guess, method='Nelder-Mead', options={'disp': True})

Что мне нужно изменить, чтобы получить максимальное значение и соответствующие уровни? Большое спасибо заранее

1 Ответ

0 голосов
/ 18 апреля 2020

Поскольку sum является встроенной функцией в Python, я бы хотел заменить ее на z. И поскольку у вас есть ограничение на то, что level будет идентичным в (buy_A, sell_B), а также (sell_A, buy_B), давайте изменим ваше уравнение, чтобы сделать это более понятным:

z = buy_A + buy_B - sell_A - sell_B 
  = (buy_A - sell_B) + (buy_B - sell_A)
  = x + y

Давайте углубимся в ваш вопрос. Первое, что мы делаем, это переформатируем исходный фрейм данных для выравнивания уровней:

tmp = df.rename({'price1': 'sell', 'price2': 'buy'}, axis=1) \
        .set_index(['level', 'type']) \
        .unstack()

# tmp:
         sell             buy        
type        A       B       A       B
level                                
5250   0.2330  0.0040  0.2865  0.0060
5500   0.1970  0.0055  0.2545  0.0075
5750   0.1615  0.0075  0.2230  0.0090
6000   0.1270  0.0105  0.1925  0.0125
6250   0.1215  0.0135  0.1635  0.0165

Затем вычисляем наши x и y:

x = tmp[('buy', 'A')] - tmp[('sell', 'B')]
y = tmp[('buy', 'B')] - tmp[('sell', 'A')]

Далее нам нужно рассчитать z. z не просто x + y, но каждое значение в x добавляется к каждому значению в y; следовательно, z является квадратной матрицей. Но нам не нужна вся матрица. Нам нужен только треугольник ниже главной диагональной линии. Модуль numpy.ma предоставляет функции для замаскированных массивов, где мы можем пометить определенные элементы, как если бы они не существовали.

import numpy.ma as ma

# Mask away the upper triangle, including the main diagonal
# len(x) == len(y)
mask = np.triu(np.ones((len(x), len(y))))

# Use numpy broadcasting to add every value in `x` to every value in `y`
# `x` and `y` are pandas Series. `.values` get the underlying numpy array
#
# `y.values[:, None]` raises `y` to another dimension. This is what
# triggers numpy's array broadcasting and make `z` a square matrix
z = -ma.array(x.values + y.values[:, None], mask=mask)

# If you want to visualize `z`, type this into the debugger
# pd.DataFrame(z, index=tmp.index, columns=tmp.index)

Последний шаг - получить уровни, которые дают максимальное значение при сложении вместе. Если есть несколько ячеек с максимальным значением, будет получена только первая:

i,j = np.unravel_index(z.argmax(), z.shape)

# The level with the max sum
level1, level2 = tmp.index[[i,j]]   # 7250, 7000

# The max value of the sums
z[i,j]                              # -0.043
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...