Preparing Data

Libraries
Sys.setlocale("LC_ALL","C")
[1] "C"
rm(list=ls(all=TRUE))
load("data/tf2.rdata")
library(dplyr)
library(ggplot2)
library(caTools)
library(Matrix)
library(rpart)
library(rpart.plot)
library(caret)
library(doParallel)
計算聖誕節前一週有沒有來買
X$CHR=as.numeric(X$date)
X$CHR1=X$CHR>=11309 & X$CHR<=11315
X$CHR2=as.numeric(X$CHR1)
計算顧客最常禮拜幾來買
# table(X$cust) %>% sort %>% tail
maxWeekday = function(x){
  y = table(x) %>% t %>% as.matrix
  result = which.max(y) %>% 
    colnames(y)[.] %>% 
    as.Date %>% 
    weekdays
  return(result)
}

新增變數

  • prodPrice
  • weekday
  • CHR
  • k
  • areaEFH
  • mon1
  • mon2
  • mon3
d0 = max(X$date)
NewVar = group_by(X, cust) %>% summarise(
  prodPrice = mean(total / pieces), # 商品平均單價
  weekday = maxWeekday(date), # 顧客最常禮拜幾來買
  CHR = sum(CHR2)>0, # chistmas
  k = (1 + as.integer(difftime(max(date), min(date), units="days"))) / n(), # 個人平均購買週期
  areaEFH = ((first(area)=="E") | (first(area)=="F") | (first(area)=="H")), # 是否住在EFH區域
  areaACDEF = ((first(area)=="A") | (first(area)=="C") | (first(area)=="D") | (first(area)=="E") | (first(area)=="F")),# 是否住在ACDEF區域
  mon1 = sum(date<="2000-11-30"),
  mon2 = sum(date<="2000-12-31" & date>"2000-11-30"),
  mon3 = sum(date<="2001-01-31" & date>"2000-12-31")
  ) %>% data.frame    # 28584
將我們新增的變數和資料A合併
A = merge(A, NewVar, all.x = T)
把weekday轉換成有順序性的facotr變數
A$weekday = factor(A$weekday
    , ordered=TRUE
    , levels=c("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"))

新增變數: 年齡區間

將年齡區分為更寬的range:

  • 35歲以下為1
  • 35~50以下為2
  • 50以上為3
A$ageGroup = sapply(seq(1,nrow(A),1), function(x){
  if((A[x, "age"] == "A") | (A[x, "age"] == "B") | (A[x, "age"] == "C")) 
    A$ageGroup = 1
  else if((A[x, "age"] == "D") | (A[x, "age"] == "E") | (A[x, "age"] == "F")) 
    A$ageGroup = 2
  else
    A$ageGroup = 3
})
A$ageGroup = as.factor(A$ageGroup)

新增變數: Weekday Percentage: W1 ~ W7

X = X %>% mutate(wday = format(date, "%w"))
# table(X$wday)
# 顧客星期矩陣
mx = xtabs(~ cust + wday, X)
# dim(mx)
# mx[1:5,]
mx = mx / rowSums(mx)
# mx[1:5,]
A = data.frame(as.integer(rownames(mx)), as.matrix.data.frame(mx)) %>% 
  setNames(c("cust","W1","W2","W3","W4","W5","W6","W7")) %>% 
  right_join(A, by='cust')

新增變數: 偏向週末或平日消費

算出顧客偏向週末或是平日來消費:

  • 若偏好週末消費則為 1
  • 若無特別偏好則為 2
  • 若偏好平日消費則為3
A$weekend = sapply(seq(1,nrow(A),1), function(x){
  w15 = A[x,c("W1","W2","W3","W4","W5")] %>% sum
  w67 = A[x,c("W6","W7")] %>% sum
  if(w67>w15) 
    A$weekend = 1
  else if(w67==w15)
    A$weekend = 2
  else
    A$weekend = 3
})
A$weekend = as.factor(A$weekend)

新增變數 : 是否有購買前5大、10大、20大熱銷產品 及 前20個熱銷產品分別購買次數

顧客產品矩陣
library(Matrix)
library(slam)
Z = subset(Z, cust %in% A$cust & date < as.Date("2001-02-01"))
cpm = xtabs(~ cust + prod, Z, sparse=T)
刪去購買次數小於10的產品
table(colSums(cpm) < 10)       # 12588 

FALSE  TRUE 
 9652 12862 
cpm = cpm[, colSums(cpm) > 10]   # 
cpm = cpm[, order(-colSums(cpm))]   # order product by frequency
dim(cpm)                            # 32241 23787>14621
[1] 28584  9149
是否有購買前5大、10大、20大熱銷產品
hot5 = cpm[,1:5] %>% rowSums
A$hot5 = hot5>0
hot10 = cpm[,1:10] %>% rowSums
A$hot10 = hot10>0
hot20 = cpm[,1:20] %>% rowSums
A$hot20 = hot20>0
前20個熱銷產品分別購買次數

確認cpm和A的顧客順序及大小是否有相同

cpm = cpm %>% as.matrix
(A$cust == rownames(cpm)) %>% sum
[1] 28584

合併兩個資料並將欄位名稱變更

