<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Creating Groups of Equal Size in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268985#M269404</link>
    <description>&lt;PRE&gt;
OK. Here is what I got.
Assuming you want compare sum of each group(all data of each group) .
It looks like the minimize difference of sum between groups is 1 (divide into 4 groups).
Maybe some SAS/OR guys could offer you some OR code. 


data have;
input x y z;
obs+1;
datalines;
10 15 8
11 14 9
12 16 10
9 16 8
8 12 10
8 10 11
11 14 12
13 10 9
8 16 15
10 11 8
11 15 14
16 13 10
10 15 14
12 8 14
7 12 13
9 14 10
;
run;



proc iml;
use have;
read all var {x y z} into age[c=vname] ;
read all var {obs};
close ;

start function(x) global(age,group,nrow);
if ncol(x) ^= ncol(unique(x)) then x=ranperm(nrow,1);
y=shape(x,group,0,0);
sum_group=j(group,1,.);

do i=1 to group;
 sum_group[i]=age[y[i,],][+];
end;
obj=range(sum_group);
return (obj);
finish;

start switch_mut(s) global(nswitches,nrow);
if ncol(s) ^= ncol(unique(s)) then s=ranperm(nrow,1);
else do;
  n = ncol(s);
  do i = 1 to nswitches;
   k1 = int(uniform(1234)*n) + 1;
   k2 = int(uniform(1234)*n) + 1;
   if k1^=k2 then do;
    temp=s[k2];
    s[k2] = s[k1];
    s[k1] = temp;
   end;
  end;
end;
finish;

start uniform_cross(child1, child2, parent1, parent2) global(nrow);

child1 = parent1;
child2 = parent2;
do i = 1 to ncol(parent1);
  r = uniform(1234);
  if r&amp;lt;=0.5 then do;
   child1[i] = parent2[i];
   child2[i] = parent1[i];
  end;
end;

if ncol(child1) ^= ncol(unique(child1)) then child1=ranperm(nrow,1);
 else if ncol(child2) ^= ncol(unique(child2)) then child2=ranperm(nrow,1);

finish;



nrow=nrow(age);
group=4;  /*divide into 4 groups*/
nswitches = 3;
encoding=j(2,nrow,1);
encoding[2,]=nrow;    

id=gasetup(2,nrow,1234);
call gasetobj(id,0,"function");
call gasetcro(id,0.95,0,"uniform_cross");
call gasetmut(id,0.95,0,"switch_mut");
call gasetsel(id,100,1,1);
call gainit(id,1000,encoding);


niter = 10000;
do i = 1 to niter;
 call garegen(id);
 call gagetval(value, id);
end;
call gagetmem(mem, value, id, 1);


y=shape(mem,group,0,0);
sum_group=j(group,2,.);
do i=1 to group;
 sum_group[i,1]=i;
 sum_group[i,2]=age[y[i,],][+];
end;
Memebers=colvec(row(y))||obs[mem,]||age[mem,];
vnames={group obs}||vname;
print "Members:" Memebers[c=vnames],
      "Group sum:" sum_group[c={group sum}],
      "Min Value: " value[l = ""] ;
call gaend(id);
quit;










OUTPUT:
 	
GROUP OBS	x	y	z
	1	4	9	16	8
 	1	16	9	14	10
 	1	11	11	15	14
 	1	8	13	10	9
 	2	13	10	15	14
 	2	5	8	12	10
 	2	10	10	11	8
 	2	9	8	16	15
 	3	12	16	13	10
 	3	6	8	10	11
 	3	7	11	14	12
 	3	1	10	15	8
 	4	14	12	8	14
 	4	2	11	14	9
 	4	15	7	12	13
 	4	3	12	16	10


GROUP	SUM
	1	138
 	2	137
 	3	138
 	4	138

Min Value:	1

&lt;/PRE&gt;</description>
    <pubDate>Sat, 07 May 2016 08:54:45 GMT</pubDate>
    <dc:creator>Ksharp</dc:creator>
    <dc:date>2016-05-07T08:54:45Z</dc:date>
    <item>
      <title>Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268862#M269392</link>
      <description>&lt;P&gt;Hello,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I'm trying to create 4 equal groups(or close to equal - doesn't have to be exact) using the data below as an example. What I would like to accomplish is have the 4 groups have similar means (or sums) of all the variables. So basically I'm trying to minimize the mean, or sum, difference between the groups.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I'm trying to create a generic template also for the code, so there could be cases where there are 2,4, or other number of groups, and could also have more variables to average or sum, if you want to keep this in mind when thinking of the solution...I would like it to be as dynmaic as possible.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Any advice is appreciated!&lt;/P&gt;
