Sas 如果在24小时内有另一个观测值,请选择该观测值
我正在尝试创建一个表,该表仅填充一个联系人的条目到一个客户的业务号码,如果他们在尝试使用业务号码之前的24小时内没有首先通过家庭号码联系 所以如果我有Sas 如果在24小时内有另一个观测值,请选择该观测值,sas,Sas,我正在尝试创建一个表,该表仅填充一个联系人的条目到一个客户的业务号码,如果他们在尝试使用业务号码之前的24小时内没有首先通过家庭号码联系 所以如果我有 DATA HAVE; INPUT ID RECORD DATETIME. TYPE; FORMAT RECORD DATETIME.; CARDS; 1 17MAY2018:06:24:28 H 1 18MAY2018:05:24:28 B 1 20MAY2018:06:24:28 B 2 20MAY2018:07:24:28 H
DATA HAVE;
INPUT ID RECORD DATETIME. TYPE;
FORMAT RECORD DATETIME.;
CARDS;
1 17MAY2018:06:24:28 H
1 18MAY2018:05:24:28 B
1 20MAY2018:06:24:28 B
2 20MAY2018:07:24:28 H
2 20MAY2018:08:24:28 B
2 22MAY2018:06:24:28 H
2 24MAY2018:06:24:28 B
3 25MAY2018:06:24:28 H
3 25MAY2018:07:24:28 B
3 25MAY2018:08:24:28 B
4 26MAY2018:06:24:28 H
4 26MAY2018:07:24:28 B
4 27MAY2018:08:24:28 H
4 27MAY2018:09:24:28 B
5 28MAY2018:06:24:28 H
5 29MAY2018:07:24:28 B
5 29MAY2018:08:24:28 B
;
RUN;
我希望能够
1 20MAY2018:06:24:28 B
2 24MAY2018:06:24:28 B
5 29MAY2018:07:24:28 B
5 29MAY2018:08:24:28 B
我已经尝试向ID添加一个计数,但我不确定如何使用它,或者是否有办法在proc sql中使用子查询来创建一个在24小时内有多个观测值的计数。我相信我已经找到了答案 我有HAVEA和HAVEB表,分别承载H型和B型条目 然后我运行了下面的procsql
PROC SQL;
CREATE TABLE WANTA AS
SELECT A.RECORD AS PREVIOUS_CALL, B.* FROM HAVEB B
JOIN HAVEA A ON (B.ID=A.ID AND A.RECORD LE B.RECORD);
CREATE TABLE WANTB AS
SELECT * FROM WANTA
GROUP BY ID, RECORD
HAVING PREVIOUS_CALL = MAX(PREVIOUS_CALL);
CREATE TABLE WANTC AS
SELECT * FROM WANTB
WHERE INTNX('HOUR',RECORD,-24,'SAME') GT PREVIOUS_CALL;
QUIT;
请让我知道,对于较大的数据量,这是否是一个可持续的答案,或者是否有更好的方法来解决这一问题。因此,这会起作用,但对于大量的数字来说会非常混乱-因为您在ID中进行笛卡尔连接。如果每个ID都有少量记录,那么情况也不会太糟,但是,如果每个ID都有许多记录,则会建立很多连接
幸运的是,在SAS中有一种简单的方法可以做到这一点
data want;
do _n_ = 1 by 1 until (last.id); *for each ID:;
set have;
by id;
if first.id then last_home=0; *initialize last_home to 0;
if type='H' then last_home = record; *if it is a home then save it aside;
if type='B' and intck('Hour',last_home,record,'c') gt 24 then output; *if it is business then check if 24 hours have passed;
end;
format last_home datetime.;
run;
请注意:
我使用道琼斯指数循环,但这并不是强制性的,我只是喜欢从清晰的角度来看,它清楚地表明我在重复做一些事情。您可以删除该循环,并为最后一个家庭添加保留,它将是相同的。
我使用INTCK而不是INTNX-同样为了清晰起见,您的INTNX也很好,但是INTCK只是进行比较,而INTNX用于将日期提前一段时间。我使用了一个匹配我正在尝试做的,所以阅读代码的人可以很容易地看到我在做什么。
在更大的数据集上,如果没有其他原因,这将比SQL快得多,因为它只传递一次数据。SQL必须多次执行此操作,即使您没有在SQL查询中分离HAVEA/HAVEB 执行选择以获得最终结果集,而无需创建中间表。这里有两种选择: 第一条路 类似于你的“弄明白”。在过去24小时86400秒内未发生的to_业务呼叫之前,使用分组的反射连接检测to_home呼叫
proc sql;
create table want as
select distinct
business.*
from have as business
join have as home
on business.id = home.id
& business.type = 'B'
& home.type = 'H'
& home.CALL_DT < business.CALL_DT
group by
business.call_dt
having
max(home.call_dt) < business.call_dt - 86400
;
第二条路
对24小时前的到家电话和每次的业务电话进行非存在性检查
create table want2 as
select
business.*
from
have as business
where
business.type = 'B'
and
not exists (
select * from have as home
where home.id = business.id
and home.type = 'H'
and home.call_dt < business.call_dt
and home.call_dt >= business.call_dt - 86400
)
;
散列解决方案确实对数据量和RAM有一些依赖性…但它是另一种选择
DATA HAVE;
INPUT ID RECORD DATETIME. TYPE $;
FORMAT RECORD DATETIME.;
CARDS;
1 17MAY2018:06:24:28 H
1 18MAY2018:05:24:28 B
1 20MAY2018:06:24:28 B
2 20MAY2018:07:24:28 H
2 20MAY2018:08:24:28 B
2 22MAY2018:06:24:28 H
2 24MAY2018:06:24:28 B
3 25MAY2018:06:24:28 H
3 25MAY2018:07:24:28 B
3 25MAY2018:08:24:28 B
4 26MAY2018:06:24:28 H
4 26MAY2018:07:24:28 B
4 27MAY2018:08:24:28 H
4 27MAY2018:09:24:28 B
5 28MAY2018:06:24:28 H
5 29MAY2018:07:24:28 B
5 29MAY2018:08:24:28 B
;
RUN;
/* Keep only HOME TYPE records and
rename RECORD for using in comparision */
Data HOME(Keep=ID RECORD rename=(record=hrecord));
Set HAVE(where=(Type="H"));
Run;
Data WANT(Keep=ID RECORD TYPE);
/* Use only BUSINESS TYPE records */
Set HAVE(where=(Type="B"));
/* Set up HASH object */
If _N_=1 Then Do;
/* Multidata:YES for looping through
all successful FINDs */
Declare HASH HOME(dataset:"HOME", multidata:'yes');
home.DEFINEKEY('id');
home.DEFINEDATA('hrecord');
home.DEFINEDONE();
/* To prevent warnings in the log */
Call Missing(HRECORD);
End;
/* FIND first KEY match */
rc=home.FIND();
/* Successful FINDs result in RC=0 */
Do While (RC=0);
/* This will keep the result of the most recent, in datetime,
HOME/BUS record comparision */
If intck('Hour',hrecord,record,'c') > 24 Then Good_For_Output=1;
Else Good_For_Output=0;
/* Keep comparing HOME/BUS for all HOME records */
rc=home.FIND_NEXT();
End;
If Good_For_Output=1 Then Output;
Run;
这太烦人了,现在我明白了,这是完全有道理的,但我一辈子都不能自己去想。在执行此数据步骤之前,主要需要确保数据位于单个表中,并按ID排序,然后按记录排序,对吗?对。您可以通过将该记录添加到by语句来强制执行该记录,而不会产生任何实际问题。它实际上不必在一个数据集中,如果它在两个HAVEA和HAVEB中,通过合并,或者跨多天的多个数据集中,只需将它们添加到SET语句中,就可以执行类似的操作。