【问题标题】:SAS: sum all values except oneSAS:对除一个以外的所有值求和
【发布时间】:2014-11-28 17:05:33
【问题描述】:

我在 SAS 工作,我试图总结所有观察结果,每次都漏掉一个。 例如,如果我有:

Count    Name      Grade
1        Sam        90
2        Adam       100
3        John       80
4        Max        60
5        Andrea     70

我想为 Sam 输出一个值,该值是除他自己以外的所有成绩的总和,而为 Adam 输出一个值,是除他自己以外的所有成绩的总和 - 等等。

有什么想法吗?谢谢!

【问题讨论】:

    标签: loops sum sas


    【解决方案1】:

    您可以改为在单个 proc sql 中执行此操作,使用关键字计算:

    data have;
    input Count    Name  $    Grade;
    datalines;
    1        Sam        90
    2        Adam       100
    3        John       80
    4        Max        60
    5        Andrea     70
    ;;;;
    run;
    
    proc sql;
        create table want as
        select *, sum(grade) as all_grades, calculated all_grades-grade as minus_grade
        from have;
    quit;
    

    【讨论】:

    • 谢谢,这是一个不错的解决方案
    • 对于没有NOTE: The query requires remerging summary statistics back with the original data. 消息的执行此操作的方法,请查看下面我对@Reese 答案的轻微修改。每当我在日志中看到这条消息时,它几乎总是意味着我在group byselect 子句中犯了一个错误。
    【解决方案2】:

    这是一个几乎一次性的解决方案(如果数据集适合读取缓冲区,它将与一次性解决方案的速度大致相同)。我实际上在这里计算了平均值而不是总和,因为我觉得这是一个更有趣的结果(总和当然是没有除法的平均值)。

    data have;
    input Count    Name  $    Grade;
    datalines;
    1        Sam        90
    2        Adam       100
    3        John       80
    4        Max        60
    5        Andrea     70
    ;;;;
    run;
    
    data want;
      retain grademean;
      if _n_=1 then do;
          do _n_ = 1 to nobs_have;
            set have(keep=grade) point=_n_ nobs=nobs_have;
            gradesum+grade;
          end;
          grademean=gradesum/nobs_have;
      end;
      set have;
      grade_noti = ((grademean*nobs_have)-grade)/(nobs_have-1);
    run;
    

    计算平均值,然后为每条记录减去该记录对平均值的贡献部分。当您想要将记录与其他总体进行比较时,这是一种非常有用的统计测试技术,并且您有一个复杂的类组合,您宁愿先做平均值。在这些情况下,您首先使用PROC MEANS,然后将其合并,然后进行减法。

    【讨论】:

      【解决方案3】:
      proc sql;
      create table temp as select
      sum(grade) as all_grades
      from orig_data;
      quit;
      
      proc sql;
      create table temp2 as select
      a.count,
      a.name,
      a.grade,
      (b.all_grades-a.grade) as sum_other_grades
      from orig_data a
      left join temp b;
      quit;
      

      尚未对其进行测试,但以上应该可以工作。它创建一个新的数据集 temp,其中包含所有成绩的总和,并将其合并以创建一个新表,其中所有成绩的总和减去当前学生的成绩为 sum_other_grades。

      【讨论】:

        【解决方案4】:

        此解决方案执行对起始数据集的每次观察,然后循环遍历同一数据集,汇总具有不同名称的任何记录的等级值,因此以“Sam”开头,我们仅在找到时添加 oth_g 变量不是“山姆”的名字:

        数据需要; 设置有; 其他_g=0; i=1 到 n; 设置有 (保持=名称等级重命名=(名称=名称循环等级=等级循环)) nobs=n 点=i; 如果 name^=name_loop 那么 oth_g+grade_loop; 结尾; 删除grade_loop name_loop i n; 跑;

        【讨论】:

        • 谢谢。我尝试了这个解决方案,但它给了我 0 的 Sam,其他人的值相同。
        • @Deb,那你错过了什么;当我运行它时,它的工作原理与宣传的完全一样。
        • 我已经在新的 SAS Studio Online 产品中对其进行了测试。在复制第二个 set 语句周围的换行符时请小心。为了便于阅读,我在这里只添加了一些额外的内容。
        【解决方案5】:

        这是对上面提供的@Reese 答案的轻微修改。

        proc sql;
            create table want as
            select *,
                   (select sum(grade) from have) as all_grades,
                   calculated all_grades - grade as minus_grade
            from have;
        quit;
        

        我以这种方式重新排列它以避免将以下消息打印到日志中:

        NOTE: The query requires remerging summary statistics back with the original data.
        

        如果您看到上述消息,它几乎总是意味着您犯了一个错误。如果您确实打算将汇总统计信息与原始数据重新合并,那么您应该明确地这样做(就像我在上面通过重构 @reese 的查询所做的那样。

        个人认为重构后的版本也更容易理解。

        【讨论】:

        • 我认为,如果您使用 having 子句,日志消息并不一定意味着发生了错误。虽然它在 SAS 中的使用通常不是有效的 ANSI SQL(根据我的经验),但它是 proc sql 的一个方便功能。
        • 它可以返回所需的结果,是的,但即使它可以,你为什么要这样做呢?通过重写代码可以达到相同的结果,使其更易读、更高效,并且与其他语言和数据库兼容!我个人认为 SAS 不应该允许它成为有效的语法。
        猜你喜欢
        • 1970-01-01
        • 2014-03-23
        • 2011-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-25
        相关资源
        最近更新 更多