A = cbind(A,cpm[,1:20])
colnames(A)[33:52] = sapply(seq(33,52,1), function(x){
  names = paste0("p",colnames(A)[x])
})
summary
summary(A)
      cust                W1               W2        
 Min.   :    1069   Min.   :0.0000   Min.   :0.0000  
 1st Qu.: 1060898   1st Qu.:0.0000   1st Qu.:0.0000  
 Median : 1654100   Median :0.0000   Median :0.0000  
 Mean   : 1461070   Mean   :0.2310   Mean   :0.1399  
 3rd Qu.: 1945003   3rd Qu.:0.3484   3rd Qu.:0.2000  
 Max.   :20002000   Max.   :1.0000   Max.   :1.0000  
                                                     
       W3               W4              W5               W6        
 Min.   :0.0000   Min.   :0.000   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:0.0000   1st Qu.:0.000   1st Qu.:0.0000   1st Qu.:0.0000  
 Median :0.0000   Median :0.000   Median :0.0000   Median :0.0000  
 Mean   :0.1176   Mean   :0.103   Mean   :0.1188   Mean   :0.1136  
 3rd Qu.:0.1333   3rd Qu.:0.000   3rd Qu.:0.1354   3rd Qu.:0.1111  
 Max.   :1.0000   Max.   :1.000   Max.   :1.0000   Max.   :1.0000  
                                                                   
       W7               r               s               f         
 Min.   :0.0000   Min.   : 1.00   Min.   : 1.00   Min.   : 1.000  
 1st Qu.:0.0000   1st Qu.:11.00   1st Qu.:47.00   1st Qu.: 1.000  
 Median :0.0000   Median :21.00   Median :68.00   Median : 2.000  
 Mean   :0.1762   Mean   :32.12   Mean   :61.27   Mean   : 3.089  
 3rd Qu.:0.2500   3rd Qu.:53.00   3rd Qu.:83.00   3rd Qu.: 4.000  
 Max.   :1.0000   Max.   :92.00   Max.   :92.00   Max.   :60.000  
                                                                  
       m                rev             raw               age      
 Min.   :    8.0   Min.   :    8   Min.   : -742.0   D      :5832  
 1st Qu.:  359.4   1st Qu.:  638   1st Qu.:   70.0   C      :5238  
 Median :  709.5   Median : 1566   Median :  218.0   E      :4514  
 Mean   : 1012.4   Mean   : 2711   Mean   :  420.8   F      :3308  
 3rd Qu.: 1315.0   3rd Qu.: 3426   3rd Qu.:  535.0   B      :2802  
 Max.   :10634.0   Max.   :99597   Max.   :15565.0   G      :1940  
                                                     (Other):4950  
      area          amount         buy            prodPrice      
 E      :9907   Min.   :    8   Mode :logical   Min.   :   5.00  
 F      :7798   1st Qu.:  454   FALSE:15342     1st Qu.:  63.36  
 C      :3169   Median :  993   TRUE :13242     Median :  86.44  
 G      :3052   Mean   : 1499                   Mean   : 115.97  
 D      :1778   3rd Qu.: 1955                   3rd Qu.: 123.20  
 H      :1295   Max.   :28089                   Max.   :3939.00  
 (Other):1585   NA's   :15342                                    
      weekday        CHR                k           areaEFH       
 Sunday   :6761   Mode :logical   Min.   : 1.000   Mode :logical  
 Monday   :3463   FALSE:27066     1st Qu.: 1.000   FALSE:9584     
 Tuesday  :2900   TRUE :1518      Median : 5.571   TRUE :19000    
 Wednesday:2727                   Mean   : 8.550                  
 Thursday :3878                   3rd Qu.:14.000                  
 Friday   :3617                   Max.   :45.000                  
 Saturday :5238                                                   
 areaACDEF            mon1             mon2              mon3       
 Mode :logical   Min.   : 0.000   Min.   : 0.0000   Min.   : 0.000  
 FALSE:5130      1st Qu.: 0.000   1st Qu.: 0.0000   1st Qu.: 0.000  
 TRUE :23454     Median : 1.000   Median : 1.0000   Median : 1.000  
                 Mean   : 1.112   Mean   : 0.9339   Mean   : 1.043  
                 3rd Qu.: 1.000   3rd Qu.: 1.0000   3rd Qu.: 1.000  
                 Max.   :26.000   Max.   :21.0000   Max.   :25.000  
                                                                    
 ageGroup  weekend      hot5           hot10           hot20        
 1: 9445   1: 5337   Mode :logical   Mode :logical   Mode :logical  
 2:13654   2: 3205   FALSE:19029     FALSE:16425     FALSE:13336    
 3: 5485   3:20042   TRUE :9555      TRUE :12159     TRUE :15248    
                                                                    
                                                                    
                                                                    
                                                                    
 p4711271000014   p4714981010038    p4719090900065   
 Min.   :0.0000   Min.   : 0.0000   Min.   :0.00000  
 1st Qu.:0.0000   1st Qu.: 0.0000   1st Qu.:0.00000  
 Median :0.0000   Median : 0.0000   Median :0.00000  
 Mean   :0.1837   Mean   : 0.1631   Mean   :0.07679  
 3rd Qu.:0.0000   3rd Qu.: 0.0000   3rd Qu.:0.00000  
 Max.   :5.0000   Max.   :16.0000   Max.   :6.00000  
                                                     
 p4711080010112     p4710908131589   p4713985863121 
 Min.   : 0.00000   Min.   :0.0000   Min.   :0.000  
 1st Qu.: 0.00000   1st Qu.:0.0000   1st Qu.:0.000  
 Median : 0.00000   Median :0.0000   Median :0.000  
 Mean   : 0.06014   Mean   :0.0543   Mean   :0.053  
 3rd Qu.: 0.00000   3rd Qu.:0.0000   3rd Qu.:0.000  
 Max.   :21.00000   Max.   :8.0000   Max.   :9.000  
                                                    
 p4710114128038    p4710421090059    p4710291112172  
 Min.   :0.00000   Min.   : 0.0000   Min.   :0.0000  
 1st Qu.:0.00000   1st Qu.: 0.0000   1st Qu.:0.0000  
 Median :0.00000   Median : 0.0000   Median :0.0000  
 Mean   :0.05153   Mean   : 0.0515   Mean   :0.0508  
 3rd Qu.:0.00000   3rd Qu.: 0.0000   3rd Qu.:0.0000  
 Max.   :5.00000   Max.   :13.0000   Max.   :5.0000  
                                                     
 p4712425010712    p4710583996008    p4710011401128   
 Min.   :0.00000   Min.   :0.00000   Min.   :0.00000  
 1st Qu.:0.00000   1st Qu.:0.00000   1st Qu.:0.00000  
 Median :0.00000   Median :0.00000   Median :0.00000  
 Mean   :0.05076   Mean   :0.04894   Mean   :0.04807  
 3rd Qu.:0.00000   3rd Qu.:0.00000   3rd Qu.:0.00000  
 Max.   :5.00000   Max.   :7.00000   Max.   :8.00000  
                                                      
 p4710088410139    p4719090900058     p4710094097768    
 Min.   :0.00000   Min.   : 0.00000   Min.   : 0.00000  
 1st Qu.:0.00000   1st Qu.: 0.00000   1st Qu.: 0.00000  
 Median :0.00000   Median : 0.00000   Median : 0.00000  
 Mean   :0.04803   Mean   : 0.04628   Mean   : 0.04429  
 3rd Qu.:0.00000   3rd Qu.: 0.00000   3rd Qu.: 0.00000  
 Max.   :5.00000   Max.   :13.00000   Max.   :17.00000  
                                                        
 p4710088410610    p4710085120628    p4710265849066   
 Min.   :0.00000   Min.   :0.00000   Min.   :0.00000  
 1st Qu.:0.00000   1st Qu.:0.00000   1st Qu.:0.00000  
 Median :0.00000   Median :0.00000   Median :0.00000  
 Mean   :0.04394   Mean   :0.04121   Mean   :0.04058  
 3rd Qu.:0.00000   3rd Qu.:0.00000   3rd Qu.:0.00000  
 Max.   :6.00000   Max.   :7.00000   Max.   :4.00000  
                                                      
 p4710018004605    p4710908131534   
 Min.   :0.00000   Min.   :0.00000  
 1st Qu.:0.00000   1st Qu.:0.00000  
 Median :0.00000   Median :0.00000  
 Mean   :0.03985   Mean   :0.03778  
 3rd Qu.:0.00000   3rd Qu.:0.00000  
 Max.   :6.00000   Max.   :5.00000  
                                    



Spliting the Data

A$buy = factor(ifelse(A$buy, "yes", "no"))  # comply to the rule of caret
TR = A[spl, ]
TS = A[!spl, ]
# 把"cust"及"amount"欄位拿掉
TR1 = subset(TR, select = -c(cust, amount))
TS1 = subset(TS, select = -c(cust, amount))



Turn on Parallel Processing
#做平行運算
library(doParallel)
clust = makeCluster(detectCores())
registerDoParallel(clust); getDoParWorkers()
[1] 4



CART Classification Model

CV Control for Classification
ctrl = trainControl(
  method="repeatedcv", number=10,    # 10-fold, Repeated CV
  savePredictions = "final", classProbs=TRUE,
  summaryFunction=twoClassSummary)
CV: rpart(), Classification Tree
ctrl$repeats = 2
t0 = Sys.time(); set.seed(2)
cv.rpart = train(
  buy ~ ., data=TR1, method="rpart", 
  trControl=ctrl, metric="ROC",
  tuneGrid = expand.grid(.cp = seq(0.0002,0.001,0.0001)))
Sys.time() - t0
Time difference of 35.16521 secs
plot(cv.rpart);cv.rpart
CART 

20008 samples
   49 predictor
    2 classes: 'no', 'yes' 

No pre-processing
Resampling: Cross-Validated (10 fold, repeated 2 times) 
Summary of sample sizes: 18007, 18007, 18007, 18007, 18007, 18007, ... 
Resampling results across tuning parameters:

  cp     ROC        Sens       Spec     
  2e-04  0.6945636  0.7386622  0.5807015
  3e-04  0.7063938  0.7728375  0.5760073
  4e-04  0.7161350  0.7787498  0.5792441
  5e-04  0.7234962  0.7929951  0.5694282
  6e-04  0.7256986  0.7994671  0.5675938
  7e-04  0.7275238  0.8028204  0.5660290
  8e-04  0.7258432  0.8104117  0.5597687
  9e-04  0.7236823  0.8129257  0.5577191
  1e-03  0.7224932  0.8109231  0.5605789

