【问题标题】:Creating dummy rows in SAS from last entry date to specified date从上次输入日期到指定日期在 SAS 中创建虚拟行
【发布时间】:2019-02-05 12:26:49
【问题描述】:

假设我有以下 SAS 数据集:

Account  Month  Balance  LastMonth   MonthDate    LastMonthDate
1        Jan    5        May         2012-01-01  2012-05-01
1        Feb    2        May         2012-02-01  2012-05-01
1        Mar    1        May         2012-03-01  2012-05-01
2        Feb    6        Apr         2012-02-01  2012-04-01
2        Mar    4        Apr         2012-03-01  2012-04-01

我需要创建以下内容:

Account  Month  Balance  LastMonth   MonthDate    LastMonthDate
1        Jan    5        May         2012-01-01  2012-05-01
1        Feb    2        May         2012-02-01  2012-05-01
1        Mar    1        May         2012-03-01  2012-05-01
1        Apr    1        May         2012-04-01  2012-05-01
1        May    1        May         2012-05-01  2012-05-01
2        Feb    6        Apr         2012-02-01  2012-04-01
2        Mar    4        Apr         2012-03-01  2012-04-01
2        Apr    4        Apr         2012-04-01  2012-04-01

也就是说,我需要为每个帐户添加额外的行,以便每个帐户每个月都有一个条目,直到 'LastMonth' 列。对于不在原始数据集中的月份,余额必须与数据集中最后一个条目的余额保持一致。我的数据集已按“帐户”和“月份”排序。

请注意,这只是两个示例帐户,因为我的真实数据集有多个帐户,每个帐户都有不同的“LastMonth”列。我需要概括此过程,以便为每个帐户创建截至其“上个月”日期的缺失行数。

编辑:“MonthDate”和“LastMonthDate”存储如下:

【问题讨论】:

  • 是 month_date 和 lastMonth_date 字符还是日期变量?
  • @DomPazz - 它们是 SAS 日期格式 (yymmdd10.)
  • 它们是存储为日期还是字符串?格式是告诉 SAS 如何显示数据的一种方式。
  • @DomPazz - 请查看编辑以获取列属性的屏幕截图 :)
  • 为你更新了我的答案。

标签: database syntax sas


【解决方案1】:

您需要检查您是否在帐户的最后一行(需要按帐户对数据进行排序)。然后将您的字符串月份转换为数字,在它们之间进行迭代,并输出新的月份名称。

编辑

基于 cmets,此数据步骤将处理您的数据。保留旧答案以获取更多信息:

data want;
set have;
by account;

output;

if last.account then do;
    /*Current month as a number*/
    month_n = month(MonthDate);
    /*LastMonth as a number*/
    to_month = month(LastMonthDate);

    do i=month_n+1 to to_month;
        month = put(mdy(i,1,2000),monname3.); /*Increment the month and write the month name*/
        output;
    end;
end;

drop month_n to_month i;
run;

结束编辑

不幸的是,SAS 没有一种简单的格式或信息可以在月份之间转换为字符串和数字。所以在这里我将它们设为日期并使用month() 函数提取月份:

data want;
set have;
by account;

output;

if last.account then do;
    /*Current month as a number*/
    month_n = month(input(catt("01",strip(month),"2000"),date9.));
    /*LastMonth as a number*/
    to_month = month(input(catt("01",lastMonth,"2000"),date9.));

    do i=month_n+1 to to_month;
        month = put(mdy(i,1,2000),monname3.); /*Increment the month and write the month name*/
        output;
    end;
end;

drop month_n to_month i;
run;

您始终可以为转换创建自己的格式和信息。这将使代码更简洁。

proc format;
value MName 1="Jan"
             2="Feb"
             3="Mar"
             4="Apr"
             5="May"
             6="Jun"
             7="Jul"
             8="Aug"
             9="Sep"
             10="Oct"
             11="Nov"
             12="Dec";

invalue MName "Jan"=1
             "Feb"=2
             "Mar"=3
             "Apr"=4
             "May"=5
             "Jun"=6
             "Jul"=7
             "Aug"=8
             "Sep"=9
             "Oct"=10
             "Nov"=11
             "Dec"=12;
run;

data want2;
set have;
by account;

output;

if last.account then do;
    /*Current month as a number*/
    month_n = input(month,MName.);
    /*LastMonth as a number*/
    to_month = input(lastMonth,MName.);

    do i=month_n+1 to to_month;
        month = put(i,MName.);
        output;
    end;
end;

drop month_n to_month i;
run;

【讨论】:

  • 我还有一个字段,其中 'Month' 和 'LastMonth' 都以实际日期格式 (yymmddn10.) 存储 - 使用这些变量时更容易获得更清晰的代码吗?我现在将它们编辑,以便您查看。
  • 确定只需将month_n = month(input(catt("01",strip(month),"2000"),date9.)); 更改为month_n = month(month_date_var);(如果它们是SAS 日期)或month_n = month(input(month_date_var,yymmdd10.)); 如果它是一个字符串。
  • 我现在编辑了问题以显示日期格式的变量
【解决方案2】:

这是使用 DOW 循环方法的一种方法。它确实需要“预先通过”数据来评估和枚举涵盖每个帐户日期范围的单调月份。

关键概念是

  • 使用 LAG 和 INTCK 查找组内月差
  • 使用 INTNX 计算循环迭代
  • 使用后来删除的支持变量来维护状态

示例代码

假定 monthlastmonth 是正确的日期变量

data have;
attrib account format=8. month format=yymon7. informat=date9. lastmonth format=yymon7. informat=date9.;
input
Account  Month        Balance  LastMonth; datalines;
1        01-Jan-18    5        01-May-18
1        01-Feb-18    2        01-May-18
1        01-Mar-18    1        01-May-18
2        01-Feb-18    6        01-Apr-18
2        01-Mar-18    4        01-Apr-18
3        01-Jan-18    15       01-May-18
3        01-Mar-18    11       01-May-18
run;

data want;
  do _n_ = 1 by 1 until (last.account);

    set have;
    by account;

    prior_month = lag(month);
    prior_balance = lag(balance);

    * fill-in gaps within group;
    if _n_ > 1 and intck('month', prior_month, month) > 1 then do;
      curr_month = month;
      curr_balance = balance;

      balance = prior_balance;

      gap_start = intnx('month', prior_month, 1);
      gap_end   = intnx('month', curr_month, -1);

      * repeat prior observed months data for missing months;
      do month = gap_start by 0 until (month >= gap_end);
        OUTPUT;
        put 'NOTE: ' account= 'within-group gap data output ' month= balance=;

        month = intnx('month', month, 1);
      end;

      * restore original state;
      month = curr_month;
      balance = curr_balance;
    end;

    * unconditional output for within group data;
    OUTPUT;
  end;

  gap_start = intnx('month', month, 1);
  gap_end   = intnx('month', lastmonth, 0); * just for saftey sake;

  * conditional output for post-group months using data from last row in group ;
  do month = gap_start by 0 until (month > gap_end);
    OUTPUT;
    put 'NOTE: ' account= '  post-group gap data output ' month= balance=;    
    month = intnx('month', month, 1);
  end;

  drop prior_: curr_: gap_:;
run;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-29
    • 2019-10-25
    • 2014-04-07
    • 2019-11-22
    • 1970-01-01
    • 1970-01-01
    • 2020-05-09
    相关资源
    最近更新 更多