&lt;P&gt;Thanks,&lt;/P&gt;
&lt;P&gt;Tom&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;BR /&gt;data have;&lt;BR /&gt;&amp;nbsp;&amp;nbsp; input x y z;&lt;BR /&gt;&amp;nbsp;&amp;nbsp; datalines;&lt;BR /&gt;10 15 8&lt;BR /&gt;11 14 9&lt;BR /&gt;12 16 10&lt;BR /&gt;9 16 8&lt;BR /&gt;8 12 10&lt;BR /&gt;8 10 11&lt;BR /&gt;11 14 12&lt;BR /&gt;13 10 9&lt;BR /&gt;8 16 15&lt;BR /&gt;10 11 8&lt;BR /&gt;11 15 14&lt;BR /&gt;16 13 10&lt;BR /&gt;10 15 14&lt;BR /&gt;12 8 14&lt;BR /&gt;7 12 13&lt;BR /&gt;9 14 10&lt;BR /&gt;;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The "want" dataset would simply be the one from above with a "groupID" variable next to each one.&lt;/P&gt;</description>
      <pubDate>Fri, 06 May 2016 17:24:33 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268862#M269392</guid>
      <dc:creator>triley</dc:creator>
      <dc:date>2016-05-06T17:24:33Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268865#M269393</link>
      <description>&lt;P&gt;Would you expect some of the GroupId to be missing for some obs that don't belong to any group?&lt;/P&gt;</description>
      <pubDate>Fri, 06 May 2016 17:45:32 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268865#M269393</guid>
      <dc:creator>PGStats</dc:creator>
      <dc:date>2016-05-06T17:45:32Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268866#M269394</link>
      <description>&lt;P&gt;no, I would expect every observation to have a GroupID&lt;/P&gt;</description>
      <pubDate>Fri, 06 May 2016 17:47:07 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268866#M269394</guid>
      <dc:creator>triley</dc:creator>
      <dc:date>2016-05-06T17:47:07Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268869#M269395</link>
      <description>&lt;P&gt;To minimize the difference of&amp;nbsp;means or other statistic of mulltiple variables simulaneously is likely to be difficult exercise.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here is a grouping approach that might work for some purposes. If the order of the varaibles is reasonally random the means or such should be somewhat similar for large enough data sets. This does have the advantage of simplicity and extensibility&amp;nbsp;if not precision:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Data want;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp; Set have;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp; GroupId = mod(_n_,4);&lt;/P&gt;
&lt;P&gt;run;&lt;/P&gt;
&lt;P&gt;This approach does mean that the largest difference in size of groups should be one (some groups may have one more member than others).&lt;/P&gt;
&lt;P&gt;Note, your example data set is a bit small.&lt;/P&gt;</description>
      <pubDate>Fri, 06 May 2016 17:53:47 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268869#M269395</guid>
      <dc:creator>ballardw</dc:creator>
      <dc:date>2016-05-06T17:53:47Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268879#M269396</link>
      <description>&lt;P&gt;This seems to be a clustering problem. If you are okay with SAS/STAT try proc cluster or proc fastclus to assign a label to each observation.&lt;/P&gt;</description>
      <pubDate>Fri, 06 May 2016 18:47:20 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268879#M269396</guid>
      <dc:creator>stat_sas</dc:creator>
      <dc:date>2016-05-06T18:47:20Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268907#M269397</link>
      <description>&lt;P&gt;I would agree with&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/42042"&gt;@stat_sas﻿&lt;/a&gt;&amp;nbsp;that clustering would be a good approach. But getting equal sized groups might prove difficult. &amp;nbsp;A simpler approach would be, as &lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/13884"&gt;@ballardw﻿&lt;/a&gt;&amp;nbsp;suggest, to form equal-sized groups along a single variable. Make that variable the first principal component and you are in business:&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let vars=x y z;
%let nbGroups=2;

