2017-04-03 67 views
0

谢谢谁能帮助我。我有如下数据集:基于随后使用的第一个标记值。保留等

data smp; 
infile datalines dlm=','; 
informat identifier $7. trx_date $9. transaction_id $13. product_description $50. ; 
input identifier $ trx_date transaction_id $ product_description $ ; 
datalines; 
Cust1,11Aug2016,20-0030417313,ONKEN BIOPOT F/FREE STRAWBERRY 
Cust1,11Aug2016,20-0030417313,ONKEN BIOPOT F/FREE STRAWBERRY 
Cust1,11Aug2016,20-0030417313,ONKEN BIOPOT FULL STRAWB/GRAIN 
Cust1,11Aug2016,20-0030417313,RACHELS YOG GREEK NAT F/F/ORG 
Cust1,03Nov2016,23-0040737060,RACHELS YOG GREEK NAT F/F/ORG 
Cust3,13Feb2016,39-0070595440,COLLECT YOG LEMON 
Cust3,21Jun2016,34-0050769524,AF YOG FARMHOUSE STRAWB/REDCUR 
Cust3,21Jun2016,34-0050769524,Y/VALLEY GREEK HONEY ORGANIC 
Cust3,21Jun2016,34-0050769524,Y/VALLEY THICK LEMON CURD ORG 
Cust3,21Jun2016,34-0050769524,Y/VALLEY THICK YOG FRUITY FAVS 
Cust3,21Jun2016,34-0050769524,Y/VALLEY THICK YOG STRAWB ORG 
Cust3,26Jun2016,39-0430106897,TOTAL GREEK YOGURT 0% 
Cust3,14Aug2016,54-0040266755,M/BUNCH SQUASHUMS STRAW/RASP 
Cust3,14Aug2016,54-0040266755,MULLER CORNER STRAWBERRY 
Cust3,14Aug2016,54-0040266755,TOTAL GREEK YOGURT 0% 
Cust3,22Aug2016,54-0050447336,M/BUNCH SQUASHUMS STRAW/RASP 
; 

对于每个客户(以及基于TRANSACTION_ID他们的每一个购买的),我想标志,该标志将在下次访问期间回购各产品(只有自己的未来访问)。因此,在上述数据集中,正确的标志位于第4,12和13行,因为这些产品是在下次客户拜访时购买的(我们只看下一次拜访)。

我想用下面的程序做到这一点:

proc sort data = smp out = td; 
by descending identifier transaction_id product_description; 
run; 

DATA TD2(DROP=tmp_product); 
SET td; 
BY identifier transaction_id product_description; 
RETAIN tmp_product; 
IF FIRST.product_description and first.transaction_id THEN DO; 
    tmp_product = product_description; 
END; 
ATTRIB repeat_flag FORMAT=$1.; 
IF NOT FIRST.product_description THEN DO; 
IF tmp_product EQ product_description THEN repeat_flag ='Y'; 
ELSE repeat_flag = 'N'; 
END; 
RUN; 

proc sort data = td2; 
by descending identifier transaction_id product_description; 
run; 

但它不工作?如果有人能够帮助它将是fab。 祝福

+0

您的前两行是相同的产品和相同的日期。这可能会造成麻烦。 – Tom

回答

1

其他方法是在原始数据集和数据集暂时以产生虚设基。在原始数据集中,按照每个顾客的访问时间对组进行排序,在临时数据集中,组从每个顾客的第二次访问时间开始排序,临时数据集中的组号与原始数据集的组号相同,但其访问时间是下一个访问原始数据集。使用虚拟组,可以很容易地找到在哈希表下次访问期间被重新购买的相同产品。

proc sort data=smp; 
by identifier trx_date; 
run; 

data have(drop=_group) temp(drop=group rename=(_group=group)); 
    set smp; 
    by identifier trx_date; 
    if first.identifier then do; 
    group=1; _group=0; 
    end; 
    if dif(trx_date)>0 then do; 
     group+1; _group+1; 
    end; 
    if _group^=0 then output temp; 
    output have; 
run; 

data want; 
    if 0 then set temp; 
    if _n_=1 then do; 
     declare hash h(dataset:'temp'); 
     h.definekey('identifier','group','product_description'); 
     h.definedata('product_description'); 
     h.definedone(); 
    end; 
    set have; 
    flag=(h.find()=0); 
    drop group; 
run;   
+0

这里不需要虚拟组,你可以在散列查找('h.find(key:group + 1)'或类似的)中交互查找下一个组。 – Joe

0

的方法,下面将进行排序,所以你可以把比较到同一行的简单的逻辑后,“向前看”到下一行(相对滞后):

** convert character date to numeric **; 
data smp1; set smp; 
    TRX_DATE_NUM = input(TRX_DATE,ANYDTDTE10.); 
    format TRX_DATE_NUM mmddyy10.; 
run; 

** sort **; 
proc sort data = smp1; 
    by IDENTIFIER PRODUCT_DESCRIPTION TRX_DATE_NUM; 
run; 

