如何使用SAS根据前一时期的性能创建排名



我有一个像下面这样的数据集。我想根据每个人前一天的表现给他排名。如果namesales在第t天排名前10%(20%),则name在第t+1天的排名应为1(2)。同样,如果namesales在第t天排名后10%,则name在第t+1天的排名应为10。

name   date   sales   rank
a      day1     11
b      day1     20
c      day1     15
d      day1     8
a      day2     12 
b      day2     21
c      day2     16
d      day2     9
a      day3     7 
b      day3     14
c      day3     12
d      day3     10

到目前为止我所做的是:步骤1。按date sales排序数据步骤2。创建new_variable iN。I是名称I在每个date上的确切排名。N测量每个date上的观测总数。如果I/N小于。1,则Rank_previous = 10,以此类推。这个新变量Rank_previous将是name在第t天的排名。

然而,我不知道如何将今天的排名Rank_previous分配给第二天的Rank。因为我的数据集非常大,如果你有更有效的方法来解决这个问题,那就太好了。

data data;
    set data;
    retain I;by date sales;
    if first.date or first.sales then I=1; else I=I+1;
run;
proc sql;
    create table data
    as select a.*,  max(I) as N 
    from data as a  
    group by date sales
    order by date sales;
quit;
data data (drop=I N);
    set data;
    Rank_temp = I/N; 
    if Rank_temp <= .1 then rank = 10;
run;

考虑到SAS的命名法,计算排名最简单的方法是PROC RANK。因此,数据必须先按by date排序。

data have;
input name   $ date   $ sales;
datalines;
a      day1     11
b      day1     20
c      day1     15
d      day1     8
a      day2     12 
b      day2     21
c      day2     16
d      day2     9
a      day3     7 
b      day3     14
c      day3     12
d      day3     10
;;;;
run;
proc rank data=have out=ranks percent;
by date;
var sales;
ranks rank;
run;

percent参数要求百分位数而不是数字排名。另一个可能会给你想要的排名的选项是groups=10,它会将所有值分配给十个组中的一个,尽管有时使用原始百分位数并自己分配更容易(为了更好地处理平局等)。你也可以用descending来反向赋值,因为我不清楚你想要的顺序。

当然,当您想要下一个天的排名时,您将需要一个短的数据步来将日期增加1并合并,或者SQL连接,或者您喜欢的任何方法。

**首先让我们加载比示例中更多的数据:**;

data have;
input name   $ date   $ sales;
datalines;
a      day1     11
b      day1     20
c      day1     15
d      day1     8
a      day2     12 
b      day2     21
c      day2     16
d      day2     9
e      day2     1
f      day2     90
g      day2     99
h      day2     2
i      day2     70
j      day2     39
k      day2     1
l      day2     16
m      day2     90
a      day3     7 
b      day3     14
c      day3     12
d      day3     10
e      day4     1
f      day4     90
g      day4     99
h      day4     2
i      day4     70
j      day4     39
k      day4     1
l      day4     16
m      day4     90
;
run;

**然后,按照Joe教我们的,让我们应用proc rank。我们需要的是排名,而不是销售额,所以让我们删掉它**;

proc rank  groups=10
    data=have 
    out=ranks  (drop=sales);
    by date;
    var sales;
    ranks rank_previous;
run;

**现在要合并前一天的排名和今天的销售,我们需要一点记忆**;

data have_memory;
    set have;
    by date;
    retain date_previous;
    if first.date then date_previous = lag1(date);
run;

**现在一个经典的合并工作**;

data have_ranked (drop=date_previous);
    merge have_memory (in=has)
          ranks (rename=(date=date_previous));
    by date_previous name;
    if not has then date = 'next';
run;

使用两组临时数组:一组用于保存前一天的排名,另一组用于创建当天的排名。

当你点击最后。日期,可以输出当天的所有信息,包括前几天的排行。然后,将今天的排名复制到前一天的数组中。

这样,您只需要在按日期和销售额排序后浏览一次数据。

首先让我们加载比示例中更多的数据:

data have;
input name   $ date   $ sales;
datalines;
a      day1     11
b      day1     20
c      day1     15
d      day1     8
a      day2     12 
b      day2     21
c      day2     16
d      day2     9
e      day2     1
f      day2     90
g      day2     99
h      day2     2
i      day2     70
j      day2     39
k      day2     1
l      day2     16
m      day2     90
a      day3     7 
b      day3     14
c      day3     12
d      day3     10
;
run;

考虑到性能问题,我会选择PROC MEAN(它是PROC sort的扩展版本,可以保存小计并且非常高效)。class子句对应于进程sort)

中的by子句。
proc means data=have noprint;
class date sales name;
output out=haveMean (where=(_type_ in (4,7)));

小计和详细信息由类型区分。省略where子句以查找哪个类型具有什么数据。现在合并类型 4:其中频率为我们提供了当天活动的销售人员数量和类型 7:详细信息

data salesSum;
merge haveMean (where=(_type_ eq 4) rename=(_freq_=numberPerDay) drop=name sales)
      haveMean (where=(_type_ eq 7));
by date;

跟踪一天内的订单数量,并将其除以活动销售人员的数量

retain orderInDay rank;
if first.date then orderInDay = 1; else orderInDay = orderInDay+ 1;

只计算具有一定销售量的第一个观察值的排名,给执行相同的排名

if first.date or lag1(sales) NE sales then rank = ceil(10 * orderInDay / numberPerDay);

打印相关内容

proc print data=salesSum;
by date;
var name sales rank;
run;

该解决方案仍然缺少将排名移植到下一个工作日的方法。为此,我考虑使用散列表。

最新更新