proc princomp data=have n=1 out=haveprin;
var &amp;amp;vars;
run;

proc rank data=haveprin groups=&amp;amp;nbGroups out=want(rename=prin1=groupId);
var prin1;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 06 May 2016 20:18:39 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268907#M269397</guid>
      <dc:creator>PGStats</dc:creator>
      <dc:date>2016-05-06T20:18:39Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268920#M269398</link>
      <description>&lt;P&gt;&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/462"&gt;@PGStats﻿&lt;/a&gt;: &amp;nbsp;Interesting approach. To learn more about this just a few&amp;nbsp;questions:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Why PCA with only one principal component?&lt;/P&gt;
&lt;P&gt;Why only two groups and are these&amp;nbsp;two groups sufficient to make sure&amp;nbsp;variation between groups is large enough to conclude that means are significantly different?&lt;/P&gt;</description>
      <pubDate>Fri, 06 May 2016 20:48:26 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268920#M269398</guid>
      <dc:creator>stat_sas</dc:creator>
      <dc:date>2016-05-06T20:48:26Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268927#M269399</link>
      <description>&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Oops! You make me realize that the ranking approach will &lt;STRONG&gt;maximize&lt;/STRONG&gt; the difference between group means, which is contrary to what is required.&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/13884"&gt;@ballardw﻿&lt;/a&gt;'s approach makes more sense.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let vars=x y z;
%let nbGroups=2;

proc princomp data=have n=1 out=haveprin;
var &amp;amp;vars;
run;

proc sort data=haveprin; by prin1; run;

data want;
set haveprin;
groupId = mod(_n_, &amp;amp;nbGroups);
drop prin1;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;But in the end, when you try to balance on many factors, it may be safer to use simple randomisation.&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 06 May 2016 21:15:04 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268927#M269399</guid>
      <dc:creator>PGStats</dc:creator>
      <dc:date>2016-05-06T21:15:04Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268930#M269400</link>
      <description>&lt;P&gt;Still not significantly different:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;proc glm data=want;&lt;BR /&gt;class groupid;&lt;BR /&gt;model x y z=groupid;&lt;BR /&gt;run;&lt;/P&gt;</description>
      <pubDate>Fri, 06 May 2016 21:25:51 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268930#M269400</guid>
      <dc:creator>stat_sas</dc:creator>
      <dc:date>2016-05-06T21:25:51Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268940#M269401</link>
      <description>&lt;P&gt;I suspect a wizard in the IML world might already have an n-dimension difference minimization program but my head started hurting very briefly&amp;nbsp;after contemplating that, especially with the "equal group size" requirement. I figured out pretty quickly I could likely build a data set that would cause issues for any given group size.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;It might be time for Triley to expand on the uses of the data after the groupid is added.&lt;/P&gt;</description>
      <pubDate>Fri, 06 May 2016 22:05:23 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268940#M269401</guid>
      <dc:creator>ballardw</dc:creator>
      <dc:date>2016-05-06T22:05:23Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268963#M269402</link>
      <description>&lt;PRE&gt;
It is more like a SAS/OR problem . Can you post it at OR forum.
And Can you explain this " 4 groups have similar means (or sums) of all the variables. ". 
Give us a simple example to explain that. How you calculated these sums, 
sum of all data of each group ? or sum of each variable ?

Here is an example solution by Genetic Algorithm . 
This is example only have a variable( AGE ),and take dataset sashelp.class as for example.
Maybe I should call some OR guys to take a look at this question.




proc iml;
use sashelp.class;
read all var {age} ;
close ;

start function(x) global(age,group);
if ncol(x) ^= ncol(unique(x)) then obj=9999999;
else do;
 y=age[x,];
 obj=range(shape(y,group,0,0)[,+]);
end;
 return (obj);
finish;

start switch_mut(s) global(nswitches,nrow);
if ncol(s) ^= ncol(unique(s)) then s=ranperm(nrow,1);
else do;
  n = ncol(s);
  do i = 1 to nswitches;
   k1 = int(uniform(1234)*n) + 1;
   k2 = int(uniform(1234)*n) + 1;
   if k1^=k2 then do;
    temp=s[k2];
    s[k2] = s[k1];
    s[k1] = temp;
   end;
  end;
end;
finish;

start uniform_cross(child1, child2, parent1, parent2) global(nrow);

