3

我难住了。

我想将一个非常大的数据集减少为更少的观察,但包含原始数据集的所有级别(最多)一次。这样做是出于测试目的,因此提出具有最少 obs 数量的最终数据集符合我们的最大利益。

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

输出看起来像这样:(SASHELP.CLASS:所有级别按年龄,性别):

  • AGE 有 6 个不同的级别 (11-16)
  • SEX 有 2 个不同的级别(“F”、“M”)
  • 理论上覆盖这些级别的最少 obs 数量是 6。

所以我们应该最终得到:

  • OBS #1:Affred,“M”,14
  • OBS #2:爱丽丝,“F”,13

芭芭拉、卡罗尔和亨利不会被输出,因为 FM 和 13-14 都被覆盖了

  • OBS #3:詹姆斯,“M”,12
  • OBS #4:珍妮特,“F”,15
  • OBS #5:乔伊斯,“F”,11
  • OBS #6:菲利普,“M”,16

输出结束

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

我想这将需要某种递归算法来最有效地获得少量 obs 来覆盖这些值,但不知道从哪里开始。任何帮助将不胜感激!

4

4 回答 4

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;
于 2013-10-28T15:19:55.763 回答
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;

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

于 2013-10-28T17:21:57.547 回答
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;
于 2013-10-28T14:03:25.017 回答
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,直到所有级别都被表示。

于 2013-10-28T13:18:06.590 回答