【问题标题】:SAS maximize a function of variablesSAS最大化变量的函数
【发布时间】:2017-01-13 11:35:58
【问题描述】:

给定一组变量v(1) - v(k),函数f定义为f(v1,v2,...vk)

目标是在给定v(1)+v(2)+....+v(k)=n 的情况下拥有一组最大化f 的v(i)。所有元素都限制为非负整数。

注意:我没有SAS/IMLSAS/OR

如果知道k,比如2,那么我可以这样做。

data out;
    set in;
    maxf = 0;
    n1 = 0;
    n2 = 0;
    do i = 0 to n;
        do j = 0 to n;
            if i + j ne n then continue;
            _max = f(i,j);
            if _max > maxf then do;
                maxf = max(maxf,_max);
                n1 = i;
                n2 = j;
            end;
        end;
    end;
    drop i j;
run;

但是,这个解决方案有几个问题。

  1. 使用循环似乎效率很低。

  2. 当 k 未知时,它不知道如何需要嵌套循环。

这正是“将 n 个球分配到 k 个容器中”的问题,其中 k 由具有特定前缀的数据 in 中的列数确定,n 由宏变量确定。

函数f是已知的,例如f(i,j) = 2*i+3*j

这可以在数据步骤中完成吗?

【问题讨论】:

  • f 总是变量的线性函数吗?如果是这样,我建议使用 SAS 将问题导出到另一个应用程序,例如 lpsolve,而不是重新发明轮子。
  • @user667489 不幸的是没有......这是我想知道这个问题是否可以解决的部分原因......
  • SCIP 或许可以解决这个问题
  • 你有 SAS/STAT 还是 SAS/ETS?
  • @dompazz 不是 ets。但是你能解释一下 ets 是如何做到的吗?

标签: sas


【解决方案1】:

正如 cmets 中所说,一般的非线性整数程序很难求解。下面的方法将求解连续参数。您将必须获取输出并找到最接近的整数值以最大化您的功能。但是,现在循环将变得更小,运行起来也更快。

首先让我们创建一个函数。这个函数有一个额外的参数并且在那个参数中是线性的。将你的函数包装在这样的东西中。

proc fcmp outlib=work.fns.fns;
function f(x1,x2,a);
    out = -10*(x1-5)*(x1-5) + -2*(x2-2)*(x2-2) + 2*(x1-5) + 3*(x2-2);
    return(out+a);
endsub;
run;quit;

options cmplib=work.fns;

我们需要添加a参数,这样我们就可以拥有一个SAS可以传递的值,除了实际的参数。 SAS 会认为它正在解决A 的可能性,基于x1x2

生成具有A 值的数据集。

data temp;
a = 1;
run;

现在使用PROC NLMIXED 来最大化A 的可能性。

ods output ParameterEstimates=Parameters;
ods select ParameterEstimates;

proc nlmixed data=temp;
parms x1=1 x2=1;
bounds x1>0, x2>0;

y = f(x1,x2,a);

model a ~ general(y);
run;

ods select default;

我得到x1=5.1x2=2.75 的输出。然后,您可以搜索“周围”以查看最大值出现在哪里。

这是我在数据步骤中搜索值的尝试:

%macro call_fn(fn,n,parr);
%local i;
&fn(&parr[1]
%do i=2 %to &n;
    , &parr[&i]
%end;
,0)
%mend;

%let n=2;
%let c=%sysevalf(2**&n);

data max;
set Parameters end=last;
array parms[&n] _temporary_;
array start[&n]  _temporary_;
array pmax[&n];
max = -9.99e256;

parms[_n_] = estimate;

if last then do;
    do i=1 to &n;
        start[i] = floor(parms[i]);
    end;

    do i=1 to &c;
        x = put(i,$binary2.);
        do j=1 to &n;
            parms[j] = input(substr(x,j,1),best.) + start[j];
        end;


        /*You need a macro to write this dynamically*/
        val = %call_fn(f,&n,parms);

        *put i= max= val=;
        if val > max then do;
            do j=1 to &n;
                pmax[j] = parms[j];
            end;
            max = val;
        end;
    end;
    output;
end;

【讨论】:

  • 有趣的解决方案。对于最大似然部分,我需要查看教科书以获取详细信息,现在不记得其背后的逻辑了..但我认为一旦有了连续解,找到最接近的整数应该很容易。我还有两个问题。 1.在第一部分,proc nlmixed不保证x之和等于n。你把它留到第二部分吗? 2.不明白 substr 部分是如何工作的..
  • 我没有看到 sum(x) = n 的约束。我将不得不看看如何实现它。 substr() 部分有效,因为我在解 (2^n) 周围取了 C 个整数。我数到 C,将数字转换为二进制字符串——即 2 = 10。然后我使用 substr() 函数获取该字符串中的第 j 个值并将其添加到起始值。这为我提供了一种简单的方法来确保将 0 和 1 的所有组合添加到起始值。
  • 不要担心可能性部分。它只是最大化一个函数。
  • NLMIXED 没有约束,因此我可以强制 sum(x)=n。 SAS/ETS 中的 PROC MODEL 将允许这样做。
  • 我认为 sum(x)
猜你喜欢
  • 2017-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-08
  • 1970-01-01
  • 2021-12-18
  • 2021-06-18
  • 1970-01-01
相关资源
最近更新 更多