child1 = parent1;
child2 = parent2;
do i = 1 to ncol(parent1);
  r = uniform(1234);
  if r&amp;lt;=0.5 then do;
   child1[i] = parent2[i];
   child2[i] = parent1[i];
  end;
end;

if ncol(child1) ^= ncol(unique(child1)) then child1=ranperm(nrow,1);
 else if ncol(child2) ^= ncol(unique(child2)) then child2=ranperm(nrow,1);

finish;



nrow=nrow(age);
group=4;
nswitches = 3;
encoding=j(2,nrow,1);
encoding[2,]=nrow;    

id=gasetup(2,nrow,1234);
call gasetobj(id,0,"function");
call gasetcro(id,0.95,0,"uniform_cross");
call gasetmut(id,0.95,0,"switch_mut");
call gasetsel(id,100,1,1);
call gainit(id,1000,encoding);


niter = 10000;
summary = j(niter,2);
mattrib summary [c = {"Min Value", "Avg Value"} l=""];
do i = 1 to niter;
 call garegen(id);
 call gagetval(value, id);
 summary[i,1] = value[1];
 summary[i,2] = value[:];
end;
call gagetmem(mem, value, id, 1);


Memebers=shape(age[mem,],group,0,0);
print "Members:" Memebers[l=""],
      "Group sum:" (Memebers[,+]),
      "Min Value: " value[l = ""] ;
call gaend(id);
quit;




OUTPUT:
Members:	
        13	12	14	11	14
 	11	15	14	12	12
 	13	13	12	12	14
 	15	16	15	15	0
Group sum:	
        64
 	64
 	64
 	61
Min Value:	
        3



&lt;/PRE&gt;</description>
      <pubDate>Sat, 07 May 2016 03:01:22 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268963#M269402</guid>
      <dc:creator>Ksharp</dc:creator>
      <dc:date>2016-05-07T03:01:22Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268970#M269403</link>
      <description>&lt;P&gt;Here is a flexible (maybe too flexible &lt;img id="smileyhappy" class="emoticon emoticon-smileyhappy" src="https://communities.sas.com/i/smilies/16x16_smiley-happy.png" alt="Smiley Happy" title="Smiley Happy" /&gt;) approach to the problem of creating groups of equal sizes, means and variances. The idea is to create some well balanced experimental groups.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;/* Goal : divide data into equal size groups with similar means 
 and variances and define clusters of matched observations */
/* Example data, including id */
data have;
length id $8;
input x y z;
id = cats("OBS_", _n_);
datalines;
10 15 8
11 14 9
12 16 10
9 16 8
8 12 10
8 10 11
11 14 12
13 10 9
8 16 15
10 11 8
11 15 14
16 13 10
10 15 14
12 8 14
7 12 13
9 14 10
;

/* Number of groups to form */
%let nbGroups=4;

/* Define a distance between observations. Here I use the Chebychev 
 distance which is the maximum difference Dx, Dy, or Dz between the 
 standardized variables */ 
proc distance data=have method=Chebychev out=haveDist;
var interval(x y z / std=STD);
id id;
run;

/* Multidimentional scaling: Derive a single variable that approximates 
 the distances between observations. */ 
proc mds data=haveDist dimension=1 
    out=haveScaled(where=(_TYPE_="CONFIG")) 
    plots=none nophist; run;

/* Order observations by the new variable */
proc sort data=haveScaled; by dim1; run;

/* Define clusters of close by observations. Within clusters, assign observations 
 to separate groups. Do this assignment in a random order. Clusters could be used 
 to implement pairing. */
data haveGroups;
array grp grp1-grp&amp;amp;nbGroups (1 : &amp;amp;nbGroups);
seed = 8568;
do until (done);
    clusterId + 1;
    call ranperm(seed, of grp{*});
    do i = 1 to &amp;amp;nbGroups until(done);
        set haveScaled end=done;
        groupId = grp{i};
        output;
        end;
    end;
keep _name_ groupId clusterId;
run;

/* Rejoin the group assignments with original data, using id */
proc sql;
create table want as
select 
    input(scan(id, 2, "_"), best.) as obs,
    have.*, 
    haveGroups.groupId,
    haveGroups.clusterId
