[英]SAS - Data Step equivalent of Proc SQL
與此 proc sql 等效的數據步驟是什么?
proc sql;
create table issues2 as(
select request,
area,
sum(issue_count) as issue_count,
sum(resolved_count) as resolved_count
from
issues1
group by request, area
);
PROC MEANS/SUMMARY 更好,但如果相關,實際的數據步驟解決方案如下。 基本上,您只需在first.<var>
上將計數器重置為 0 並在last.<var>
上輸出,其中<var>
是by
組中的最后一個變量。
注意:這假設數據按by request area
排序。 如果不是,請對其進行排序。
data issues2(rename=(issue_count_sum=issue_count resolved_count_sum=resolved_count) drop=issue_count resolved_count);
set issues1;
by request area;
if first.area then do;
issue_count_sum=0;
resolved_count_sum=0;
end;
issue_count_sum+issue_count;
resolved_count_sum+resolved_count;
if last.area then output;
run;
您正在嘗試做的功能等效如下:
data _null_;
set issues1(rename=(issue_count=_issue_count
resolved_count=_resolved_count)) end=done;
if _n_=1 then do;
declare hash total_issues();
total_issues.defineKey("request", "area");
total_issues.defineData("request", "area", "issue_count", "resolved_count");
total_issues.defineDone();
end;
if total_issues.find() ne 0 then do;
issue_count = _issue_count;
resolved_count = _resolved_count;
end;
else do;
issue_count + _issue_count;
resolved_count + _resolved_count;
end;
total_issues.replace();
if done then total_issues.output(dataset: "issues2");
run;
此方法不需要您對數據集進行預排序。 我想看看使用不同的方法會獲得什么樣的性能,所以我對 74M 行數據集進行了一些測試。 我得到了以下運行時間(您的結果可能會有所不同):
未排序的數據集:
Proc SQL
- 12.18 秒Data
步驟(以上) - 26.68 秒Proc Means
使用class
語句 (nway) - 5.13 秒排序數據集(36.94 秒進行 proc 排序):
Proc SQL
- 10.82 秒Proc Means
使用by
語句 - 9.31 秒Proc Means
使用class
語句 (nway) - 6.07 秒by
語句的Data
步驟(我使用了 Joe 回答中的代碼)- 8.97 秒如您所見,我不建議將數據步驟與上面顯示的哈希對象方法一起使用,因為它花費的時間是 proc sql 的兩倍。
我不確定為什么proc means
使用by
語句比使用class
語句的proc means
花費更長的時間,但是我在一堆不同的數據集上嘗試了這個,並看到了運行時的類似差異(我在 Linux 64 上使用 SAS 9.3)。
需要記住的是,這些運行時可能與您的情況完全不同,但我建議使用以下代碼進行求和:
proc means data=issues1 noprint nway;
class request area;
var issue_count resolved_count;
output out=issues2(drop=_:) sum=;
run;
我認為,完全在數據步驟中進行操作很尷尬 - 在by
變量的每個級別對變量進行求和和重置會起作用。 散列對象也可能起作用。
也許最簡單的非 Proc SQL 方法是使用 Proc 摘要:-
proc summary data = issues1 nway missing;
class request area;
var issue_count resolved_count;
output out = issues2 sum(issue_count) = issue_count sum(resolved_count) = resolved_count ;
run;
這是臨時數組方法。 這是其中“最簡單的”,對請求和面積值做了一些假設; 如果這些假設是錯誤的,因為它們通常存在於真實數據中,那么事情可能不會這么簡單。 請注意,雖然在下面的數據確實被排序,但我不依賴於它被排序並且該過程不會從它被排序中獲得任何優勢。
data issues1;
do request=1 to 1e5;
do area = 1 to 7;
do issueNum = 1 to 1e2;
issue_count = floor(rand('Uniform')*7);
resolved_count = floor(rand('Uniform')*issue_count);
output;
end;
end;
end;
run;
data issues2;
set issues1 end=done;
array ra_issue[1100000] _temporary_;
array ra_resolved[1100000] _temporary_;
*array index = request||area, so request 9549 area 6 = 95496.;
ra_issue[input(cats(request,area),best7.)] + issue_count;
ra_resolved[input(cats(request,area),best7.)] + resolved_count;
if done then do;
do _t = 1 to dim(ra_issue);
if not missing(ra_issue[_t]) then do;
request = floor(_t/10);
area = mod(_t,10);
issue_count=ra_issue[_t];
resolved_count=ra_resolved[_t];
output;
keep request area issue_count resolved_count;
end;
end;
end;
run;
考慮到我開始使用的簡單數據,它的性能與帶有 CLASS 的 PROC MEANS 相當。 如果您不能從 area 和 request 的組合中輕松生成一個鍵(例如,如果它們是字符變量),您將不得不存儲另一個名稱到鍵關系的數組,這會使其速度變慢如果有很多組合(盡管如果組合相對較少,也不一定都那么糟糕)。 如果由於某種原因您在生產中這樣做,我將首先創建一個唯一請求+區域組合的表,創建一個 Format 和一個 Informat 以從唯一鍵來回轉換(這應該非常快,並為您提供可靠的index),然后使用該格式/信息而不是我在這里所做的貓/除法模數來執行此操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.