根据日期字段按年份对汇总统计信息进行分组

Group summary statistics by year based on a date field

我知道那些关注 SAS 标签的人已经习惯了这个论坛上一些非常高级的东西。我现在只是想学习我的基础知识,并根据我使用 SQL 或只是 Excel 的经验来思考。我想知道如何按日期列的年份部分进行分组。我做了一些 Google 搜索并迷路了。

如果我有这样的样本数据集:

Date    Close   Volume
12/31/2014  222.41  2402097
12/30/2014  222.23  2903242
12/29/2014  225.71  2811828
12/26/2014  227.82  3327016
12/24/2014  222.26  1333518
12/23/2014  220.97  4513321
12/22/2014  222.6   4806917
12/19/2014  219.29  6910461
12/18/2014  218.26  7483349
12/17/2014  205.82  7367834
12/16/2014  197.81  8426105
12/15/2014  204.04  5218252
12/12/2014  207 7173782

而这个数据实际上涵盖了两年-2013-14。如果我想按年份分组,那么对于2013和2014,我该如何,例如:

proc means data=tsla;
// something here to break out Date by 2013 and 2014?
run;  

给出:

有没有办法告诉 SAS 按年(日期)或类似的语法将其分解?

类似于:

proc univariate data=tsla; 
var Close Volume; 
run;

SAS 的一个优点是它在使用汇总过程时按格式化值分组。这意味着如果您将日期字段格式化为年份,它将按年份分组,而无需创建额外的列。

data have;
input Date : mmddyy10.  Close   Volume;
format date mmddyy10.;
datalines;
12/31/2014  222.41  2402097
12/30/2014  222.23  2903242
12/29/2014  225.71  2811828
12/26/2014  227.82  3327016
12/24/2014  222.26  1333518
12/23/2014  220.97  4513321
12/22/2014  222.6   4806917
12/19/2014  219.29  6910461
12/18/2014  218.26  7483349
12/17/2014  205.82  7367834
12/16/2014  197.81  8426105
12/15/2014  204.04  5218252
12/12/2014  207 7173782
;
run;

proc means data=have sum mean;
class date;
format date year.;
var close volume;
run;

由于您似乎需要更明确的细节,我将在此处解释一些有帮助的主要概念。

首先,SAS 有两种基本类型:数字和字符。它有一些派生类型,它们不是真正的类型——它们是解释数字的方式。 Date 是其中一种派生类型。日期值作为自 1/1/1960 以来的天数存储在数字字段中;所以今天是 20117。

SAS 然后使用 formats 将该基础数字转换为视觉上有用的东西。 Excel 的工作方式完全相同,只是开始日期不同(Excel 为 1/1/1900),因此这通常有助于解释。 SAS 的格式是 Excel 的数字格式,除了功能更强大之外,完全相同的想法。

这些格式总是以字符开头,然后以句点或句点后跟数字结尾。例如,mmddyy10.mmddyyw. 格式,其中 w.d 表示 width.decimal (宽度 = 显示的字符总数,小数点 = 小数点后的位数) , 除了 mmddyyw. 由于显而易见的原因没有小数。

SAS 也有 informats,它们与格式类似,只是相反:"How do I store this textual value as a number?"。因此,如果 MMDDYYw. 格式将 20117 转换为 01/29/2015,则 MMDDYYw. 格式会将 01/29/2015 转换为 20117。如果您想利用 SAS 的格式化功能,则必须进行转换:SAS 无法使用 01/29/2015 并弄清楚如何将其显示为 2015-01-29,但它可以将其转换为 20117,然后显示 任意数量的方式。

那么,Keith 在他的回答中所做的,以及我同意的一个很好的解决方案(以及我会做的),是使用 mmddyy10. 信息格式将 01/29/2015 转换为 20117,然后使用 YEAR4. 格式(YEARw.,其中 w=4)将 2014 年的任何日期显示为 2014,以及 2013 年的任何日期作为 2013。这是一种技巧,但它是一个很好的技巧:它不需要创建新变量,并且日期仍然具有它们过去使用的所有信息 - 它们只是在屏幕上显示为 2014

他正在做的另一件事是利用 proc means(和大多数触发)的工作方式。如果它们具有 summarizing/grouping 功能,则该功能基于分组依据的字段的 格式化 值起作用。对于 proc means,主要的分组方法是 class - 它基本上表示在 SQL 中“按每个唯一的 class 变量值. Works nearly identically to分组”。所以:

proc means data=<yourdata>;
  class date;
  var close volume;
run;

将为 date 的每个唯一值汇总 closevolume。除了这里,这意味着它将每天分别汇总 - 这没有用!

proc means data=<yourdata>;
  class date;
  var close volume;
  format date YEAR4.;
run;

啊哈。现在,日期由 year 的格式化值汇总。所以你的输出将类似于

Date  close volume
2013  15.34 123135342
2014  16.13 151232144

(除了多一点,因为您不仅得到一个平均值,而且还有 n 和 stdev 以及 max/min)。

这在功能上类似于添加 year 列,这可能更容易理解。假设您有一个包含此数据的数据集 have

data for_means;
  set have;
  year = year(date);
run;

这将在新列 year 中存储日期的年份(假设它存储为 SAS 日期,一个数字)。那么你可以这样做:

proc means data=for_means;
  class year;
  var close volume;
run;

但是 Keith 的方法 - 使用格式 - 更容易和更快。