from 
    have inner join 
    haveGroups on have.id=haveGroups._NAME_
order by obs;
quit;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Sat, 07 May 2016 05:25:07 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268970#M269403</guid>
      <dc:creator>PGStats</dc:creator>
      <dc:date>2016-05-07T05:25:07Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268985#M269404</link>
      <description>&lt;PRE&gt;
OK. Here is what I got.
Assuming you want compare sum of each group(all data of each group) .
It looks like the minimize difference of sum between groups is 1 (divide into 4 groups).
Maybe some SAS/OR guys could offer you some OR code. 


data have;
input x y z;
obs+1;
datalines;
10 15 8
11 14 9
12 16 10
9 16 8
8 12 10
8 10 11
11 14 12
13 10 9
8 16 15
10 11 8
11 15 14
16 13 10
10 15 14
12 8 14
7 12 13
9 14 10
;
run;



proc iml;
use have;
read all var {x y z} into age[c=vname] ;
read all var {obs};
close ;

start function(x) global(age,group,nrow);
if ncol(x) ^= ncol(unique(x)) then x=ranperm(nrow,1);
y=shape(x,group,0,0);
sum_group=j(group,1,.);

do i=1 to group;
 sum_group[i]=age[y[i,],][+];
end;
obj=range(sum_group);
return (obj);
finish;

start switch_mut(s) global(nswitches,nrow);
if ncol(s) ^= ncol(unique(s)) then s=ranperm(nrow,1);
else do;
  n = ncol(s);
  do i = 1 to nswitches;
   k1 = int(uniform(1234)*n) + 1;
   k2 = int(uniform(1234)*n) + 1;
   if k1^=k2 then do;
    temp=s[k2];
    s[k2] = s[k1];
    s[k1] = temp;
   end;
  end;
end;
finish;

start uniform_cross(child1, child2, parent1, parent2) global(nrow);

child1 = parent1;
child2 = parent2;
do i = 1 to ncol(parent1);
  r = uniform(1234);
  if r&amp;lt;=0.5 then do;
   child1[i] = parent2[i];
   child2[i] = parent1[i];
  end;
end;

if ncol(child1) ^= ncol(unique(child1)) then child1=ranperm(nrow,1);
 else if ncol(child2) ^= ncol(unique(child2)) then child2=ranperm(nrow,1);

finish;



nrow=nrow(age);
group=4;  /*divide into 4 groups*/
nswitches = 3;
encoding=j(2,nrow,1);
encoding[2,]=nrow;    

id=gasetup(2,nrow,1234);
call gasetobj(id,0,"function");
call gasetcro(id,0.95,0,"uniform_cross");
call gasetmut(id,0.95,0,"switch_mut");
call gasetsel(id,100,1,1);
call gainit(id,1000,encoding);


niter = 10000;
do i = 1 to niter;
 call garegen(id);
 call gagetval(value, id);
end;
call gagetmem(mem, value, id, 1);


y=shape(mem,group,0,0);
sum_group=j(group,2,.);
do i=1 to group;
 sum_group[i,1]=i;
 sum_group[i,2]=age[y[i,],][+];
end;
Memebers=colvec(row(y))||obs[mem,]||age[mem,];
vnames={group obs}||vname;
print "Members:" Memebers[c=vnames],
      "Group sum:" sum_group[c={group sum}],
      "Min Value: " value[l = ""] ;
call gaend(id);
quit;










OUTPUT:
 	
GROUP OBS	x	y	z
	1	4	9	16	8
 	1	16	9	14	10
 	1	11	11	15	14
 	1	8	13	10	9
 	2	13	10	15	14
 	2	5	8	12	10
 	2	10	10	11	8
 	2	9	8	16	15
 	3	12	16	13	10
 	3	6	8	10	11
 	3	7	11	14	12
 	3	1	10	15	8
 	4	14	12	8	14
 	4	2	11	14	9
 	4	15	7	12	13
 	4	3	12	16	10


GROUP	SUM
	1	138
 	2	137
 	3	138
 	4	138

Min Value:	1

&lt;/PRE&gt;</description>
      <pubDate>Sat, 07 May 2016 08:54:45 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/268985#M269404</guid>
      <dc:creator>Ksharp</dc:creator>
      <dc:date>2016-05-07T08:54:45Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269012#M269405</link>
      <description>&lt;P&gt;Here's one way to minimize the range by using PROC OPTMODEL in SAS/OR:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data have;
   input x1-x3;
   datalines;
