# Compute P(active|p1x,tx,T)rfm_data_array = rfm_data.select("P1X", "P2X", "t_x", "T").collect().to_numpy()p1x = rfm_data_array[:, 0].astype(np.int16)p2x = rfm_data_array[:, 1].astype(np.int16)t_x = rfm_data_array[:, 2]T = rfm_data_array[:, 3]maxab = np.max((alpha, beta))absab = np.abs(alpha - beta)param2 = s +1if alpha < beta: param2 = r + p1xF0 = (alpha + T) ** (r + p1x) * (beta + T) ** sif absab ==0: F1 =1/ ((maxab + t_x) ** (r + s + p1x)) F2 =1/ ((maxab + T) ** (r + s + p1x))else: F1 = hyp2f1(r + s + p1x, param2, r + s + p1x +1, absab / (maxab + t_x)) / ( (maxab + t_x) ** (r + s + p1x) ) F2 = hyp2f1(r + s + p1x, param2, r + s + p1x +1, absab / (maxab + T)) / ( (maxab + T) ** (r + s + p1x) )pactive =1/ (1+ (s / (r + s + p1x)) * F0 * (F1 - F2))# compute average P(active|p1x,tx,T) and determine the proportion of customers buying in the second 39 weeks for each level of p1x# Compute unique levels of p1xunique_p1x = np.arange(p1x.max() +1)# Compute counts per unique p1xnp1x = np.bincount(p1x)# Compute actual proportions of active customerspa_actual = np.divide( np.bincount(p1x, weights=(p2x >0).astype(float)), np1x, where=np1x !=0)# Compute estimated proportions of active customerspa_est = np.divide(np.bincount(p1x, weights=pactive), np1x, where=np1x !=0)
Code
# create right-censored version for plotcensor =7# Right-censor at 7+denom = np.sum(np1x[censor:]) # Compute denominator# Compute censored actual proportionspa_act_cen = np.zeros(censor +1)pa_act_cen[:censor] = pa_actual[:censor]pa_act_cen[censor] = np.dot(np1x[censor:], pa_actual[censor:]) / denom# Compute censored estimated proportionspa_est_cen = np.zeros(censor +1)pa_est_cen[:censor] = pa_est[:censor]pa_est_cen[censor] = np.dot(np1x[censor:], pa_est[censor:]) / denomprop_active_customers = pl.DataFrame( {"P1X": [str(i) if i <7else"7+"for i inrange(8)],"Empirical": pa_act_cen,"Pareto/NBD": pa_est_cen, })prop_active_customers = prop_active_customers.unpivot( on=["Empirical", "Pareto/NBD"], index="P1X", variable_name="Actual Vs Estimated", value_name="P(active)",)( alt.Chart(prop_active_customers) .mark_line() .encode( x=alt.X("P1X:O", title="# Transactions in Weeks 1−39", axis=alt.Axis(labelAngle=0) ), y=alt.Y("P(active):Q", title="P(Active)"), strokeDash="Actual Vs Estimated:N", ) .properties( width=550, height=400, title="Predicted vs. Actual Proportions of Active Customers", ) .configure_view(stroke=None) .configure_axisY(grid=False) .configure_axisX(grid=False))
3.4 Computing Conditional Expectations
Code
t_ce =39# period for which conditional expectations are to be computedtmp1 = (r + p1x) * (beta + T) / ((alpha + T) * (s -1))tmp2 = ((beta + T) / (beta + T + t_ce)) ** (s -1)ce = tmp1 * (1- tmp2) * pactiveindividual_trans = individual_trans.hstack([pl.Series("Pareto/NBD", ce)])# compute average E[Y(t)|p1x,tx,T] and average actual number of# transactions in the second 39 weeks for each level of p1x# Compute unique levels of p1xunique_p1x = np.arange(p1x.max() +1)# Compute counts per unique p1xnp1x = np.bincount(p1x)ce_est = np.divide(np.bincount(p1x, weights=ce), np1x, where=np1x !=0)