【问题标题】:SAS sum observations not in a group, by groupSAS总和观察不在一个组中,按组
【发布时间】:2020-06-17 09:16:20
【问题描述】:

我有一个数据集:

data have;
   input group $ value;
   datalines;
A 4
A 3
A 2
A 1
B 1
C 1
D 2
D 1
E 1
F 1
G 2
G 1
H 1
;
run;

第一个变量是组标识符,第二个变量是值。

对于每个组,我想要一个新变量“sum”,其中包含列中所有值的总和,除了观察所在的组。

我的问题是必须对近 3000 万次观察进行此操作,因此效率很重要。 我发现使用 data step 比使用 procs 更有效。

最终的数据库应该是这样的:

data want;
   input group $ value $ sum;
   datalines;
A 4 11
A 3 11
A 2 11
A 1 11
B 1 20
C 1 20
D 2 18
D 1 18
E 1 20
F 1 20
G 2 18
G 1 20
H 1 20
;
run;

您知道如何执行此操作吗?

编辑:我不知道这是否重要,但我给出的示例是我的问题的简化版本。在实际情况中,我有 2 个其他组变量,因此取整列的总和并减去组中的总和不是一个可行的解决方案。

【问题讨论】:

  • 关于“我发现使用数据步骤比使用 procs 更有效。”你试过什么代码? 30M 行中有多少个不同的组?
  • 不是为了这个特定的任务,我正在计算大约 6000 万次观察的计数变量,不记得我在两年前使用的 proc,因为我使用过类似的任务数据步骤。在我开始使用 procs 时,我至少需要 2 个小时才能在不到 30 分钟的时间内对数据步骤执行相同的操作。问题可能是内存,计算是在内存只有 8gb 的服务器上进行的(不可能添加更多)。
  • 数据是否总是按group预排序?
  • 拥有多个分组变量会如何改变你想要的?你是说在这种情况下你想要多个 sum 变量?

标签: dataframe sas


【解决方案1】:

要求

列中所有值的总和,观察所在的组除外

表示必须发生两次数据传递:

  1. 计算all_sum 和每个组的group_sum
    哈希可以存储每个组的总和——通过指定的suminc: 变量和.ref() 方法调用计算。一个变量可以累积allsum
  2. 为组的每一行计算 allsum - group_sum
    从哈希中检索 group_sum 并从 allsum 中减去。

例子:

data want;
  if 0 then set have; * prep pdv;

  declare hash sums (suminc:'value');
  sums.defineKey('group');
  sums.defineDone();

  do while (not hash_loaded);
    set have end=hash_loaded;
    sums.ref();                * adds value to internal sum of hash data record;
    allsum + value;
  end;

  do while (not last_have);
    set have end=last_have;
    sums.sum(sum:sum);         * retrieve groups sum. Do you hear the Dragnet theme too?;
    sum = allsum - sum;        * subtract from allsum;
    output;
  end;

  stop;
run;

【讨论】:

  • 感谢您的回答。它在最小的示例上完美运行,但我无法将它用于多个组。就我而言,我有 3 个级别的组,第一级是年,然后是区域,最后是区域内的组。数据步开头的简单 by 语句不起作用,因为在 do while 循环中,它获取整个数据库的总和。知道如何修改代码以允许更多级别的组吗?
  • 更改defineKey 语句以列出所有组变量sums.defineKey('byvar1', 'byvar2', 'byvar3');
  • 当然,更多的分组变量意味着更多的组合意味着需要更多的内存来保存哈希。你说的是 30M 观察。你能回答以下问题:大约有多少组?这些组是否按顺序排列?你许可 SAS/MDDB 吗?根据@Tom,您是否想要多个总和变量(即您想要一级聚合、二级聚合和三级聚合?)
  • 是的,该组已排序。第一组有 9 个级别,第二个 304 和最后一个略小于 100。要记住的哈希数仅适用于最后一组,所以大约 100。对于 SAS/MDDB,我不知道,因为许可证是由购买的服务器和数据提供者。
【解决方案2】:

直截了当的方法有什么问题?无论你做什么,你都需要通过两次。

像这样。我包含了额外的变量,因此您可以查看这些值是如何派生的。

proc sql ;
 create table want as
  select a.*,b.grand,sum(value) as total, b.grand - sum(value) as sum
  from have a
     , (select sum(value) as grand from have) b
  group by a.group
 ;
quit;

结果:

Obs    group    value    grand    total    sum

  1      A        3        21       10      11
  2      A        1        21       10      11
  3      A        2        21       10      11
  4      A        4        21       10      11
  5      B        1        21        1      20
  6      C        1        21        1      20
  7      D        2        21        3      18
  8      D        1        21        3      18
  9      E        1        21        1      20
 10      F        1        21        1      20
 11      G        1        21        3      18
 12      G        2        21        3      18
 13      H        1        21        1      20

请注意,您的 GROUP BY 子句使用什么并不重要。

您真的需要输出所有原始观察结果吗?为什么不直接输出汇总表?

proc sql ;
 create table want as
  select a.group, b.grand - sum(value) as sum
  from have a
     , (select sum(value) as grand from have) b
  group by a.group
 ;
quit;

结果

Obs    group    total    sum

 1       A        10      11
 2       B         1      20
 3       C         1      20
 4       D         3      18
 5       E         1      20
 6       F         1      20
 7       G         3      18
 8       H         1      20

【讨论】:

  • 谢谢,这种方法完全有效,我只是缺乏 sql 经验。如果您还有几分钟的时间,您将如何在语句中包含多个组?正如你所说的“你有什么作为你的 GROUP BY 子句并不重要”,我该如何计算多个(在我的情况下为 3 个)级别的组?
  • “多组”是什么意思。如果您的组由多个变量定义,例如 AGEGROUP 和 GENDER,那么只需在 GROUP BY 语句中同时使用这两个变量。 group by agegroup, gender。如果您想要不同 AGEGROUP 类别的单独总和以及 GENDER 类别 10 的另一组总和,则需要进行单独分析。
【解决方案3】:

我会把它分成两个不同的部分:

1.) 您可以从使用 PROC SQL 开始按组获取总和

2.) 然后使用一些 IF/THEN 语句按组重新分配值

【讨论】:

    猜你喜欢
    • 2020-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多