10 15 8
11 14 9
12 16 10
9 16 8
8 12 10
8 10 11
11 14 12
13 10 9
8 16 15
10 11 8
11 15 14
16 13 10
10 15 14
12 8 14
7 12 13
9 14 10
;

%let num_vars   = 3;
%let num_groups = 4;
proc optmodel;
   set VARS   = 1..&amp;amp;num_vars;
   set GROUPS = 1..&amp;amp;num_groups;
   set OBS;
   num a {OBS, VARS};
   read data have into OBS=[_N_] {j in VARS} &amp;lt;a[_N_,j]=col('x'||j)&amp;gt;;

   /* Assign[i,g] = 1 if observation i assigned to group g, 0 otherwise */
   var Assign {OBS, GROUPS} binary;

   con AssignOnce {i in OBS}:
      sum {g in GROUPS} Assign[i,g] = 1;

   con NearlyEqual {g in GROUPS}:
      floor(card(OBS)/&amp;amp;num_groups) &amp;lt;= sum {i in OBS} Assign[i,g] &amp;lt;= ceil(card(OBS)/&amp;amp;num_groups);

   impvar GroupSum {g in GROUPS} = sum {i in OBS, j in VARS} a[i,j] * Assign[i,g];

   var MinSum, MaxSum;
   con MinSumCon {g in GROUPS}:
      MinSum &amp;lt;= GroupSum[g];
   con MaxSumCon {g in GROUPS}:
      MaxSum &amp;gt;= GroupSum[g];
   min Range = MaxSum - MinSum;

   solve;

   print Assign;
   print GroupSum;
   num groupID {OBS};
   for {i in OBS} do;
      for {g in GROUPS: Assign[i,g].sol &amp;gt; 0.5} do;
         groupID[i] = g;
         leave;
      end;
   end;
   create data want(drop=i) from [i] {j in VARS} &amp;lt;col('x'||j)=a[i,j]&amp;gt; groupID;
quit;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;SAS Output&lt;/P&gt;
&lt;DIV class="branch"&gt;
&lt;DIV&gt;
&lt;DIV align="center"&gt;
&lt;TABLE class="table" summary="Procedure Optmodel: PrintTable" frame="box" rules="all" cellspacing="0" cellpadding="5"&gt;
&lt;THEAD&gt;
&lt;TR&gt;
&lt;TH class="l b header" scope="col"&gt;[1]&lt;/TH&gt;
&lt;TH class="r b header" scope="col"&gt;GroupSum&lt;/TH&gt;
&lt;/TR&gt;
&lt;/THEAD&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;1&lt;/TH&gt;
&lt;TD class="r data"&gt;137&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;2&lt;/TH&gt;
&lt;TD class="r data"&gt;138&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;3&lt;/TH&gt;
&lt;TD class="r data"&gt;138&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;4&lt;/TH&gt;
&lt;TD class="r data"&gt;138&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;
&lt;/DIV&gt;
&lt;/DIV&gt;
&lt;/DIV&gt;</description>
      <pubDate>Sat, 07 May 2016 15:32:23 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269012#M269405</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2016-05-07T15:32:23Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269044#M269406</link>
      <description>&lt;PRE&gt;
The following code is for any number of groups. Just change it at :
group=5;  /*divide into 5 groups*/

NOTE: the obs with zeros in all X Y Z are dummy obs. You can ignore them.


data have;
input x y z;
datalines;
10 15 8
11 14 9
12 16 10
9 16 8
8 12 10
8 10 11
11 14 12
13 10 9
8 16 15
10 11 8
11 15 14
16 13 10
10 15 14
12 8 14
7 12 13
9 14 10
;
run;



proc iml;
use have;
read all var _num_ into age[c=vname] ;
close ;

start function(x) global(age,group,nrow);
if ncol(x) ^= ncol(unique(x)) then x=ranperm(nrow,1);
y=shape(x,group,0,0);
sum_group=j(group,1,.);

do i=1 to group;
 sum_group[i]=age[y[i,],][+];
end;
obj=range(sum_group);
return (obj);
finish;

