Вам нужно определить функцию, которую можно запустить optimize.minimize
(чтобы она знала, что пытается минимизировать).
import pandas as pd
import numpy as np
from scipy import optimize
df = pd.DataFrame({'prod': ['prod1', 'prod2', 'prod3', 'prod4', 'prod5', 'prod6'],
'cat': ['cat1', 'cat1', 'cat2', 'cat2', 'cat3', 'cat1'],
'dog': ['dog1', 'dog2', 'dog1', 'dog2', 'dog2', 'dog3'],
'result': [20, 10, 30, 50, 45, 120]})
Итак, давайте определим функцию animal_error, как вы описали - перваяАргумент - это массив 1d с некоторым количеством значений (как требуется для оптимизации).Второй аргумент - это соответствующие строки для этих значений массива, а третий аргумент - ваш фрейм данных.Большая часть этого кода просто превращает ваши строки данных в значения, которые можно вычислить.
def animal_error(val, animal, df):
assert len(val) == len(animal)
lookup = dict()
for i in range(len(val)):
lookup[animal[i]] = val[i]
df = df.replace(lookup)
error = np.abs(df['result'] - np.multiply(df['cat'], df['dog']))
return np.mean(error) / np.mean(df['result'])
Теперь вы можете превратить строки в массив:
animals = np.concatenate([df['dog'].unique(), df['cat'].unique()])
Установить разумный начальный аргументзначение для решателя:
initial = np.repeat(np.sqrt(df['result'].mean()), animals.size)
И запустить минимизатор:
res = optimize.minimize(animal_error, args=(animals, df), x0=initial, method = 'Nelder-Mead', options={'maxiter':10000})
res_df = pd.DataFrame({'animal': animals, 'min_val':res.x})
Конечный результат следующий:
>>> res.fun
0.08676411624175694
animal min_val
0 dog1 3.754194
1 dog2 5.296533
2 dog3 22.526566
3 cat1 5.327044
4 cat2 9.307979
5 cat3 8.496109
Я думаю, что ваше описание функции стоимости можетбыть немного не в себе, поэтому вам, возможно, придется настроить его.