BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
JoshuaHarris
Obsidian | Level 7
I have an "amount" column in a dataset which has several positive and negative values. I want to create one output which has same positive and negative numbers(eg: - 56,56,-72,72) and another output(excludes the data in first output) which has total values of any combination of positive and negative numbers equals to 0. (eg:, -5,-10,15), (-90,10,-5,85).. Is it possible to do this in SAS.. Please suggest..
1 ACCEPTED SOLUTION

Accepted Solutions
RobPratt
SAS Super FREQ

The following code uses PROC OPTMODEL in SAS/OR or SAS Optimization to maximize the number of zero-sum groups:

data have;
   input amount;
   datalines;
-56
76
10
-76
56
20
-45
-3
15
-35
40
4
4
;

proc optmodel;
   /* declare parameters and read input data set */
   set OBS;
   num amount {OBS};
   read data have into OBS=[_N_] amount;
   num numGroups = card(OBS)/2;
   set GROUPS = 1..numGroups;
   
   /* declare decision variables */
   var UseGroup {GROUPS} binary;
   var Assign {OBS, GROUPS} binary;

   /* declare objective */
   max NumGroupsUsed = sum {g in GROUPS} UseGroup[g];

   /* declare constraints */
   con OneGroupPerObs {i in OBS}:
      sum {g in GROUPS} Assign[i,g] <= 1;
   con GroupSumZero {g in GROUPS}:
      sum {i in OBS} amount[i] * Assign[i,g] = 0;
   con AssignImpliesUse {i in OBS, g in GROUPS}:
      Assign[i,g] <= UseGroup[g];
   con UseImpliesAssign {g in GROUPS}:
      2*UseGroup[g] <= sum {i in OBS} Assign[i,g];
   con Symmetry {g in GROUPS diff {1}}:
      UseGroup[g] <= UseGroup[g-1];

   /* call MILP solver */
   solve;

   /* create output data set */
   num assignedGroup {OBS};
   for {i in OBS} do;
      for {g in GROUPS: Assign[i,g].sol > 0.5} do;
         assignedGroup[i] = g;
         leave;
      end;
   end;
   create data want from [i] amount assignedGroup;
quit;

The resulting optimal solution has 4 groups:

Obs i amount assignedGroup
1 1 -56 4
2 2 76 2
3 3 10 .
4 4 -76 2
5 5 56 4
6 6 20 3
7 7 -45 1
8 8 -3 1
9 9 15 3
10 10 -35 3
11 11 40 1
12 12 4 1
13 13 4 1

 

See also Solved: Net Groups of Lines in a Table to $0.00 - SAS Support Communities for an alternative greedy approach.

View solution in original post

8 REPLIES 8
PeterClemmensen
Tourmaline | Level 20

Can you provide some sample data and an explanation from that?

JoshuaHarris
Obsidian | Level 7
Sure. Please find below the sample data
Amount_column
-56
76
10
-76
56
20
-45
-3
15
-35
40
4
4
First output should hv
Amount_col
-56
56
76
-76

Second output should have
Flag amount_col
A 10
A 20
A 15
A - 45
B 40
B 4
B 4
B - 45
B - 3
if you sum all A, then it will b 0 and if you sum all B, it will be 0..(offset)
Or even one output will be better
Flag amount_col
Zero 56
Zero -56
Zero - 76
Zero 76
A 10
A 20
A 15
A - 45
B 40
B 4
B 4
B - 45
B - 3
PeterClemmensen
Tourmaline | Level 20

Ok. The first output is quite simple.

 

Regaring the second output.. Do you want ALL combinations of values that equal zero when summed?

JoshuaHarris
Obsidian | Level 7
Yes all combinations of values(positive and negative) that equal to 0 but once we identified a set of numbers thats sum is 0,that number/row item shouldn't be used again
Ksharp
Super User

I think you can't get job done simply by data step code.

You need SAS/OR to solve this kind of question.

Post it at OR forum 

https://communities.sas.com/t5/Mathematical-Optimization/bd-p/operations_research

 

And calling out @RobPratt 

RobPratt
SAS Super FREQ

The following code uses PROC OPTMODEL in SAS/OR or SAS Optimization to maximize the number of zero-sum groups:

data have;
   input amount;
   datalines;
-56
76
10
-76
56
20
-45
-3
15
-35
40
4
4
;

proc optmodel;
   /* declare parameters and read input data set */
   set OBS;
   num amount {OBS};
   read data have into OBS=[_N_] amount;
   num numGroups = card(OBS)/2;
   set GROUPS = 1..numGroups;
   
   /* declare decision variables */
   var UseGroup {GROUPS} binary;
   var Assign {OBS, GROUPS} binary;

   /* declare objective */
   max NumGroupsUsed = sum {g in GROUPS} UseGroup[g];

   /* declare constraints */
   con OneGroupPerObs {i in OBS}:
      sum {g in GROUPS} Assign[i,g] <= 1;
   con GroupSumZero {g in GROUPS}:
      sum {i in OBS} amount[i] * Assign[i,g] = 0;
   con AssignImpliesUse {i in OBS, g in GROUPS}:
      Assign[i,g] <= UseGroup[g];
   con UseImpliesAssign {g in GROUPS}:
      2*UseGroup[g] <= sum {i in OBS} Assign[i,g];
   con Symmetry {g in GROUPS diff {1}}:
      UseGroup[g] <= UseGroup[g-1];

   /* call MILP solver */
   solve;

   /* create output data set */
   num assignedGroup {OBS};
   for {i in OBS} do;
      for {g in GROUPS: Assign[i,g].sol > 0.5} do;
         assignedGroup[i] = g;
         leave;
      end;
   end;
   create data want from [i] amount assignedGroup;
quit;

The resulting optimal solution has 4 groups:

Obs i amount assignedGroup
1 1 -56 4
2 2 76 2
3 3 10 .
4 4 -76 2
5 5 56 4
6 6 20 3
7 7 -45 1
8 8 -3 1
9 9 15 3
10 10 -35 3
11 11 40 1
12 12 4 1
13 13 4 1

 

See also Solved: Net Groups of Lines in a Table to $0.00 - SAS Support Communities for an alternative greedy approach.

PeterClemmensen
Tourmaline | Level 20

@RobPratt, if I could push the 'like' button more than once, I would.

JoshuaHarris
Obsidian | Level 7
Thanks a lot for your speedy response and help

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 8 replies
  • 1796 views
  • 6 likes
  • 4 in conversation