在Pandas数据框上使用scipy.optimize

3

我试图搜索它,但结果不佳。

有人能否请解释一下如何在Pandas DataFrame上执行optimize.minimize,以便将DataFrame中的类别与结果列之间的误差最小化?

考虑以下示例:

import pandas as pd

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]})

对于每个 cat1、cat2、cat3、dog1、dog2 和 dog3,我想找到使此方程最小的值:

import numpy as np

np.average(np.abs(df['result'] - ('min for values in cat column * min for values in dog column'))) / np.average(df['result'])

我可以使用Excel中的Solver进行复制。
prod    cat     dog result  cat*dog abs
prod1   cat1    dog1    20  17.38   2.61
prod2   cat1    dog2    10  27.34   17.35
prod3   cat2    dog1    30  26.91   3.09
prod4   cat2    dog2    50  42.32   7.67
prod5   cat3    dog2    45  45.00   0.00
prod6   cat1    dog3    120 20.64   99.36

因此,我试图找到的最终得分是:

22个平均绝对值 / 45.83个平均结果 = 0.47

这些是Solver为动物返回的值:

cat1    3.59194254
cat2    5.559980313
cat3    5.91078751
dog1    4.840109868
dog2    7.613201994
dog3    5.746396256

我该如何在Python中复制这个操作?
1个回答

4
您需要定义一个函数,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 函数 - 第一个参数是一个具有一些数值的一维数组(根据 optimize 的要求)。第二个参数是这些数组数值对应的字符串,第三个参数是你的数据框。大部分代码都是将你的数据框字符串转换为可计算的值。
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

我认为你的成本函数描述可能有点不准确,所以你需要进行调整。


如何确定“合理的初始值”?顺便说一句,谢谢! :) - aaa
2
@Jurek 由于您的成本函数为 (r - xy)/r,而成本函数的理想值为0,因此我认为 (r - x0*x0)/r = 0 (x0 = sqrt(r)) 是一个很好的起点。老实说,问10个人,可能会得到10个不同的答案。 - CJR
我有一个非常类似的问题,您能否帮助我使用优化器函数来尝试最大化一个函数(-fun)? - Stephan Kokkas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接