2013-10-28 27 views
3

我很難過。來自數據集的最小obs覆蓋所有需要的級別

我想將一個非常大的數據集減少到較少的觀測值,但包含原始數據集的所有級別(最多)一次。這是爲了測試目的而完成的,因此我們最有興趣提出最少數量的obs的最終數據集。

所以,如果我們以數據集SASHELP.CLASS爲例。我想找出第一個obs(或者任何非特定的obs,但我認爲它可能比第一個/最後一個obs更容易),它涵蓋原始數據集的各個級別,而不是 all possible(existing ,或理論)所需變量的組合。

輸出會是這個樣子:(SASHELP.CLASS:各級按年齡,性別):

  • 時代都有6個不同等級(11-16)
  • SEX有2個不同的層次(」 F」, 「M」)
  • OBS覆蓋這些級別的數量最少理論上是6

所以我們應該結束了:

  • OBS#1:Affred, 「M」,14
  • OBS#2:翹, 「F」,13

巴巴拉,Carol和亨利不會被輸出,如FM和13-14被覆蓋

  • OBS#3:詹姆斯, 「M」,12
  • OBS#4:珍, 「F」,15
  • OBS#5:喬伊斯, 「F」, 11
  • OBS#6:觀測的菲利普, 「M」,輸出

    在這種情況下,我們通過數據順序地去的16

端,並且我們發現最小數目(6)滿足這個要求,但是如果這些等級變得更加冗長(或者相互關聯),並且數據被分類了(假設我們可以預先分類),那麼我們最終可能會得到接近最小值的東西,但並不是所需最長等級中的最小值變量。

我會想象這需要某種遞歸算法來最有效地獲得小數目的obs來覆蓋這些值,但不知道從哪裏開始。任何幫助將不勝感激!

+0

您是否需要從行中的類變量(此處爲年齡和性別)之外的其他數據?如果是這樣,它有多少 - 另一個變量或兩個或多個,以及序數或離散? – Joe

回答

0

我假設你想要一個相當容易實現的算法,併產生一個好的(但不一定是最好的)結果。

我的做法是從最稀有的水平開始。

第1步。根據級別頻率對所有類別進行排序。

在您的例子,我們可以得到:

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

SEX 
M 503 
F 524 

步驟2.啓動剩餘的稀有程度。在我們的情況下,年齡= 14。

然後在其餘類別中的每個類別中取最稀有的水平。 如果你得到一個匹配,然後用它作爲樣本。如果不是,則將搜索次數增加到更頻繁的級別,直到遇到命中。勾選您找到的關卡。直到所有的含量表示

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:

在SQL你可以用ORDER BY做到這一點。

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; 
+0

如果對於每個年齡段,每個性別至少有一次觀察結果,則這不會給出理想的結果。 –

+0

重新閱讀第二段,「......涵蓋原始數據集的每個單獨層次,而不是所有可能的(現有的或理論上的)所需變量的組合。」 – DomPazz

+0

我同意洛朗在這裏,我認爲這不會給人想要的結果。它會給出F 13和F 14,然後是M 13和M 14,這是不希望的;他想要F 13 F 14 M 13而不是那組4中的M 14)。 – Joe

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; 
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; 

它單獨檢查每個鍵的散列,並且如果記錄被發現與還未發現鍵它填充數據集,並與(多個)密鑰的散列。它不會返回並稍後檢查是否有更好的解決方案,儘管您可以在傳入數據集上使用不同(隨機)排序順序運行幾次並保留最小數據集。