2014-04-21 45 views
2

有關如何修改下面的問題代碼行以獲取無錯誤命名的數據集的任何建議?在哈希數據集語句中使用來自循環宏的變量時的SAS名稱錯誤

我有一個數據集,我想要匹配治療公司(4400)與約48000個行業和14年的控制公司,然後最近的大小沒有更換。我的方法可能有點笨拙,但我正在學習。我將治療和控制數據集分爲48x14組(在此之後,我將嘗試通過某種類型的循環來運行最近的匹配而不更換代碼)。

我已經使用了下面的哈希代碼的一個變體來創建48個數據集out1 ... out48。現在我試圖通過使用下面的代碼,將這48個數據集中的每一個進一步分爲14年。我正在接收一個錯誤數據集創建行,我嘗試創建名爲out12004,out22004,out32004的48x14數據集。 。 .out482013

問題代碼行(大約2/3下面的代碼):hh.output(dataset:'out'|| & || || put(year,best.-L));

SAS的錯誤是這樣的:

錯誤:數值超出12004不是有效的SAS名稱。

錯誤:在「DATASTEP.HASH」的實例方法OM_OUTPUT(505)期間發生錯誤。

以下是完整的代碼(從 Is it possible to loop over SAS datasets?SUGI30 paper 236-30

%MACRO process_datasets(mdataset); 
     data &mdataset.; 
     set &mdataset.; 
     data _null_ ; 
     dcl hash hoh (ordered: 'a') ; 
     dcl hiter hih ('hoh') ; 
     hoh.definekey ('year') ; 
     hoh.definedata ('year', 'hh') ; 
     hoh.definedone() ; 
     dcl hash hh() ; 
     do _n_ = 1 by 1 until (eof) ; 
     set out&i. end = eof ; 
     if hoh.find() ne 0 then do ; 
     hh = _new_ hash (ordered: 'a') ; 
     hh.definekey ('industry','cik', 'year', '_n_') ; 
     hh.definedata ('industry','cik','year','eventdat', 'at', 'roa') ; 
     hh.definedone() ; 
     hoh.replace() ; 
     end ; 
     hh.replace() ; 
     end ; 
     do rc = hih.next() by 0 while (rc = 0) ; 
     hh.output (dataset: '_'||&i||put(year, best.-L)) ; 
     rc = hih.next() ; 
     end ; 
     stop ; 
    run; 

    data _null_; 
     file 'tmp.csv' mod dsd dlm=','; *saving everything to the same file; 
     set &mdataset.; 
     put (_all_) (+0); 
    run; 

%MEND process_datasets; 

%MACRO loop_through_all; 
    %DO i = 1 %to 48; 
     %process_datasets(out&i.); 
    %END; 
%MEND loop_through_all; 

回答

1

首先,關於另一個答案中的技術要點的幾點說明 - 即「問題不是直接來自哪裏,儘管兩者都是差編碼的例子。」

&我確實可以在這裏找到,雖然我認爲這是一種很差的風格來使用它的方式。內部宏中依賴的宏變量應該定義爲宏參數;這表明它們來自哪裏。但是,從技術上講,這是沒有錯的,看到這一點:

%macro caller; 
%do i=1 %to 5; 
    %called; 
%end; 
%mend; 
%macro called; 
%put &i; 
%mend called; 

%caller; 

然而,這將是更好地使我一個放慢參數,如%macro called(i=);,使宏更清晰,更可重複使用。

其次,缺乏引號實際上不是直接的問題,儘管它確實指出了問題,並且是一種解決方法。 SAS會將​​其中的數字轉換爲字符值 - 否則會得到非常不同的錯誤信息;但是,它的做法是無用的。你所做的最類似的實施是在其周圍添加compress。這是因爲問題是SAS如何將數字轉換爲文本; &i是一個數字(在您的示例中爲1)。它需要轉換爲"1",而是使用best12.轉換爲" 1"。這是一個問題。

hh.output (dataset: compress('_'||&i||put(year, best.-L))) ; 

這是有效的。更好的實現是有意將其轉換爲字符值。宏參數非常易於轉換:只需在它們周圍添加" "即可。

hh.output(dataset: cats('_',"&i.",year); 

cats條所有的空格斷,並且使-L不必要的。它會和&i一樣工作,儘管它更好地添加引號。

我想補充一點,你可能會考慮爲什麼你將這些子集化。我認爲這樣做概念上不存在任何錯誤,但是如果你年復一年地做某些事情,你可以使用by year,並且避免將它們分組 - 也可以將它們保存在每個治療組的一個數據集中(甚至可以使用by group year? )。此外,您可以通過更少的步驟完成此操作。你打算怎麼做,最後?假設您每個組/年份都有一個數據集。你會運行什麼代碼?這可能是因爲您可以在不分出48x14數據集的情況下通過一個或幾個步驟編寫這些數據集,這可能無效。如果您有興趣瞭解詳情,請使用一對數據集詳細說明您想要做什麼。

+0

我用貓('_',「&i。」,year);這解決了它 - 非常感謝。我同意我的方法可能有點麻煩,但考慮到我接下來使用的宏,我仍然認爲我需要單獨的數據集。 – mrlcpa

0

修改,以解決有關的輸出線的具體點: -

hh.output (dataset: '_'||&i||put(year, best.-L)) ; 

的幾個注意事項: -

  • 必須引用數據集的參數,例如..(dataset: "Out123")。目前,你的不是。
  • 主宏沒有訪問宏變量&i。這是在調用宏中創建的,僅在該範圍內可用。您可以將其他參數添加到主宏,並以此方式發送&i

但事實上,您創建的代碼看起來很難維護;宏中的散列是調試的噩夢。如果您生成的代碼會創建大量輸出數據集,這些輸出數據集應該設置警報響鈴; SAS中的by聲明允許應用標準來分隔數據集內的組,並且絕對比許多數據集更可取。

讓我們來看看這個問題:您是否將控件與使用變量相匹配的治療方法相匹配,這樣每個治療就會產生多個控制組?那麼你會根據一些距離標準選擇一種治療方案?

對於第一部分,Proc SQL合併聽起來正確。你會得到一個很長的數據集,每個治療公司重複它與控制相匹配的次數。然後按treatment descending [distance criteria]排序,並按by組挑選第一個。這應該是。當然,我確定我誤解了一些東西......

最後一點;你可以在SAS中尋找匹配算法,特別是'最佳匹配'或'貪婪匹配'。根據我的經驗,SAS在匹配方面並不是很好,特別是如果它涉及一個隨機元素(你不知道),但你應該能夠找到比你現在使用的代碼更有用的代碼。

+1

您的兩個主要觀點都不正確。輸出的問題與缺乏報價無關,至少不是直接的。此外,&i。明確界定;因此在2014年之前是1年。之後我不知道這些文字 - 可能是合理的建議 - 但技術點是錯誤的。 – Joe

0

我想你可以通過在你的set語句中使用通配符來大大簡化你的上面的代碼,而不是使用多個set語句來「遍歷它們」。

例如,下面的代碼會遍歷所有以一個前綴開頭的數據集,以便您可以在不使用多個set語句的情況下處理它們。

data all; 
    set out1: 
     out2: 
     out3: 
     out4: 
     ; 
run; 

這甚至可能允許您刪除對宏的需求,從而簡化代碼。現有的代碼看起來很難維護/調試,所以我認爲簡化它是第一步。

+0

我想你誤解了他在做什麼。 (不可否認,我自己只有一個模糊的想法。)他並沒有將多個數據集合在一起,他正在使用其他(更少)數據集創建多個數據集。 – Joe

+0

在這種情況下,我確實誤解了......我剛剛看到set語句,動態數據集名稱由DO循環遞增並做出了這個假設。 –

+0

我實際上不明白在數據(某物)中存在的一點。我不明白爲什麼它不是'data_null_'。但是誰知道... – Joe