2017-04-03 14 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

相關問題