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 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

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