数据集中的最小障碍物,以涵盖所有必需的级别

时间:2013-10-28 12:00:01

标签: algorithm sas minimum

我很难过。

我想将一个非常大的数据集减少到更少的观察值,但是包含原始数据集的所有级别(最多)一次。这样做是为了测试目的,因此我们最好的办法是提出最少数量的最终数据集。

因此,如果我们以数据集SASHELP.CLASS为例。我想找出第一个障碍物(或任何非特异性障碍物,但我觉得它可能更容易使用第一个/最后一个障碍物)覆盖原始数据集的每个单独级别,所有可能的(现有的或理论上的)所需变量的组合。

输出看起来像这样:(SASHELP.CLASS:AGE,SEX的所有级别):

  • AGE有6个不同的等级(11-16)
  • SEX有2个不同的等级(“F”,“M”)
  • 理论上覆盖这些水平的最少数量为6个。

所以我们最终应该:

  • OBS#1:Affred,“M”,14
  • OBS#2:Alice,“F”,13

芭芭拉,卡罗尔和亨利将不会输出,因为F-M和13-14都被覆盖

  • OBS#3:James,“M”,12
  • OBS#4:珍妮特,“F”,15
  • OBS#5:Joyce,“F”,11
  • OBS#6:Philip,“M”,16

输出结束

在这种情况下,我们按顺序遍历数据,并且我们发现满足要求的最小数量的obs(6),但是如果级别变得更长(或相互关联),并且数据被分类(假设我们可以预先-sort),我们最终会得到一些接近最小值的东西,但不是所需变量中最长的最小值。

我认为这需要某种递归算法才能最有效地获得少量的遮挡数值,但不知道从哪里开始。任何帮助将不胜感激!

4 个答案:

答案 0 :(得分:1)

这不是一种非常有效的方法,但它可以提供理想的结果

/* sort by first key */
proc sort data=sashelp.class out=minset;
 by age;
run;

/* set wantflag to 1 if first.key else wantflag is 0 */
data minset;
 set minset;
 by age;
 if first.age then wantflag = 1;
 else wantflag = 0;
run;

/* repeat proc sort and next data step for each consecutive key */
/* sort by second key and by descending wantflag */
proc sort data=minset out=minset;
 by sex descending wantflag ;
run;

/* set wantflag to 1 if first.key, do NOT set to 0 if not key */
data minset;
 set minset;
 by sex;
 if first.sex then wantflag = 1;
run;

/* finally keep smallest possible dataset */
data minset (drop=wantflag );
 set minset;
 if wantflag eq 1 then output;
run;

答案 1 :(得分:0)

我假设你想要一个相当容易实现的算法并产生一个好的(但不一定是最好的)结果。

我的方法是从最稀有的水平开始。

步骤1.根据级别频率对所有类别进行排序。

在您的示例中,我们可能会得到:

AGE
14 117
13 119
11 140
12 154
15 165
16 170

SEX
M 503
F 524

步骤2.从最稀有的剩余水平开始。在我们的案例中,AGE = 14。

然后在(剩下的)每个类别中保留最稀有的剩余等级。 如果你得到一个匹配,那么使用它作为样本。如果没有,那么将搜索增加到更频繁的级别,直到获得命中。勾选你找到的水平。

在SQL中,您可以使用ORDER BY执行此操作:

SELECT <primary key>, 
   case when category2 = <lowest remaining freq level for category2> then 1
        when category2 = <second lowest remaining freq level for category2> then 2
        ...
   end case AS category2,
   case when category3 = <lowest remaining freq level for category3> then 1
        when category3 = <second lowest remaining freq level for category3> then 2
        ...
   end case AS category3
FROM table1
WHERE category1 = <lowest remaining freq level for category1>
ORDER BY category2, category3

重复步骤2,直到表示所有级别。

答案 2 :(得分:0)

对数据集进行排序并使用数据步骤中的by语句仅输出第一个组。

请注意,这是从我之前的帖子更新的。正如其他人指出的那样,这是不正确的。

proc sort data=SASHELP.CLASS out=class_temp;
by AGE descending sex;
run;

data class_temp;
set class_temp;
by AGE;
if first.age then output;
run;

proc sort data=SASHELP.CLASS out=class_temp2;
by sex descending AGE;
run;

data class_temp2;
set class_temp2;
by sex;
if first.sex then output;
run;

proc sort data=class_temp2;
by age;
run;

data combos;
merge class_temp class_temp2;
by age sex;
run;

答案 3 :(得分:0)

您可以使用哈希对象编写一些大致相同的内容。这样做的缺点是它并不完美 - 我列出的例子给出了一个超出你想要的额外项目,因为与细胞相互作用的顺序很重要;并且数据集的初始顺序会影响输出的多样性,因此在下面的示例中,您有很多女性记录,只有两个男性记录,而不是反映初始数据集的多样性,仅仅因为(在我的sashelp.class中,至少在大多数年龄的男性之前都有女性。

data want;
if _n_ = 1 then do;
  declare hash recs();
  recs.defineKey('keytype');
  recs.defineKey('keylist');
  recs.defineData('keydata');
  recs.defineDone();
  format keylist $10. keytype $8. keydata $8.;
  call missing(of keylist keytype keydata);
end;
set sashelp.class;
  agechar=put(age,3.);
  rc_age = recs.check(key: 'age', key:agechar);  
  rc_sex = recs.check(key:'sex',key:sex);
  rc = rc_age+rc_sex;
  if rc=0 then delete;
  else do;
    if rc_age ne 0 then recs.add(key:'age',key:agechar,data:'sex');
    if rc_sex ne 0 then recs.add(key:'sex',key:sex,data:'sex');
    output;
  end;
run;

它分别检查每个密钥的哈希值,如果找到一个带有尚未找到的密钥的记录,它会用这些密钥填充数据集和哈希值。它不会返回并稍后检查是否有更好的解决方案,尽管您可以在传入的数据集上使用不同的(随机)排序顺序运行几次并保留最小的数据集。