ROC was used to select the optimal model using the largest value.
The final value used for the model was cp = 7e-04.

Classification Tree, Final Model

第一層分歧點是f<3
第二層則分別是f<2 與 f<5
代表f(frequency購買頻率)對buy的影響力很大
最右邊的terminal node更是只經過兩層判斷: f>=3 → f>=5
也就是f >= 5 就直接判斷buy = TRUE

compute AUC
colAUC(PredictCART1,TS$buy)
                [,1]
no vs. yes 0.7449168

CART model without cp Classification Model

# CART model
rpart2 = rpart(buy ~ ., data = TR1, method="class")
# Make predictions
PredictCART2 = predict(rpart2, newdata = TS1, type = "prob")[,2]
compute AUC
colAUC(PredictCART2, TS$buy)
                [,1]
no vs. yes 0.6983998

GLM Classification Model

glm2 = glm(buy ~ . -W7 -W1 -W2 -W3 -W4 -W5 -W6 -age -areaEFH -areaACDEF -weekday -weekend -hot20 -hot10 -hot5 -ageGroup - CHR -mon1 -mon2 -mon3 , TR1[,1:30], family=binomial())
summary(glm2)

Call:
glm(formula = buy ~ . - W7 - W1 - W2 - W3 - W4 - W5 - W6 - age - 
    areaEFH - areaACDEF - weekday - weekend - hot20 - hot10 - 
    hot5 - ageGroup - CHR - mon1 - mon2 - mon3, family = binomial(), 
    data = TR1[, 1:30])

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-3.5126  -0.8816  -0.7090   1.0349   2.3789  

Coefficients:
              Estimate Std. Error z value Pr(>|z|)    
(Intercept) -1.034e+00  1.083e-01  -9.551  < 2e-16 ***
r           -2.108e-02  2.319e-03  -9.091  < 2e-16 ***
s            1.821e-02  2.341e-03   7.776 7.47e-15 ***
f            2.252e-01  2.215e-02  10.170  < 2e-16 ***
m           -3.110e-06  2.780e-05  -0.112  0.91093    
rev          4.874e-05  1.958e-05   2.489  0.01281 *  
raw         -2.850e-04  8.663e-05  -3.290  0.00100 ** 
areaB       -3.508e-02  1.321e-01  -0.266  0.79059    
areaC       -2.072e-01  1.044e-01  -1.985  0.04716 *  
areaD        3.703e-02  1.109e-01   0.334  0.73850    
areaE        2.606e-01  9.672e-02   2.695  0.00705 ** 
areaF        1.773e-01  9.738e-02   1.821  0.06859 .  
areaG       -4.751e-02  1.043e-01  -0.456  0.64869    
areaH       -1.878e-01  1.215e-01  -1.545  0.12234    
prodPrice   -7.209e-04  1.491e-04  -4.836 1.32e-06 ***
k           -2.034e-02  5.019e-03  -4.054 5.04e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 27629  on 20007  degrees of freedom
Residual deviance: 23270  on 19992  degrees of freedom
AIC: 23302

Number of Fisher Scoring iterations: 6

把age刪掉 多k,prodPrice

compute AUC
predGLM =  predict(glm2, TS1, type="response")
colAUC(predGLM, TS$buy)
                [,1]
no vs. yes 0.7578518
TS$buy %>% table
.
  no  yes 
4603 3973 
confuse matrix
cm = table(actual = TS1$buy, predict = predGLM > 0.5); cm
      predict
actual FALSE TRUE
   no   3822  781
   yes  1759 2214
compute accuracy
acc.ts = cm %>% {sum(diag(.))/sum(.)}; acc.ts 
[1] 0.7038246

Classification ModelEnsembling

# GLM + CART1
result = (predGLM + PredictCART1)/2
colAUC(result, TS$buy)
                [,1]
no vs. yes 0.7584242
# GLM + CART2
result = (predGLM + PredictCART2)/2
colAUC(result, TS$buy) # higher
                [,1]
no vs. yes 0.7584827




Regression Model

Preparing the Data
A2 = subset(A, A$buy == "yes") %>% mutate_at(c("m","rev","amount"), log10)
TR2 = subset(A2, spl2) %>% subset(., select = -c(cust, buy))
TS2 = subset(A2, !spl2) %>% subset(., select = -c(cust, buy))

linear model

lm1 = lm(amount ~ . -W7 -W1 -W2 -W3 -W4 -W5 -W6  -areaACDEF-area -weekday  -hot5-hot10-hot20-ageGroup-mon1-mon2 ,TR2)
summary(lm1)

Call:
lm(formula = amount ~ . - W7 - W1 - W2 - W3 - W4 - W5 - W6 - 
    areaACDEF - area - weekday - hot5 - hot10 - hot20 - ageGroup - 
    mon1 - mon2, data = TR2)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.8497 -0.2264  0.0478  0.2769  1.5540 

Coefficients:
                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)     1.335e+00  4.704e-02  28.376  < 2e-16 ***
r              -1.546e-03  5.262e-04  -2.937  0.00332 ** 
s               2.038e-03  5.155e-04   3.954 7.73e-05 ***
f               1.170e-02  2.705e-03   4.325 1.54e-05 ***
m               5.367e-01  4.345e-02  12.350  < 2e-16 ***
rev            -3.019e-02  4.133e-02  -0.731  0.46505    
raw             6.186e-05  8.795e-06   7.033 2.16e-12 ***
ageB            7.682e-02  2.492e-02   3.082  0.00206 ** 
ageC            1.194e-01  2.289e-02   5.218 1.85e-07 ***
ageD            1.262e-01  2.259e-02   5.588 2.37e-08 ***
ageE            1.321e-01  2.312e-02   5.712 1.15e-08 ***
ageF            1.054e-01  2.416e-02   4.365 1.29e-05 ***
ageG            8.057e-02  2.635e-02   3.058  0.00223 ** 
ageH            7.178e-02  3.106e-02   2.311  0.02083 *  
ageI            6.980e-02  3.196e-02   2.184  0.02899 *  
ageJ           -1.970e-02  2.806e-02  -0.702  0.48279    
ageK            1.130e-01  3.768e-02   2.999  0.00272 ** 
prodPrice      -3.198e-04  5.026e-05  -6.364 2.07e-10 ***
CHRTRUE        -4.254e-02  1.746e-02  -2.437  0.01484 *  
k              -5.485e-03  1.073e-03  -5.111 3.26e-07 ***
areaEFHTRUE    -1.471e-02  1.029e-02  -1.430  0.15289    
mon3            1.524e-02  4.845e-03   3.145  0.00166 ** 
weekend2       -3.722e-03  1.755e-02  -0.212  0.83209    
weekend3       -4.709e-03  1.262e-02  -0.373  0.70897    
p4711271000014 -1.239e-02  9.222e-03  -1.343  0.17922    
p4714981010038 -1.616e-02  8.396e-03  -1.925  0.05428 .  
p4719090900065 -1.011e-02  1.227e-02  -0.824  0.40996    
p4711080010112  1.684e-03  9.343e-03   0.180  0.85697    
p4710908131589  1.263e-02  1.461e-02   0.864  0.38752    
p4713985863121  2.320e-02  1.386e-02   1.674  0.09424 .  
p4710114128038  1.809e-02  1.445e-02   1.252  0.21066    
p4710421090059 -1.361e-02  1.319e-02  -1.031  0.30247    
p4710291112172  3.389e-02  1.499e-02   2.262  0.02374 *  
p4712425010712  3.541e-02  1.513e-02   2.340  0.01929 *  
p4710583996008  1.054e-02  1.377e-02   0.766  0.44376    
p4710011401128 -1.081e-03  1.237e-02  -0.087  0.93037    
p4710088410139  4.659e-03  1.527e-02   0.305  0.76035    
p4719090900058  2.458e-02  1.613e-02   1.524  0.12764    
p4710094097768  1.946e-02  1.103e-02   1.765  0.07760 .  
p4710088410610  1.353e-02  1.377e-02   0.982  0.32598    
p4710085120628  6.767e-04  1.616e-02   0.042  0.96661    
p4710265849066 -1.987e-02  1.750e-02  -1.135  0.25628    
p4710018004605  1.555e-02  1.562e-02   0.996  0.31935    
p4710908131534 -7.272e-04  1.635e-02  -0.044  0.96453    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.4179 on 9225 degrees of freedom
Multiple R-squared:  0.305, Adjusted R-squared:  0.3017 
F-statistic: 94.14 on 43 and 9225 DF,  p-value: < 2.2e-16