start switch_mut(s) global(nswitches,nrow);
if ncol(s) ^= ncol(unique(s)) then s=ranperm(nrow,1);
else do;
  n = ncol(s);
  do i = 1 to nswitches;
   k1 = int(uniform(1234)*n) + 1;
   k2 = int(uniform(1234)*n) + 1;
   if k1^=k2 then do;
    temp=s[k2];
    s[k2] = s[k1];
    s[k1] = temp;
   end;
  end;
end;
finish;

start uniform_cross(child1, child2, parent1, parent2) global(nrow);

child1 = parent1;
child2 = parent2;
do i = 1 to ncol(parent1);
  r = uniform(1234);
  if r&amp;lt;=0.5 then do;
   child1[i] = parent2[i];
   child2[i] = parent1[i];
  end;
end;

if ncol(child1) ^= ncol(unique(child1)) then child1=ranperm(nrow,1);
 else if ncol(child2) ^= ncol(unique(child2)) then child2=ranperm(nrow,1);

finish;



nrow=nrow(age);
obs=t(1:nrow);
group=5;  /*divide into 5 groups*/

mod=mod(nrow,group);
if mod^=0 then do;
 remain=group-mod;
 age=age//j(remain,ncol(age),0);
 nrow=nrow(age);
 obs=t(1:nrow);
end;
nswitches = 3;
encoding=j(2,nrow,1);
encoding[2,]=nrow;    

id=gasetup(2,nrow,1234);
call gasetobj(id,0,"function");
call gasetcro(id,0.95,0,"uniform_cross");
call gasetmut(id,0.95,0,"switch_mut");
call gasetsel(id,100,1,1);
call gainit(id,1000,encoding);


niter = 10000;
do i = 1 to niter;
 call garegen(id);
 call gagetval(value, id);
end;
call gagetmem(mem, value, id, 1);


y=shape(mem,group,0,0);
sum_group=j(group,2,.);
do i=1 to group;
 sum_group[i,1]=i;
 sum_group[i,2]=age[y[i,],][+];
end;
Memebers=colvec(row(y))||obs[mem,]||age[mem,];
vnames={group obs}||vname;
print "Members:" Memebers[c=vnames],
      "Group sum:" sum_group[c={group sum}],
      "Min Value: " value[l = ""] ;
call gaend(id);
quit;






OUTPUT:

GROUP	OBS	x	y	z
	1	14	12	8	14
 	1	12	16	13	10
 	1	17	0	0	0
 	1	4	9	16	8
 	2	10	10	11	8
 	2	6	8	10	11
 	2	8	13	10	9
 	2	5	8	12	10
 	3	7	11	14	12
 	3	2	11	14	9
 	3	20	0	0	0
 	3	13	10	15	14
 	4	11	11	15	14
 	4	19	0	0	0
 	4	16	9	14	10
 	4	1	10	15	8
 	5	3	12	16	10
 	5	18	0	0	0
 	5	9	8	16	15
 	5	15	7	12	13
 	
GROUP	SUM
	1	106
 	2	120
 	3	110
 	4	106
 	5	109
Min Value:	14



&lt;/PRE&gt;</description>
      <pubDate>Mon, 09 May 2016 05:29:53 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269044#M269406</guid>
      <dc:creator>Ksharp</dc:creator>
      <dc:date>2016-05-09T05:29:53Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269056#M269407</link>
      <description>&lt;P&gt;With five groups, the PROC OPTMODEL code finds that 14 is the minimum range:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;TABLE class="table" rules="all" frame="box" cellspacing="0" cellpadding="5" summary="Procedure Optmodel: PrintTable"&gt;
&lt;THEAD&gt;
&lt;TR&gt;
&lt;TH class="l b header" scope="col"&gt;[1]&lt;/TH&gt;
&lt;TH class="r b header" scope="col"&gt;GroupSum&lt;/TH&gt;
&lt;/TR&gt;
&lt;/THEAD&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;1&lt;/TH&gt;
&lt;TD class="r data"&gt;107&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;2&lt;/TH&gt;
&lt;TD class="r data"&gt;110&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;3&lt;/TH&gt;
&lt;TD class="r data"&gt;108&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;4&lt;/TH&gt;
&lt;TD class="r data"&gt;106&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
&lt;TH class="l rowheader" scope="row"&gt;5&lt;/TH&gt;
&lt;TD class="r data"&gt;120&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TBODY&gt;
&lt;/TABLE&gt;</description>
      <pubDate>Sun, 08 May 2016 13:07:56 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269056#M269407</guid>
      <dc:creator>RobPratt</dc:creator>
      <dc:date>2016-05-08T13:07:56Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269084#M269408</link>
      <description>&lt;P&gt;Rob,&lt;/P&gt;