** look ahead at the next observations and use logic to identify flags **; 
data look_ahead; 
    set smp1; 
    by IDENTIFIER; 
    set smp1 (firstobs = 2 
       keep = IDENTIFIER PRODUCT_DESCRIPTION TRX_DATE_NUM 
       rename = (IDENTIFIER = NEXT_ID PRODUCT_DESCRIPTION = NEXT_PROD TRX_DATE_NUM = NEXT_DT)) 
     smp1 (obs = 1 drop = _ALL_); 
    if last.IDENTIFIER then do; 
     NEXT_ID = ""; 
     NEXT_PROD = ""; 
     NEXT_DT = .; 
    end; 
run; 

** logic says if the next row is the same customer who bought the same product on a different date then flag **; 
data look_ahead_final; set look_ahead; 
    if IDENTIFIER = NEXT_ID and NEXT_PROD = PRODUCT_DESCRIPTION and TRX_DATE_NUM ne NEXT_DT then FLAG = 1; 
     else FLAG = 0; 
run; 
+0

我认为这与汤姆的答案有同样的问题;这会检查他们再次购买它,但不是他们在下次访问时购买它。 – Joe

+0

嗨,它确实检查他们是否再次购买,这是非常接近,但不一样,他们是否立即在下次访问。如果添加以下一行数据(Cust3,26dec2016,66-0070595440,COLLECT YOG LEMON),收集YOG LEMON在13feb2016上被错误标记。 – tezzaaa

0

有几个如何做到这一点;我认为理解最简单但仍具有合理的性能级别的方法是按降序排序数据,然后使用数组存储最后一个trx_date的product_descriptions。

这里我使用了一个2维数组,其中第一维只是一个1/2值;每个trx_date同时加载数组的一行,并检查数组的另一行(使用_array_switch来确定正在加载/检查哪一行)。

你可以用哈希表做同样的事情,它会明显快一些,在某些方面可能稍微复杂一点;如果你熟悉散列表并希望看到解决方案评论,并且我或其他人可以提供它。

你也可以使用SQL来做到这一点,我认为这是最常见的解决方案,但我不能完全理解它的工作原理,因为它与子查询中的子查询有一些复杂性, ,而且我显然还不够好。

以下是阵列解决方案。将prods的第二维设置为您的数据的合理上限 - 它甚至可能是数千,这是一个临时数组,并且不会使用太多的内存,因此设置为32000或其他任何内容都不是什么大问题。

proc sort data=smp; 
    by identifier descending trx_date ; 
run; 

data want; 
    array prods[2,20] $255. _temporary_; 
    retain _array_switch 2; 
    do _n_ = 1 by 1 until (last.trx_date); 
    set smp; 
    by identifier descending trx_date; 
    /* for first row for an identifier, clear out the whole thing */ 
    if first.identifier then do; 
     call missing(of prods[*]); 
    end; 

    /* for first row of a trx_date, clear out the array-row we were looking at last time, and switch _array_switch to the other value */ 
    if first.trx_date then do; 
     do _i = 1 to dim(prods,2); 
     if missing(prods[_array_switch,_i]) then leave; 
     call missing(prods[_array_switch,_i]); 
     end; 
     _array_switch = 3-_array_switch; 
    end; 

    *now check the array to see if we should set next_trans_flag; 

    next_trans_flag='N'; 
    do _i = 1 to dim(prods,2); 
     if missing(prods[_array_switch,_i]) then leave; *for speed; 
     if prods[_array_switch,_i] = product_description then next_trans_flag='Y';  
    end; 
    prods[3-_array_switch,_n_] = product_description; *set for next trx_date; 
    output; 
    end; 
    drop _:; 
run; 
+0

。嗨,我查过了,这似乎工作!非常感谢你 - ) – tezzaaa

0

我认为,要真正回答这个问题,你需要生成的不同访问*产品组合的清单。并且还列出了在特定访问中购买的不同产品的列表。

proc sql noprint ; 
    create table bought as 
    select distinct identifier, product_description, trx_date, transaction_id 
    from smp 
    order by 1,2,3,4 
    ; 
    create table all_visits as 
    select a.identifier, product_description, trx_date, transaction_id 
    from (select distinct identifier,product_description from bought) a 
    natural join (select distinct identifier,transaction_id,trx_date from bought) b 
    order by 1,2,3,4 
    ; 
quit; 

然后,您可以将它们合并在一起,并标记该产品是否在该次访问中购买。

data check ; 
    merge all_visits bought(in=in1) ; 
    by identifier product_description trx_date transaction_id ; 
    bought=in1; 
run; 

您现在可以使用一个lead技术弄清楚,如果他们也购买了该产品在下次访问。

data flag ; 
    set check ; 
    by identifier product_description trx_date transaction_id ; 
    set check(firstobs=2 keep=bought rename=(bought=bought_next)) check(drop=_all_ obs=1); 
    if last.product_description then bought_next=0; 
run; 

然后,您可以结合实际购买并消除额外的虚拟记录。

proc sort data=smp; 
    by identifier product_description trx_date transaction_id ; 
run; 

data want ; 
    merge flag smp (in=in1); 
    by identifier product_description trx_date transaction_id ; 
    if in1 ; 
run; 

让我们把记录放回原来的顺序,以便我们检查结果。

proc sort; by row; run; 
proc print; run; 

enter image description here