So you have multiple objectives. Here is one way to combine them into a single objective that minimizes the sum of the ranges:
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..&num_vars;
set GROUPS = 1..&num_groups;
set OBS;
num a {OBS, VARS};
read data have into OBS=[_N_] {j in VARS} <a[_N_,j]=col('x'||j)>;
/* 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)/&num_groups) <= sum {i in OBS} Assign[i,g] <= ceil(card(OBS)/&num_groups);
impvar GroupSum {g in GROUPS, j in VARS} = sum {i in OBS} a[i,j] * Assign[i,g];
var MinSum {VARS}, MaxSum {VARS};
con MinSumCon {g in GROUPS, j in VARS}:
MinSum[j] <= GroupSum[g,j];
con MaxSumCon {g in GROUPS, j in VARS}:
MaxSum[j] >= GroupSum[g,j];
impvar Range {j in VARS} = MaxSum[j] - MinSum[j];
min Objective = sum {j in VARS} Range[j];
solve;
print Assign;
print GroupSum;
num groupID {OBS};
for {i in OBS} do;
for {g in GROUPS: Assign[i,g].sol > 0.5} do;
groupID[i] = g;
leave;
end;
end;
create data want(drop=i) from [i] {j in VARS} <col('x'||j)=a[i,j]> groupID;
quit;
The resulting optimal solution has an objective value of (42 - 41) + (55 - 52) + (44 - 43) = 5:
SAS Output
Assign
1
2
3
4
1
1
0
0
0
2
0
1
0
0
3
0
1
0
0
4
0
0
0
1
5
0
0
1
0
6
0
1
0
0
7
0
0
0
1
8
1
0
0
0
9
0
0
1
0
10
0
-0
1
0
11
1
0
0
0
12
0
0
1
0
13
0
1
0
0
14
0
0
0
1
15
1
0
0
0
16
0
0
-0
1
GroupSum
1
2
3
1
41
52
44
2
41
55
44
3
42
52
43
4
41
52
44
If the variables have different scales, you might want to instead minimize a weighted sum of ranges:
min Objective = sum {j in VARS} weight[j] * Range[j];
For example, you might take the weight of variable j to be 1 / max {i in OBS} a[i,j].
... View more