&lt;P&gt;OR well done. I can't image SAS/OR can do solve so many different kind of challenge .&lt;/P&gt;</description>
      <pubDate>Mon, 09 May 2016 00:55:57 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269084#M269408</guid>
      <dc:creator>Ksharp</dc:creator>
      <dc:date>2016-05-09T00:55:57Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269155#M269409</link>
      <description>&lt;P&gt;Thank you for your response.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;To answer your question, what i'm trying to do is create 4 groups that are as similar as possible (among all variables). So in this case, i have 3 variables that i want to create the groups based on.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;You can think of the variables on a customer basis by "# of site visits" (x), "# of products viewed" (y), and "# of products bought" (z). I just made this example up so the numbers i provided previously don't make sense for it, but i want to create 4 groups to test different website designs to determine a "winner".&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I want the 4 groups to be as similar as possible, so that when they are in the final groups, all groups have a similar mean, or sum, of each of the variables. So Group 1 - 4 should have a similar mean of x, y, and z.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I don't know if this will change any of the answers, as I have not had time to go through and test them all yet, but thought I would clarify this first to give anyone a chance to re-visit their solution if it didn't match what I was hoping for.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thank you again for your response.&lt;/P&gt;</description>
      <pubDate>Mon, 09 May 2016 12:46:57 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269155#M269409</guid>
      <dc:creator>triley</dc:creator>
      <dc:date>2016-05-09T12:46:57Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269157#M269410</link>
      <description>&lt;P&gt;Rob, I appreciate your response as I am very interested in creating an OPTMODEL for this. However, I think that the result is slightly different from what I was actually looking for (my fault) and have clarified my question in a reply in a previous post. If you get a chance to modify for the output I am looking for I would appreciate it.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Basically, instead of combing the sum of all variables together, I want to treat them independently, and make the mean (or sum) of each variable similar between the 4 groups.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;So for example, group1 would have a mean of 10 for "x", 15 for "y" and 12 for "z".&lt;/P&gt;
&lt;P&gt;Group2 would have a mean of 11 for "x", 14 for "y" and 13 for "z" (so that the means of each variable are similar among groups).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This is for designing a pilot test, so the means or sums of each group need to be similar to remove variability from the design experiment.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thanks,&lt;/P&gt;
&lt;P&gt;Tom&lt;/P&gt;</description>
      <pubDate>Mon, 09 May 2016 12:58:33 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269157#M269410</guid>
      <dc:creator>triley</dc:creator>
      <dc:date>2016-05-09T12:58:33Z</dc:date>
    </item>
    <item>
      <title>Re: Creating Groups of Equal Size</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269158#M269411</link>
      <description>&lt;P&gt;All,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I have modified my question slightly since I don't believe I explained it properly the first time.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I am trying to create an experiment and want to design it in a way that I have 4 groups, that are similar among a few variables. These variables can be different things, so "x" could be "# of site visits", and "y" could be "conversion rate" for example. So the scale could be vastly different for each variable (e.g. x=10, y=15%, z= 1,000). I am not trying to sum the 3 variables together, I want to treat them individually and have similar variable means (or sums) across groups.&lt;/P&gt;
&lt;P&gt;&lt;BR /&gt;So for Group1, I want "x" to have a similar mean as Group2,3,and 4's "x" variable. Same with the "y" and "z" variables as well.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps, sorry for the misunderstanding (I will try and be more clear explaining the example in the future).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thanks,&lt;/P&gt;
&lt;P&gt;Tom&lt;/P&gt;</description>
      <pubDate>Mon, 09 May 2016 13:07:19 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Creating-Groups-of-Equal-Size/m-p/269158#M269411</guid>
      <dc:creator>triley</dc:creator>
      <dc:date>2016-05-09T13:07:19Z</dc:date>
    </item>
  </channel>
</rss>

