如何在SAS/SQL中基于行值进行条件计数?
重新上传,因为我上一篇文章有一些问题,我不知道我们应该发布样本数据。我是SAS的新手,我有一个问题,我知道如何用Excel解决,但不知道SAS。但是,数据集太大,无法在Excel中合理使用 我有四个变量:id、年份、组名、测试分数 样本数据:如何在SAS/SQL中基于行值进行条件计数?,sql,excel,sas,Sql,Excel,Sas,重新上传,因为我上一篇文章有一些问题,我不知道我们应该发布样本数据。我是SAS的新手,我有一个问题,我知道如何用Excel解决,但不知道SAS。但是,数据集太大,无法在Excel中合理使用 我有四个变量:id、年份、组名、测试分数 样本数据: id year_start group_name test_score 1 19931231 Red 90 1 19941230 Red
id year_start group_name test_score
1 19931231 Red 90
1 19941230 Red 89
1 19951231 Red 91
1 19961231 Red 92
2 19930630 Red 85
2 19940629 Red 87
2 19950630 Red 95
3 19950931 Blue 90
3 19960931 Blue 90
4 19930331 Red 95
4 19940331 Red 97
4 19950330 Red 98
4 19960331 Red 95
5 19931231 Red 96
5 19941231 Red 97
我的目标是通过每年的考试分数获得一份排名表。我希望我能够使用PROC秩分数来实现这一点。此函数将通过一个测试来计算顺序,最高的分数为1,第二高的分数为2,依此类推,然后除以观察的总数以提供分数等级。不幸的是,每一行的起始年份差别很大。对于每个id/年组合,我希望从年初开始执行一年回顾,并将该观察结果与在该一年范围内有一年开始的所有其他id进行排序。我对按日历年进行比较不感兴趣,每个id的排名应该是相对于它自己的年份开始的。再加上另一个复杂程度,我希望这个排名由groupname执行
如果有人有一个SQL解决方案,ProcSQL是完全好的
使用上述数据,排名如下所示:
id year_start group_name test_score rank
1 19931231 Red 90 0.75
1 19941230 Red 89 0.8
1 19951231 Red 91 1
1 19961231 Red 92 1
2 19930630 Red 85 1
2 19940629 Red 87 0.8
2 19950630 Red 95 0.75
3 19950931 Blue 90 1
3 19960931 Blue 90 1
4 19930331 Red 95 1
4 19940331 Red 97 0.2
4 19950330 Red 98 0.2
4 19960331 Red 95 0.333
5 19931231 Red 96 0.25
5 19941231 Red 97 0.667
为了计算第1行的排名
我们首先排除蓝色观察。
然后我们计算在那一年开始前一年内的观测数量,19931231,所以我们有4个观测。
我们计算这些观察中有多少具有较高的test_分数,然后加1以找到当前观察的顺序,因此它是第三高的。
然后,我们将顺序除以总数,得到秩3/4=0.75。
在Excel中,此变量的公式如下所示。假设公式适用于第1行,共有100行。id=A,年份开始=B,组名=C,测试分数=D:
=(1+countifs(D1:D100,">"&D1,
B1:B100,"<="&B1,
B1:B100,">"&B1-365.25,
C1:C100, C1))/
countifs(B1:B100,"<="&B1,
B1:B100,">"&B1-365.25,
C1:C100, C1)
非常感谢你的帮助
如果我读对了,你的例子是不正确的,所以很难确切知道你想做什么。但是试试下面的方法,看看是否有效。您可能需要调整不平等性以打开或关闭,这取决于您是否希望包括截至日期的一年。请注意,您的year_start列需要以SAS日期格式导入才能正常工作。否则,您可以使用inputyear\u start,yymmdd8.对其进行更改
proc sql;
select distinct
a.id,
a.year_start,
a.group_name,
a.test_score,
1+sum(case when b.test_score > a.test_score then 1 else 0 end) as rank_num,
count(b.id) as rank_denom,
calculated rank_num / calculated rank_denom as rank
from testdata a left join testdata b
on a.group_name = b.group_name
and intnx('year',a.year_start,-1,'s') le b.year_start le a.year_start
group by a.id, a.year_start, a.group_name, a.test_score
order by id, year_start;
quit;
请注意,由于没有9/31,我将日期从9/31改为9/30,但由于这可能是有意的,所以只剩下3/30、6/29和12/30,尽管其他日期似乎是季度末。考虑SQL中的相关计数子查询: 资料 过程SQL 包括供您查看的其他字段 输出 您将注意到,您的预期结果之间存在细微差异,这可能是由于您申请所有年份的季度日365.25,因为SAS的intnx需要一个完整的日历年,天数随着年份的变化而变化
你能解释一下秩函数的逻辑吗?也许做一些示例计算。请阅读,这里是一个学习如何提高问题质量和获得更好答案的好地方。你的例子是错误的。在第一排,排名将是4分之3,因为这是一年内第三高的红色分数。也没有9月31日的日期。哦,哇,你说得对,我道歉。在实际数据中,越低越好,我忘了更新excel公式和输出以匹配我提供的示例。更新..如果您没有在总和中添加1,但使用了大于:sumcase当b.test\u score>=a.test\u score然后1或0结束为rank\u num时,我们的结果将反映出来。例如,19960331记录有两个日期介于那一天和一年前之间:19951231和19950630,您和OP将其计算为1。但是+1作为您的解决方案可能更有效,因为在大多数RDBMS中,联接取代了相关子查询。感谢回复Talmage。您的代码似乎非常合理,但数据集非常大,因此我还没有任何结果。我能否用select distinct*,,替换select distinct a.id、a.year\U start、a.group\U name、a.test\U score?我在实数集中有很多变量。1+和的原因…>。。。与总和相反…>=。。。正在处理领带。请参阅下面我对您的解决方案的评论。我不确定,因为有一个表2的连接。如果我记得的话,SAS SQL抱怨select a.*甚至不需要distinct,但您仍然需要在group by子句中列出非联接变量,并在联接条件中列出联接变量。仅查看输出,就不太正确。请注意,最后一行有一个97,这是并列的所有提供的最高分数,但num_排名可能是2,因为如何处理平局。id 4的最后一行也存在类似的问题,其中num_rank是2而不是1。
data ranktable;
infile datalines missover;
input id year_start group_name $ test_score;
datalines;
1 19931231 Red 90
1 19941230 Red 89
1 19951231 Red 91
1 19961231 Red 92
2 19930630 Red 85
2 19940629 Red 87
2 19950630 Red 95
3 19950930 Blue 90
3 19960930 Blue 90
4 19930331 Red 95
4 19940331 Red 97
4 19950330 Red 98
4 19960331 Red 95
5 19931231 Red 96
5 19941231 Red 97
;
run;
data ranktable;
set ranktable;
format year_start date9.;
year_start = input(put(year_start,z8.),yymmdd8.);
run;
proc sql;
select r.id, r.year_start, r.group_name, r.test_score,
put(intnx('year', r.year_start, -1, 's'), yymmdd10.) as year_ago,
(select count(*) from ranktable sub
where sub.test_score >= r.test_score
and sub.group_name = r.group_name
and sub.year_start <= r.year_start
and sub.year_start >= intnx('year', r.year_start, -1, 's')) as num_rank,
(select count(*) from ranktable sub
where sub.group_name = r.group_name
and sub.year_start <= r.year_start
and sub.year_start >= intnx('year', r.year_start, -1, 's')) as denom_rank,
calculated num_rank / calculated denom_rank as rank
from ranktable r;
run;