【问题标题】:sas: count number of rows according to datesas:根据日期计算行数
【发布时间】:2020-04-08 23:01:43
【问题描述】:

我正在处理犯罪数据。现在,我有下表crimes。每行包含一个特定的罪行(例如攻击):它的犯罪日期 (date) 和犯罪者的个人 ID (person)。

date       person     
------------------------------
02JAN2017       1        
03FEB2017       1      
04JAN2018       1     --> not to be counted (more than a year after 02JAN2017)
27NOV2017       2      
28NOV2018       2     --> should not be counted (more than a year after 27NOV2017)   
01MAY2017       3
24FEB2018       3
10OCT2017       4

我对每个人在同一个人第一次犯罪后的 1 年内是否犯过 (relapse=1) 或未犯过 (relapse=0) 感兴趣。另一个条件是必须在特定年份(此处为 2017 年)内犯下第一次犯罪。

因此结果应如下所示:

date       person     relapse
------------------------------
02JAN2017       1           1  
03FEB2017       1           1
04JAN2018       1           1
27NOV2017       2           0 
28NOV2018       2           0 
01MAY2017       3           1
24FEB2018       3           1
10OCT2017       4           0

谁能给我一个关于如何在 SAS 中执行此操作的提示? 显然,真实数据要大得多,所以我无法手动完成。

【问题讨论】:

  • 如果有人在 2017 年 1 月、2018 年 2 月和 2018 年 3 月犯罪怎么办? (请在问题中填写您的示例)
  • 那么,由于2018年2月和2018年3月所犯罪行是在2017年1月之后一年以上,所以没有复发。但是如果是5年而不是1年的话,就算复发了.
  • 如果有人在 2016 年 1 月、2017 年 2 月和 2017 年 3 月犯罪怎么办?
  • 另一个条件是必须在特定年份(此处为 2017 年)内犯下第一次罪行。

标签: sas


【解决方案1】:

一种方法是使用 DATA 逐步分组处理。

BY <var> 语句设置二进制变量first.<var>last.<var>,分别标记组中的第一行和组中的最后一行。

您似乎正在为整个组分配计算出的 relapse 标志,这种计算可以通过 SAS 编码人员所说的 DOW 循环来完成——带有SET 语句的循环内部循环,后续循环将计算分配给组中的每一行。

INTCK 函数可以计算两个日期之间的年数。

例如:

data want(keep=person date relapse);
  * DOW loop computes assertion that relapse occurred;

  relapse = 0;
  do _n_ = 1 by 1 until (last.person);

    set crimes;          * <-------------- CRIMES;
    by person date;

    * check if persons first crime was in 2017;
    if _n_ = 1 and year(date) = 2017 then _first = date;

    * check if persons second crime was within 1 year of first;
    if _n_ = 2 and _first then relapse = intck('year', _first, date, 'C') < 1;
  end;

  * at this point the relapse flag has been computed, and its value
  * will be repeated for each row output;

  * serial loop over same number of rows in the group, but 
  * read in through a second SET statement;

  do _n_ = 1 to _n_;
    set crimes;              * <-------------- CRIMES;
    output;
  end;
run;

如果实际过程是根据比“2017 年第 1 次和 1 年内下一次”更细微的规则将一个人的不同时间范围分类为复发或改革,那么该过程会更复杂,记账变量更多。

【讨论】:

    【解决方案2】:

    我最近才开始使用 sas - 我绝不想在这里创建完美的代码。

    我会先按 id/person 和日期对数据进行排序(日期应该是数字),然后使用保留语句检查第一次犯罪的日期。它并不完美,但如果你的数据很好(没有丢失日期),它会起作用,而且很容易遵循恕我直言。

    这仅适用于第一次犯罪记录和犯罪行为应该发生在 2017 年。如果您在 2016 年发生犯罪,并且想检查 2017 年是否犯了“犯罪”然后检查复发,那么这个代码不起作用-但我认为您的问题下方的 cmets 已经涵盖了这一点。

    data test;
    input tmp_year $ 1-9 person;  
    datalines;
    02JAN2017       1        
    03FEB2017       1      
    04JAN2018       1    
    27NOV2017       2      
    28NOV2018       2    
    01MAY2017       3
    24FEB2018       3
    10OCT2017       4
    ;
    run;
    
    data test2;
        set test;
        crime_date = input(tmp_year, date9.);
        act_year = year(crime_date);
    run;
    
    proc sort data=test2;
       by person crime_date ;
    run;
    
    data want;
        set test2;
        by person crime_date;
        retain date_of_crime;
        if first.person and act_year = 2017 then date_of_crime = crime_date;
        else if first.person then call missing(date_of_crime);
        if intck('YEAR', date_of_crime, crime_date) =< 1 and not first.person 
        then relapse = 1;
        else relapse = 0;
    run;
    

    上面的代码标记了 2017 年犯罪行为发生一年后的犯罪行为。然后,您可以使用 proc sql 语句检索唯一的人员,并将他们与您拥有的任何数据集连接起来。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-04
      • 2014-12-07
      • 1970-01-01
      • 1970-01-01
      • 2017-05-16
      • 1970-01-01
      相关资源
      最近更新 更多