compute R-squared

r2.tr = summary(lm1)$r.sq
SST = sum((TS2$amount - mean(TR2$amount))^ 2)
SSE = sum((predict(lm1, TS2) -  TS2$amount)^2)
r2.ts = 1 - (SSE/SST)
c(r2.tr, r2.ts)
[1] 0.3049726 0.2732476

CART Regression Model

Cross-Validation
library(caret)
library(e1071)
library(rpart)
# Define cross-validation experiment
# k=10
numFolds = trainControl( method = "cv", number = 10 ) 
# pick the posiible values for cp
cpGrid = expand.grid( .cp = seq(0.001,0.1,0.001)) 
# Perform the cross validation
cv = train(amount ~ ., data = TR2, method = "rpart", trControl = numFolds, tuneGrid = cpGrid )
# method="rpart" : we wanto to validate a CART model
plot(cv);cv
CART 

9269 samples
  49 predictor

No pre-processing
Resampling: Cross-Validated (10 fold) 
Summary of sample sizes: 8342, 8342, 8344, 8341, 8343, 8343, ... 
Resampling results across tuning parameters:

  cp     RMSE       Rsquared   MAE      
  0.001  0.4292028  0.2690773  0.3282264
  0.002  0.4252379  0.2792146  0.3270657
  0.003  0.4259257  0.2767614  0.3279024
  0.004  0.4270146  0.2727301  0.3293621
  0.005  0.4276177  0.2700327  0.3302938
  0.006  0.4280014  0.2686708  0.3308160
  0.007  0.4285473  0.2667992  0.3310266
  0.008  0.4291134  0.2649987  0.3312590
  0.009  0.4305926  0.2599312  0.3320272
  0.010  0.4331756  0.2514542  0.3344812
  0.011  0.4332454  0.2511085  0.3346050
  0.012  0.4332454  0.2511085  0.3346050
  0.013  0.4352086  0.2444000  0.3362385
  0.014  0.4367615  0.2389578  0.3377461
  0.015  0.4374698  0.2363249  0.3379678
  0.016  0.4374698  0.2363249  0.3379678
  0.017  0.4374698  0.2363249  0.3379678
  0.018  0.4374698  0.2363249  0.3379678
  0.019  0.4374698  0.2363249  0.3379678
  0.020  0.4375541  0.2357503  0.3380023
  0.021  0.4375541  0.2357503  0.3380023
  0.022  0.4375541  0.2357503  0.3380023
  0.023  0.4375541  0.2357503  0.3380023
  0.024  0.4375541  0.2357503  0.3380023
  0.025  0.4375541  0.2357503  0.3380023
  0.026  0.4375541  0.2357503  0.3380023
  0.027  0.4375541  0.2357503  0.3380023
  0.028  0.4383222  0.2329409  0.3387731
  0.029  0.4383222  0.2329409  0.3387731
  0.030  0.4391150  0.2300391  0.3392694
  0.031  0.4420512  0.2195971  0.3413720
  0.032  0.4439264  0.2129179  0.3424785
  0.033  0.4445446  0.2108207  0.3428081
  0.034  0.4447775  0.2100530  0.3430843
  0.035  0.4447775  0.2100530  0.3430843
  0.036  0.4447775  0.2100530  0.3430843
  0.037  0.4447775  0.2100530  0.3430843
  0.038  0.4447775  0.2100530  0.3430843
  0.039  0.4447775  0.2100530  0.3430843
  0.040  0.4447775  0.2100530  0.3430843
  0.041  0.4447775  0.2100530  0.3430843
  0.042  0.4447775  0.2100530  0.3430843
  0.043  0.4447775  0.2100530  0.3430843
  0.044  0.4447775  0.2100530  0.3430843
  0.045  0.4447775  0.2100530  0.3430843
  0.046  0.4447775  0.2100530  0.3430843
  0.047  0.4447775  0.2100530  0.3430843
  0.048  0.4495928  0.1929573  0.3471033
  0.049  0.4550808  0.1731512  0.3517455
  0.050  0.4562046  0.1691672  0.3531857
  0.051  0.4571753  0.1655309  0.3539768
  0.052  0.4571753  0.1655309  0.3539768
  0.053  0.4571753  0.1655309  0.3539768
  0.054  0.4571753  0.1655309  0.3539768
  0.055  0.4589018  0.1591169  0.3553477
  0.056  0.4589018  0.1591169  0.3553477
  0.057  0.4589018  0.1591169  0.3553477
  0.058  0.4589018  0.1591169  0.3553477
  0.059  0.4589018  0.1591169  0.3553477
  0.060  0.4589018  0.1591169  0.3553477
  0.061  0.4589018  0.1591169  0.3553477
  0.062  0.4589018  0.1591169  0.3553477
  0.063  0.4589018  0.1591169  0.3553477
  0.064  0.4589018  0.1591169  0.3553477
  0.065  0.4589018  0.1591169  0.3553477
  0.066  0.4589018  0.1591169  0.3553477
  0.067  0.4589018  0.1591169  0.3553477
  0.068  0.4589018  0.1591169  0.3553477
  0.069  0.4589018  0.1591169  0.3553477
  0.070  0.4589018  0.1591169  0.3553477
  0.071  0.4589018  0.1591169  0.3553477
  0.072  0.4589018  0.1591169  0.3553477
  0.073  0.4589018  0.1591169  0.3553477
  0.074  0.4589018  0.1591169  0.3553477
  0.075  0.4589018  0.1591169  0.3553477
  0.076  0.4589018  0.1591169  0.3553477
  0.077  0.4589018  0.1591169  0.3553477
  0.078  0.4589018  0.1591169  0.3553477
  0.079  0.4589018  0.1591169  0.3553477
  0.080  0.4589018  0.1591169  0.3553477
  0.081  0.4589018  0.1591169  0.3553477
  0.082  0.4589018  0.1591169  0.3553477
  0.083  0.4589018  0.1591169  0.3553477
  0.084  0.4589018  0.1591169  0.3553477
  0.085  0.4589018  0.1591169  0.3553477
  0.086  0.4589018  0.1591169  0.3553477
  0.087  0.4589018  0.1591169  0.3553477
  0.088  0.4589018  0.1591169  0.3553477
  0.089  0.4589018  0.1591169  0.3553477
  0.090  0.4589018  0.1591169  0.3553477
  0.091  0.4589018  0.1591169  0.3553477
  0.092  0.4589018  0.1591169  0.3553477
  0.093  0.4589018  0.1591169  0.3553477
  0.094  0.4589018  0.1591169  0.3553477
  0.095  0.4589018  0.1591169  0.3553477
  0.096  0.4589018  0.1591169  0.3553477
  0.097  0.4589018  0.1591169  0.3553477
  0.098  0.4589018  0.1591169  0.3553477
  0.099  0.4589018  0.1591169  0.3553477
  0.100  0.4589018  0.1591169  0.3553477

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was cp = 0.002.

Create a CART model

rpart2 = rpart(amount ~ ., data = TR2, cp = 0.002)
SST = sum((TS2$amount - mean(TR2$amount))^ 2)
SSE = sum((predict(rpart2, TS2) -  TS2$amount)^2)
1 - (SSE/SST)
[1] 0.2521828

