2016-10-27 6 views
0

У меня есть набор данных около 50 миллионов записей с примерно 30 переменными (столбцами). Мне нужно ранжировать набор данных для каждой переменной.Как оценивать несколько переменных в большом наборе данных?

Оценка Proc не работает, так как для этого большого набора данных требуется много памяти.

Чтобы присвоить ранг вручную, мне нужно отсортировать набор данных в соответствующем столбце переменной и затем присвоить ранг с помощью формулы. Но проблема в том, что мы должны сортировать набор данных 30 раз по 30 переменным, что займет очень много времени и не выполнимо.

Какие альтернативы мы можем использовать в этом случае?

ответ

0

Вы находитесь в трудном месте без множества вариантов. Если вы сортируете и сохраняете все 30 переменных каждый раз, это значительно увеличит время обработки. Если бы я был вами, я бы только сохранил переменную, которую вы хотите ранжировать, и порядковый номер для применения вашей формулы, а затем объединить все это вместе в конце. Это потребовало бы, чтобы вы перебирали каждую переменную в своем наборе данных, а затем объединяли все вместе. Смотрите пример ниже, и если это поможет уменьшить ваше время обработки:

** PUT ALL VARIABLES INTO LIST **; 
PROC SQL NOPRINT; 
    SELECT DISTINCT(NAME) 
    INTO :VARS SEPARATED BY " " 
    FROM DICTIONARY.COLUMNS 
    WHERE LIBNAME = 'SASHELP' AND MEMNAME = 'FISH'; 
QUIT; 

%PUT &VARS.; 

** CREATE SEQUENCE NUMBER IN FULL DATA **; 
DATA FISH; SET SASHELP.FISH; 
    SEQ=_N_; 
RUN; 

** LOOP OVER EACH VARIABLE TO ONLY PROCESS THAT VARIABLE AND SEQUENCE -- REDUCES PROCESSING TIME **; 
%MACRO LOOP_OVER(VARS); 
    %DO I=1 %TO %SYSFUNC(COUNTW(&VARS.)); 
     %LET VAR = %SCAN(&VARS,&I.); 
     DATA FISH_&I.; SET FISH (KEEP=SEQ &VAR.); 
     RUN; 

     /* INSERT YOUR FORMULA CODE HERE ON FISH_&I. DATA (MINE IS AN EXAMPLE) */ 
     PROC SORT DATA = FISH_&I.; 
      BY &VAR.; 
     RUN; 

     DATA FISH1_&I.; SET FISH_&I.; 
      BY &VAR.; 
      RANK_&VAR = _N_; 
     RUN; 

     /* RESORT FINAL DATA BY SEQUENCE NUMBER VARIABLE */ 
     PROC SORT DATA = FISH1_&I.; 
      BY SEQ; 
     RUN; 
    %END; 
%MEND; 

%LOOP_OVER(&VARS.); 

** MERGE ALL SUBSETS BACK TOGETHER BY THE ORIGINAL SEQUENCE NUMBER **; 
DATA FINAL; 
    MERGE FISH1_:; 
    BY SEQ; 
    DROP SEQ; 
RUN; 
+0

You может дополнительно повысить производительность за счет объединения первых двух шагов в% DO I в один PROC SORT data = fish (keep = seq & var) out = fish_ & i; и т. д. А также с помощью VIEW для шага данных для вычисления рангов и использования этого в качестве входа в последний PROC SORT. –

0

Если вам просто нужно ранжировать в децилях/процентили и т.д., а не полный рейтинг от 1 до 50 м по всем строкам 50м, вы должны быть в состоянии получите очень хорошее приближение правильного ответа, используя намного меньший объем памяти через proc summary, используя qmethod=P2 и указав подходящую настройку qmarkers.

Этот подход использует P-квадратом алгоритм: http://www.cs.wustl.edu/~jain/papers/ftp/psqr.pdf

0

Я не уверен, является ли это хорошая идея: Но вы можете использовать объект Hash. Объект загружается в вашу оперативную память. Предполагая, что у вас есть 30 Mio числовых наблюдений, вам понадобится около (2 * 8 байт) * 50 mio = 800MB ОЗУ - если я не ошибаюсь.

Код может выглядеть следующим образом (с использованием Foxers Macro для цикла по переменным, немного помощник макрос, чтобы получить список переменных из набора данных и небольшого тестового набора данных с двумя переменными):

%Macro GetVars(Dset) ; 
%Local VarList ; 
/* open dataset */ 
%Let FID = %SysFunc(Open(&Dset)) ; 
/* If accessable, process contents of dataset */ 
%If &FID %Then %Do ; 
    %Do I=1 %To %SysFunc(ATTRN(&FID,NVARS)) ; 
    %Let VarList= &VarList %SysFunc(VarName(&FID,&I)); 
%End ; 
/* close dataset when complete */ 
%Let FID = %SysFunc(Close(&FID)) ; 
%End ; 
&VarList 
%Mend ; 

data dsn; 
input var1 var2; 
datalines; 
1 48 
1 8 
2 5 
2 965 
3 105 
4 105 
3 85 
; 
run; 


%MACRO LOOP_OVER(VARS); 
%DO I=1 %TO %SYSFUNC(COUNTW(&VARS.)); 
    %LET var = %SCAN(&VARS,&I.); 
    data out&i.(keep=rank&i.); 
     if 0 then set dsn; 
     if _N_ =1 then 
     do; 
      dcl hash hh(ordered:'A'); 
      dcl hiter hi('hh'); 
      hh.definekey("&var."); 
      hh.definedata("&var.","rank&i."); 
      hh.definedone(); 
     end; 

     /*Get unique combination variable and point in dataset*/ 
     do while(not last); 
      set dsn end=last; 
      hh.ref(); 
     end; 

     /*Assign ranks within hash object*/ 
     rc=hi.first(); 
     k = 1; 
     do while(rc=0); 
      rank&i.=k; 
      hh.replace(); 
      k+1; 
      rc=hi.next(); 
     end; 

     /*Output rank to new dataset in original order of observations*/ 
     do while(not theend); 
      set dsn end=theend; 
      hh.find(); 
      output; 
     end; 
     /*If data can be sorted according to the rank (with no duplicates) use: 
     hh.output("out&i."); 

     &outi. will then have variables &var. and rank&i. 
     However, the merging below may not be sensible anymore 
     as correspondence between variables is not preserved. 
     There will also be no duplicates in the dataset. 
     */ 

    run; 
%END; 

%MEND LOOP_OVER; 

%LOOP_OVER(%GetVars(dsn)); 


/*Merge all rank datasets to one large*/ 
data all; 
merge out:; 
run; 

 Смежные вопросы

  • Нет связанных вопросов^_^