model ensembling

predLM = predict(lm1, newdata=TS2)
predCART = predict(rpart2, newdata=TS2)
result = (predLM + predCART)/2
SST = sum((TS2$amount - mean(TR2$amount))^ 2)
SSE = sum((result -  TS2$amount)^2)
1 - (SSE/SST)
[1] 0.2740926




Stop Parallel Processing
stopCluster(clust)








LS0tDQp0aXRsZTogIkRhdGEgUHJlcGFyYXRpb24sIFRhLUZlbmciDQphdXRob3I6ICJHcm91cCA0ICA4LzYiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQo8YnI+DQoNCiMjIyBQcmVwYXJpbmcgRGF0YQ0KDQojIyMjIyBMaWJyYXJpZXMNCmBgYHtyIGVjaG89VCwgbWVzc2FnZT1GLCBjYWNoZT1GLCB3YXJuaW5nPUZ9DQpTeXMuc2V0bG9jYWxlKCJMQ19BTEwiLCJDIikNCnJtKGxpc3Q9bHMoYWxsPVRSVUUpKQ0KbG9hZCgiZGF0YS90ZjIucmRhdGEiKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoY2FUb29scykNCmxpYnJhcnkoTWF0cml4KQ0KbGlicmFyeShycGFydCkNCmxpYnJhcnkocnBhcnQucGxvdCkNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KGRvUGFyYWxsZWwpDQpgYGANCg0KDQojIyMjIyDoqIjnrpfogZboqpXnr4DliY3kuIDpgLHmnInmspLmnInkvobosrcNCmBgYHtyfQ0KWCRDSFI9YXMubnVtZXJpYyhYJGRhdGUpDQoNClgkQ0hSMT1YJENIUj49MTEzMDkgJiBYJENIUjw9MTEzMTUNClgkQ0hSMj1hcy5udW1lcmljKFgkQ0hSMSkNCmBgYA0KDQojIyMjIyMg6KiI566X6aGn5a6i5pyA5bi456au5ouc5bm+5L6G6LK3DQpgYGB7cn0NCiMgdGFibGUoWCRjdXN0KSAlPiUgc29ydCAlPiUgdGFpbA0KbWF4V2Vla2RheSA9IGZ1bmN0aW9uKHgpew0KICB5ID0gdGFibGUoeCkgJT4lIHQgJT4lIGFzLm1hdHJpeA0KICByZXN1bHQgPSB3aGljaC5tYXgoeSkgJT4lIA0KICAgIGNvbG5hbWVzKHkpWy5dICU+JSANCiAgICBhcy5EYXRlICU+JSANCiAgICB3ZWVrZGF5cw0KICByZXR1cm4ocmVzdWx0KQ0KfQ0KYGBgDQoNCiMjIyMg5paw5aKe6K6K5pW4DQogDQoqIHByb2RQcmljZQ0KKiB3ZWVrZGF5DQoqIENIUg0KKiBrDQoqIGFyZWFFRkgNCiogbW9uMQ0KKiBtb24yDQoqIG1vbjMNCg0KYGBge3J9DQpkMCA9IG1heChYJGRhdGUpDQpOZXdWYXIgPSBncm91cF9ieShYLCBjdXN0KSAlPiUgc3VtbWFyaXNlKA0KICBwcm9kUHJpY2UgPSBtZWFuKHRvdGFsIC8gcGllY2VzKSwgIyDllYblk4HlubPlnYfllq7lg7kNCiAgd2Vla2RheSA9IG1heFdlZWtkYXkoZGF0ZSksICMg6aGn5a6i5pyA5bi456au5ouc5bm+5L6G6LK3DQogIENIUiA9IHN1bShDSFIyKT4wLCAjIGNoaXN0bWFzDQogIGsgPSAoMSArIGFzLmludGVnZXIoZGlmZnRpbWUobWF4KGRhdGUpLCBtaW4oZGF0ZSksIHVuaXRzPSJkYXlzIikpKSAvIG4oKSwgIyDlgIvkurrlubPlnYfos7zosrfpgLHmnJ8NCiAgYXJlYUVGSCA9ICgoZmlyc3QoYXJlYSk9PSJFIikgfCAoZmlyc3QoYXJlYSk9PSJGIikgfCAoZmlyc3QoYXJlYSk9PSJIIikpLCAjIOaYr+WQpuS9j+WcqEVGSOWNgOWfnw0KICBhcmVhQUNERUYgPSAoKGZpcnN0KGFyZWEpPT0iQSIpIHwgKGZpcnN0KGFyZWEpPT0iQyIpIHwgKGZpcnN0KGFyZWEpPT0iRCIpIHwgKGZpcnN0KGFyZWEpPT0iRSIpIHwgKGZpcnN0KGFyZWEpPT0iRiIpKSwjIOaYr+WQpuS9j+WcqEFDREVG5Y2A5Z+fDQogIG1vbjEgPSBzdW0oZGF0ZTw9IjIwMDAtMTEtMzAiKSwNCiAgbW9uMiA9IHN1bShkYXRlPD0iMjAwMC0xMi0zMSIgJiBkYXRlPiIyMDAwLTExLTMwIiksDQogIG1vbjMgPSBzdW0oZGF0ZTw9IjIwMDEtMDEtMzEiICYgZGF0ZT4iMjAwMC0xMi0zMSIpDQogICkgJT4lIGRhdGEuZnJhbWUgICAgIyAyODU4NA0KYGBgDQoNCiMjIyMjIOWwh+aIkeWAkeaWsOWinueahOiuiuaVuOWSjOizh+aWmUHlkIjkvbUNCmBgYHtyfQ0KQSA9IG1lcmdlKEEsIE5ld1ZhciwgYWxsLnggPSBUKQ0KYGBgDQoNCg0KIyMjIyPmiop3ZWVrZGF56L2J5o+b5oiQ5pyJ6aCG5bqP5oCn55qEZmFjb3Ry6K6K5pW4DQpgYGB7cn0NCkEkd2Vla2RheSA9IGZhY3RvcihBJHdlZWtkYXkNCiAgICAsIG9yZGVyZWQ9VFJVRQ0KICAgICwgbGV2ZWxzPWMoIlN1bmRheSIsICJNb25kYXkiLCAiVHVlc2RheSIsICJXZWRuZXNkYXkiLCAiVGh1cnNkYXkiLCAiRnJpZGF5IiwgIlNhdHVyZGF5IikpDQpgYGANCg0KIyMjIyDmlrDlop7orormlbg6IOW5tOm9oeWNgOmWkw0KDQrlsIflubTpvaHljYDliIbngrrmm7Tlr6znmoRyYW5nZToNCg0KKiAzNeatsuS7peS4i+eCujENCiogMzV+NTDku6XkuIvngroyDQoqIDUw5Lul5LiK54K6Mw0KYGBge3J9DQpBJGFnZUdyb3VwID0gc2FwcGx5KHNlcSgxLG5yb3coQSksMSksIGZ1bmN0aW9uKHgpew0KICBpZigoQVt4LCAiYWdlIl0gPT0gIkEiKSB8IChBW3gsICJhZ2UiXSA9PSAiQiIpIHwgKEFbeCwgImFnZSJdID09ICJDIikpIA0KICAgIEEkYWdlR3JvdXAgPSAxDQogIGVsc2UgaWYoKEFbeCwgImFnZSJdID09ICJEIikgfCAoQVt4LCAiYWdlIl0gPT0gIkUiKSB8IChBW3gsICJhZ2UiXSA9PSAiRiIpKSANCiAgICBBJGFnZUdyb3VwID0gMg0KICBlbHNlDQogICAgQSRhZ2VHcm91cCA9IDMNCn0pDQpBJGFnZUdyb3VwID0gYXMuZmFjdG9yKEEkYWdlR3JvdXApDQpgYGANCg0KDQojIyMjIOaWsOWinuiuiuaVuDogV2Vla2RheSBQZXJjZW50YWdlOiBXMSB+IFc3DQpgYGB7cn0NClggPSBYICU+JSBtdXRhdGUod2RheSA9IGZvcm1hdChkYXRlLCAiJXciKSkNCiMgdGFibGUoWCR3ZGF5KQ0KDQojIOmhp+WuouaYn+acn+efqemZow0KbXggPSB4dGFicyh+IGN1c3QgKyB3ZGF5LCBYKQ0KIyBkaW0obXgpDQojIG14WzE6NSxdDQpteCA9IG14IC8gcm93U3VtcyhteCkNCiMgbXhbMTo1LF0NCmBgYA0KDQpgYGB7cn0NCkEgPSBkYXRhLmZyYW1lKGFzLmludGVnZXIocm93bmFtZXMobXgpKSwgYXMubWF0cml4LmRhdGEuZnJhbWUobXgpKSAlPiUgDQogIHNldE5hbWVzKGMoImN1c3QiLCJXMSIsIlcyIiwiVzMiLCJXNCIsIlc1IiwiVzYiLCJXNyIpKSAlPiUgDQogIHJpZ2h0X2pvaW4oQSwgYnk9J2N1c3QnKQ0KYGBgDQoNCiMjIyMg5paw5aKe6K6K5pW4OiDlgY/lkJHpgLHmnKvmiJblubPml6XmtojosrsNCg0K566X5Ye66aGn5a6i5YGP5ZCR6YCx5pyr5oiW5piv5bmz5pel5L6G5raI6LK7Og0KDQoqIOiLpeWBj+WlvemAseacq+a2iOiyu+WJh+eCuiAxIA0KKiDoi6XnhKHnibnliKXlgY/lpb3liYfngrogMg0KKiDoi6XlgY/lpb3lubPml6XmtojosrvliYfngrozDQoNCmBgYHtyfQ0KQSR3ZWVrZW5kID0gc2FwcGx5KHNlcSgxLG5yb3coQSksMSksIGZ1bmN0aW9uKHgpew0KICB3MTUgPSBBW3gsYygiVzEiLCJXMiIsIlczIiwiVzQiLCJXNSIpXSAlPiUgc3VtDQogIHc2NyA9IEFbeCxjKCJXNiIsIlc3IildICU+JSBzdW0NCiAgaWYodzY3PncxNSkgDQogICAgQSR3ZWVrZW5kID0gMQ0KICBlbHNlIGlmKHc2Nz09dzE1KQ0KICAgIEEkd2Vla2VuZCA9IDINCiAgZWxzZQ0KICAgIEEkd2Vla2VuZCA9IDMNCn0pDQpBJHdlZWtlbmQgPSBhcy5mYWN0b3IoQSR3ZWVrZW5kKQ0KYGBgDQoNCg0KDQojIyMjIOaWsOWinuiuiuaVuCA6IOaYr+WQpuacieizvOiyt+WJjTXlpKfjgIExMOWkp+OAgTIw5aSn54ax6Yq355Si5ZOBIOWPiiDliY0yMOWAi+eGsemKt+eUouWTgeWIhuWIpeizvOiyt+asoeaVuA0KDQojIyMjIyDpoaflrqLnlKLlk4Hnn6npmaMNCmBgYHtyfQ0KbGlicmFyeShNYXRyaXgpDQpsaWJyYXJ5KHNsYW0pDQoNClogPSBzdWJzZXQoWiwgY3VzdCAlaW4lIEEkY3VzdCAmIGRhdGUgPCBhcy5EYXRlKCIyMDAxLTAyLTAxIikpDQpjcG0gPSB4dGFicyh+IGN1c3QgKyBwcm9kLCBaLCBzcGFyc2U9VCkNCmBgYA0KDQojIyMjIyDliKrljrvos7zosrfmrKHmlbjlsI/mlrwxMOeahOeUouWTgQ0KYGBge3J9DQp0YWJsZShjb2xTdW1zKGNwbSkgPCAxMCkgICAgICAgIyAxMjU4OCANCmNwbSA9IGNwbVssIGNvbFN1bXMoY3BtKSA+IDEwXSAgICMgDQpjcG0gPSBjcG1bLCBvcmRlcigtY29sU3VtcyhjcG0pKV0gICAjIG9yZGVyIHByb2R1Y3QgYnkgZnJlcXVlbmN5DQpkaW0oY3BtKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIDMyMjQxIDIzNzg3PjE0NjIxDQpgYGANCg0KIyMjIyMg5piv5ZCm5pyJ6LO86LK35YmNNeWkp+OAgTEw5aSn44CBMjDlpKfnhrHpirfnlKLlk4ENCmBgYHtyfQ0KaG90NSA9IGNwbVssMTo1XSAlPiUgcm93U3Vtcw0KQSRob3Q1ID0gaG90NT4wDQoNCmhvdDEwID0gY3BtWywxOjEwXSAlPiUgcm93U3Vtcw0KQSRob3QxMCA9IGhvdDEwPjANCg0KaG90MjAgPSBjcG1bLDE6MjBdICU+JSByb3dTdW1zDQpBJGhvdDIwID0gaG90MjA+MA0KYGBgDQoNCiMjIyMjIOWJjTIw5YCL54ax6Yq355Si5ZOB5YiG5Yil6LO86LK35qyh5pW4DQrnorroqo1jcG3lkoxB55qE6aGn5a6i6aCG5bqP5Y+K5aSn5bCP5piv5ZCm5pyJ55u45ZCMDQpgYGB7cn0NCmNwbSA9IGNwbSAlPiUgYXMubWF0cml4DQooQSRjdXN0ID09IHJvd25hbWVzKGNwbSkpICU+JSBzdW0NCmBgYA0KDQrlkIjkvbXlhanlgIvos4fmlpnkuKblsIfmrITkvY3lkI3nqLHorormm7QNCmBgYHtyfQ0KQSA9IGNiaW5kKEEsY3BtWywxOjIwXSkNCg0KY29sbmFtZXMoQSlbMzM6NTJdID0gc2FwcGx5KHNlcSgzMyw1MiwxKSwgZnVuY3Rpb24oeCl7DQogIG5hbWVzID0gcGFzdGUwKCJwIixjb2xuYW1lcyhBKVt4XSkNCn0pDQpgYGANCg0KDQojIyMjIyBzdW1tYXJ5DQpgYGB7cn0NCnN1bW1hcnkoQSkNCmBgYA0KPGJyPjxicj48aHI+DQoNCg0KDQojIyMgU3BsaXRpbmcgdGhlIERhdGENCmBgYHtyfQ0KQSRidXkgPSBmYWN0b3IoaWZlbHNlKEEkYnV5LCAieWVzIiwgIm5vIikpICAjIGNvbXBseSB0byB0aGUgcnVsZSBvZiBjYXJldA0KVFIgPSBBW3NwbCwgXQ0KVFMgPSBBWyFzcGwsIF0NCg0KIyDmiooiY3VzdCLlj4oiYW1vdW50IuashOS9jeaLv+aOiQ0KVFIxID0gc3Vic2V0KFRSLCBzZWxlY3QgPSAtYyhjdXN0LCBhbW91bnQpKQ0KVFMxID0gc3Vic2V0KFRTLCBzZWxlY3QgPSAtYyhjdXN0LCBhbW91bnQpKQ0KYGBgDQoNCg0KPGJyPjxicj48aHI+DQoNCg0KDQoNCiMjIyMjIFR1cm4gb24gUGFyYWxsZWwgUHJvY2Vzc2luZw0KYGBge3J9DQoj5YGa5bmz6KGM6YGL566XDQpsaWJyYXJ5KGRvUGFyYWxsZWwpDQpjbHVzdCA9IG1ha2VDbHVzdGVyKGRldGVjdENvcmVzKCkpDQpyZWdpc3RlckRvUGFyYWxsZWwoY2x1c3QpOyBnZXREb1BhcldvcmtlcnMoKQ0KYGBgDQo8YnI+PGJyPjxocj4NCg0KDQojIyMgQ0FSVCBDbGFzc2lmaWNhdGlvbiBNb2RlbCANCg0KIyMjIyMgQ1YgQ29udHJvbCBmb3IgQ2xhc3NpZmljYXRpb24NCmBgYHtyfQ0KY3RybCA9IHRyYWluQ29udHJvbCgNCiAgbWV0aG9kPSJyZXBlYXRlZGN2IiwgbnVtYmVyPTEwLCAgICAjIDEwLWZvbGQsIFJlcGVhdGVkIENWDQogIHNhdmVQcmVkaWN0aW9ucyA9ICJmaW5hbCIsIGNsYXNzUHJvYnM9VFJVRSwNCiAgc3VtbWFyeUZ1bmN0aW9uPXR3b0NsYXNzU3VtbWFyeSkNCg0KYGBgDQoNCiMjIyMjIENWOiBgcnBhcnQoKWAsIENsYXNzaWZpY2F0aW9uIFRyZWUgDQpgYGB7cn0NCmN0cmwkcmVwZWF0cyA9IDINCnQwID0gU3lzLnRpbWUoKTsgc2V0LnNlZWQoMikNCmN2LnJwYXJ0ID0gdHJhaW4oDQogIGJ1eSB+IC4sIGRhdGE9VFIxLCBtZXRob2Q9InJwYXJ0IiwgDQogIHRyQ29udHJvbD1jdHJsLCBtZXRyaWM9IlJPQyIsDQogIHR1bmVHcmlkID0gZXhwYW5kLmdyaWQoLmNwID0gc2VxKDAuMDAwMiwwLjAwMSwwLjAwMDEpKSkNClN5cy50aW1lKCkgLSB0MA0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTd9DQpwbG90KGN2LnJwYXJ0KTtjdi5ycGFydA0KYGBgDQoNCg0KIyMjIyMgQ2xhc3NpZmljYXRpb24gVHJlZSwgRmluYWwgTW9kZWwNCmBgYHtyfQ0KI0NyZWF0ZSBhIENBUlQgbW9kZWwNCnJwYXJ0MSA9IHJwYXJ0KGJ1eSB+IC4sIFRSMSwgbWV0aG9kPSJjbGFzcyIsIGNwPTAuMDAwOCAsIG1pbmJ1Y2tldCkNCg0KI+eVq+WHuuaxuuetluaouQ0KbGlicmFyeShycGFydC5wbG90KQ0KI3JwYXJ0LnBsb3QocnBhcnQxLHR3ZWFrPTMpDQpwcnAocnBhcnQxLCAgICAgICAgICMg5qih5Z6LDQogICAgZmFjbGVuPTAsICAgICAgICAgICAjIOWRiOePvueahOiuiuaVuOS4jeimgee4ruWvqw0KICAgIGZhbGxlbi5sZWF2ZXM9VFJVRSwgIyDorpPmqLnmnp3ku6XlnoLnm7TmlrnlvI/lkYjnj74NCiAgICBzaGFkb3cuY29sPSJncmF5IiwgICMg5pyA5LiL6Z2i55qE56+A6bue5aGX5LiK6Zmw5b2xDQogICAgIyBudW1iZXIgb2YgY29ycmVjdCBjbGFzc2lmaWNhdGlvbnMgLyBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGluIHRoYXQgbm9kZQ0KICAgIGV4dHJhPTIsDQogICAgdHdlYWs9Mi41LHNwYWNlPTAuNSkNCj9wcnANCg0KUHJlZGljdENBUlQxID0gcHJlZGljdChycGFydDEsIFRTLCB0eXBlPSJwcm9iIilbLDJdIA0KYGBgDQrnrKzkuIDlsaTliIbmrafpu57mmK9mPDMgPGJyPg0K56ys5LqM5bGk5YmH5YiG5Yil5pivZjwyIOiIhyBmPDUgPGJyPg0K5Luj6KGoZihmcmVxdWVuY3nos7zosrfpoLvnjocp5bCNYnV555qE5b2x6Z+/5Yqb5b6I5aSnIDxicj4NCuacgOWPs+mCiueahHRlcm1pbmFsIG5vZGXmm7TmmK/lj6rntpPpgY7lhanlsaTliKTmlrc6IGY+PTMg4oaSIGY+PTUgPGJyPg0K5Lmf5bCx5pivZiA+PSA1IOWwseebtOaOpeWIpOaWt2J1eSA9IFRSVUU8YnI+PGJyPg0KDQoNCg0KDQojIyMjIyBjb21wdXRlIEFVQw0KYGBge3J9DQpjb2xBVUMoUHJlZGljdENBUlQxLFRTJGJ1eSkNCmBgYA0KDQoNCiMjIyBDQVJUIG1vZGVsIHdpdGhvdXQgY3AgQ2xhc3NpZmljYXRpb24gTW9kZWwgDQpgYGB7cn0NCiMgQ0FSVCBtb2RlbA0KcnBhcnQyID0gcnBhcnQoYnV5IH4gLiwgZGF0YSA9IFRSMSwgbWV0aG9kPSJjbGFzcyIpDQoNCiMgTWFrZSBwcmVkaWN0aW9ucw0KUHJlZGljdENBUlQyID0gcHJlZGljdChycGFydDIsIG5ld2RhdGEgPSBUUzEsIHR5cGUgPSAicHJvYiIpWywyXQ0KYGBgDQoNCiMjIyMjIGNvbXB1dGUgQVVDDQpgYGB7cn0NCmNvbEFVQyhQcmVkaWN0Q0FSVDIsIFRTJGJ1eSkNCmBgYA0KDQoNCg0KIyMjIEdMTSBDbGFzc2lmaWNhdGlvbiBNb2RlbCANCmBgYHtyfQ0KZ2xtMiA9IGdsbShidXkgfiAuIC1XNyAtVzEgLVcyIC1XMyAtVzQgLVc1IC1XNiAtYWdlIC1hcmVhRUZIIC1hcmVhQUNERUYgLXdlZWtkYXkgLXdlZWtlbmQgLWhvdDIwIC1ob3QxMCAtaG90NSAtYWdlR3JvdXAgLSBDSFIgLW1vbjEgLW1vbjIgLW1vbjMgLCBUUjFbLDE6MzBdLCBmYW1pbHk9Ymlub21pYWwoKSkNCg0Kc3VtbWFyeShnbG0yKQ0KYGBgDQoNCuaKimFnZeWIquaOiQ0K5aSaayxwcm9kUHJpY2UNCg0KIyMjIyMgY29tcHV0ZSBBVUMNCmBgYHtyfQ0KcHJlZEdMTSA9ICBwcmVkaWN0KGdsbTIsIFRTMSwgdHlwZT0icmVzcG9uc2UiKQ0KY29sQVVDKHByZWRHTE0sIFRTJGJ1eSkNClRTJGJ1eSAlPiUgdGFibGUNCmBgYA0KDQojIyMjIyBjb25mdXNlIG1hdHJpeA0KYGBge3J9DQpjbSA9IHRhYmxlKGFjdHVhbCA9IFRTMSRidXksIHByZWRpY3QgPSBwcmVkR0xNID4gMC41KTsgY20NCmBgYA0KDQojIyMjIyBjb21wdXRlIGFjY3VyYWN5DQpgYGB7cn0NCmFjYy50cyA9IGNtICU+JSB7c3VtKGRpYWcoLikpL3N1bSguKX07IGFjYy50cyANCmBgYA0KDQoNCg0KIyMjIENsYXNzaWZpY2F0aW9uIE1vZGVsRW5zZW1ibGluZw0KYGBge3J9DQojIEdMTSArIENBUlQxDQpyZXN1bHQgPSAocHJlZEdMTSArIFByZWRpY3RDQVJUMSkvMg0KY29sQVVDKHJlc3VsdCwgVFMkYnV5KQ0KDQojIEdMTSArIENBUlQyDQpyZXN1bHQgPSAocHJlZEdMTSArIFByZWRpY3RDQVJUMikvMg0KY29sQVVDKHJlc3VsdCwgVFMkYnV5KSAjIGhpZ2hlcg0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KPGJyPjxicj48YnI+PGhyPg0KDQojIyMgUmVncmVzc2lvbiBNb2RlbA0KIyMjIyMgUHJlcGFyaW5nIHRoZSBEYXRhDQpgYGB7cn0NCkEyID0gc3Vic2V0KEEsIEEkYnV5ID09ICJ5ZXMiKSAlPiUgbXV0YXRlX2F0KGMoIm0iLCJyZXYiLCJhbW91bnQiKSwgbG9nMTApDQpgYGANCg0KYGBge3J9DQpUUjIgPSBzdWJzZXQoQTIsIHNwbDIpICU+JSBzdWJzZXQoLiwgc2VsZWN0ID0gLWMoY3VzdCwgYnV5KSkNClRTMiA9IHN1YnNldChBMiwgIXNwbDIpICU+JSBzdWJzZXQoLiwgc2VsZWN0ID0gLWMoY3VzdCwgYnV5KSkNCmBgYA0KDQoNCiMjIyBsaW5lYXIgbW9kZWwNCmBgYHtyfQ0KDQpsbTEgPSBsbShhbW91bnQgfiAuIC1XNyAtVzEgLVcyIC1XMyAtVzQgLVc1IC1XNiAgLWFyZWFBQ0RFRi1hcmVhIC13ZWVrZGF5ICAtaG90NS1ob3QxMC1ob3QyMC1hZ2VHcm91cC1tb24xLW1vbjIgLFRSMikNCg0Kc3VtbWFyeShsbTEpDQpgYGANCg0KIyMjY29tcHV0ZSBSLXNxdWFyZWQNCmBgYHtyfQ0KcjIudHIgPSBzdW1tYXJ5KGxtMSkkci5zcQ0KU1NUID0gc3VtKChUUzIkYW1vdW50IC0gbWVhbihUUjIkYW1vdW50KSleIDIpDQpTU0UgPSBzdW0oKHByZWRpY3QobG0xLCBUUzIpIC0gIFRTMiRhbW91bnQpXjIpDQpyMi50cyA9IDEgLSAoU1NFL1NTVCkNCmMocjIudHIsIHIyLnRzKQ0KYGBgDQoNCg0KIyMjIENBUlQgUmVncmVzc2lvbiBNb2RlbA0KDQoNCiMjIyMjIENyb3NzLVZhbGlkYXRpb24NCmBgYHtyfQ0KbGlicmFyeShjYXJldCkNCmxpYnJhcnkoZTEwNzEpDQpsaWJyYXJ5KHJwYXJ0KQ0KDQojIERlZmluZSBjcm9zcy12YWxpZGF0aW9uIGV4cGVyaW1lbnQNCiMgaz0xMA0KbnVtRm9sZHMgPSB0cmFpbkNvbnRyb2woIG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDEwICkgDQojIHBpY2sgdGhlIHBvc2lpYmxlIHZhbHVlcyBmb3IgY3ANCmNwR3JpZCA9IGV4cGFuZC5ncmlkKCAuY3AgPSBzZXEoMC4wMDEsMC4xLDAuMDAxKSkgDQoNCg0KIyBQZXJmb3JtIHRoZSBjcm9zcyB2YWxpZGF0aW9uDQpjdiA9IHRyYWluKGFtb3VudCB+IC4sIGRhdGEgPSBUUjIsIG1ldGhvZCA9ICJycGFydCIsIHRyQ29udHJvbCA9IG51bUZvbGRzLCB0dW5lR3JpZCA9IGNwR3JpZCApDQojIG1ldGhvZD0icnBhcnQiIDogd2Ugd2FudG8gdG8gdmFsaWRhdGUgYSBDQVJUIG1vZGVsDQpwbG90KGN2KTtjdg0KYGBgDQojIyNDcmVhdGUgYSBDQVJUIG1vZGVsDQpgYGB7cn0NCg0KcnBhcnQyID0gcnBhcnQoYW1vdW50IH4gLiwgZGF0YSA9IFRSMiwgY3AgPSAwLjAwMikNClNTVCA9IHN1bSgoVFMyJGFtb3VudCAtIG1lYW4oVFIyJGFtb3VudCkpXiAyKQ0KU1NFID0gc3VtKChwcmVkaWN0KHJwYXJ0MiwgVFMyKSAtICBUUzIkYW1vdW50KV4yKQ0KMSAtIChTU0UvU1NUKQ0KYGBgDQoNCg0KIyMjIG1vZGVsIGVuc2VtYmxpbmcNCmBgYHtyfQ0KcHJlZExNID0gcHJlZGljdChsbTEsIG5ld2RhdGE9VFMyKQ0KcHJlZENBUlQgPSBwcmVkaWN0KHJwYXJ0MiwgbmV3ZGF0YT1UUzIpDQpyZXN1bHQgPSAocHJlZExNICsgcHJlZENBUlQpLzINCg0KU1NUID0gc3VtKChUUzIkYW1vdW50IC0gbWVhbihUUjIkYW1vdW50KSleIDIpDQpTU0UgPSBzdW0oKHJlc3VsdCAtICBUUzIkYW1vdW50KV4yKQ0KMSAtIChTU0UvU1NUKQ0KYGBgDQoNCg0KPGJyPjxicj48YnI+PGhyPg0KDQoNCiMjIyMjIFN0b3AgUGFyYWxsZWwgUHJvY2Vzc2luZw0KYGBge3J9DQpzdG9wQ2x1c3RlcihjbHVzdCkNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCjxicj48YnI+PGJyPjxicj48aHI+PGJyPjxicj48YnI+DQoNCjxzdHlsZT4NCi5jYXB0aW9uIHsNCiAgY29sb3I6ICM3Nzc7DQogIG1hcmdpbi10b3A6IDEwcHg7DQp9DQpwIGNvZGUgew0KICB3aGl0ZS1zcGFjZTogaW5oZXJpdDsNCn0NCnByZSB7DQogIHdvcmQtYnJlYWs6IG5vcm1hbDsNCiAgd29yZC13cmFwOiBub3JtYWw7DQogIGxpbmUtaGVpZ2h0OiAxOw0KfQ0KcHJlIGNvZGUgew0KICB3aGl0ZS1zcGFjZTogaW5oZXJpdDsNCn0NCnAsbGkgew0KICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsNCn0NCg0KLnJ7DQogIGxpbmUtaGVpZ2h0OiAxLjI7DQp9DQoNCnRpdGxlew0KICBjb2xvcjogI2NjMDAwMDsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmJvZHl7DQogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOw0KfQ0KDQpoMSxoMixoMyxoNCxoNXsNCiAgY29sb3I6ICMwMDg4MDA7DQogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOw0KfQ0KDQpoM3sNCiAgY29sb3I6ICNiMzZiMDA7DQogIGJhY2tncm91bmQ6ICNmZmUwYjM7DQogIGxpbmUtaGVpZ2h0OiAyOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCg0KaDV7DQogIGNvbG9yOiAjMDA2MDAwOw0KICBiYWNrZ3JvdW5kOiAjZmZmZmUwOw0KICBsaW5lLWhlaWdodDogMjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQoNCmVtew0KICBjb2xvcjogIzAwMDBjMDsNCiAgYmFja2dyb3VuZDogI2YwZjBmMDsNCiAgfQ0KPC9zdHlsZT4NCg0K