---
# System prepended metadata

title: DegustaBox
tags: [Consultoria]

---

---
title: DegustaBox
tags: Consultoria
slideOptions:
  theme: white
  transition: 'fade'
---

# DegustaBox - Customer Retention

Persona de contacte: Alejandro Aragones (AA) <alejandro@degustabox.com>



## Recompte d'hores

La bossa d'hores contractada inicialment és de 20 hores [[cf. Slack amb JV, 2021-12-17](https://dsresearchub.slack.com/archives/D01KE9W0R7S/p1639739520002800)]

| Dia        | Hora  | Duración | Participantes               | Horas totales | Comentario                                                   |
| ---------- | ----- | -------- | --------------------------- | ------------- | ------------------------------------------------------------ |
| 29-10-2021 | 10:00 | 1:00     | JMP, AA                     | 1.50          | 1 h meeting, 15 min note-taking, 15 min dedicated to my TODO (check-out tutorials). |
| 05-11-2021 | 10:00 | 1:00     | JMP, AA                     | 1.00          | 30 min meeting, 15 min note-taking, 15 min dedicated to my TODO |
| 12-11-2021 | 10:00 | 1:00     | JMP, AA                     | 1.00          | 1h discussion about prediction model                         |
| 12-11-2021 | 16:30 | 0:30     | JMP, AA                     | 0.50          | Discussion of early results shared by email by AA            |
| 19-11-2021 | 10:00 | 0:30     | JMP, AA, Jürgen             | 0.75          | 30 min meeting, 15 min note-taking and send email about reinstalling sklearn etc. |
| 23-11-2021 | 12:00 | 1:00     | JMP, JV, AA, Jürgen, Silvia | 2.50          | 1 h meeting, 15 min prepare and send email about Partial Dependence Plots |
| 26-11-2021 | 10:00 | 0:45     | JMP, AA                     | 1.50          | 45 min meeting, 45 min note-taking and preparing and sending notes on Survival Analysis |
| 17-12-2021 | 10:00 | 0:45     | JMP, AA                     | 2.25          | 45 min meeting, 30 min note-taking, 1h TODOs (15 min person-hour calculation, 30 min create pysurvival environment YML for Anaconda --  conclusion package has [issues with Windows](https://github.com/square/pysurvival/issues/8) and is not much responsive to [requests for support](https://github.com/square/pysurvival/issues/8)), 15 min send email with update on TODOs. |
| *SUBTOTAL* |       |          | *SUBTOTAL*                  | **11.00**     |                                                              |
| 12-01-2022 | 10:00 | 10:45    |                             | 2.25          |                                                              |
| 26-01-2022 | 11:00 | 12:00    | JMP, AA                     | 2.00          | 1h meet + 15 min notes + (2x)15 min amb JV. + 15 min email "vidas medias infinitas" (tarda) |
| *SUBTOTAL* |       |          | *SUBTOTAL*                  | **4.75**      |                                                              |
| *TOTAL*    |       |          | *TOTAL*                     | 15.75         |                                                              |



## Resum trobades:



## dl 2021-10-25 12:00 Trobada a Google Meet (JV, JMP, AA) i debat posterior JV-JMP

* Farem una col·laboració on el guiarem sobre com resoldre el problema, però és ell qui farà tot el codi i anàlisi.
* Quedem en pressupostar per una col·laboració de 20h amb trobades setmanals els dimarts (12-13h) i divendres (10-11:30).
* Exploració inicial de dades per AA suggereix que pot tenir sentit crear **diferents models per a diferents paísos** (e.g., ES i FR tenen molt major % de cancel·lacions al cap d'1-2 mesos mentre que a UK,DE,NL es mantenen més temps; no està clara la variabilitat home-dona).
* Tres fases:
  * Concepció
  * Models predictius
  * Model causal

### Concepció

* Quin és l'objectiu? 
  * Amb JV han parlat de desenvolupar un model de tipus **survival analysis** que tingui en compte el problema que les dades pateixen de *right censoring*: fins a una data, només estem segurs que són bones les etiquetes dels casos que han marxat; dels que en aquesta data són clients, no podem saber si marxaran el mes que ve o mai.
* Quines dades tenim? Quines variables tenim? Són contínues, ordinals o categòriques? Per a les ordinals i categòriques: quants valors possibles? (Es poden descartar categories amb poques dades?)
* Quina informació temporal tenim i quina podem obtenir?

### Models predictius

* El primer objectiu ha de ser definir un **model predictiu "bàsic"** (és a dir, no de survival analysis). Això servirà per a dues coses:
  * Determinar si les dades de què disposem són suficients per predir els clients que marxaran;
  * Suposant que la resposta és afirmativa (i.e., les dades tenen poder predictiu), aquest model servirà de benchmark per al model de survival analysis.
* Un cop tenim un model predictiu bàsic, el segon pas serà crear un **model de supervivència**: la pregunta que volem respondre pot ser:
  * **Quina és la probabilitat que un client deixi de ser-ho en un horitzó de M mesos? Caldrà determinar amb DegustaBox quin és l'horitzó útil per a ells, i si cal adaptar-lo a cada país (e.g., M=1 per a {ES,FR} i M=3 per a {UK, DE}).**
  * Per a respondre aquesta pregunta, tindrem en compte el right censoring de les dades. Llibreries útils a consultar:
    * [scikit-surival](https://scikit-survival.readthedocs.io/): an open-source Python package for time-to-event analysis fully compatible with scikit-learn. Paper: Sebatian Pölsterl, [JMLR **21**(212): 1-6 (2020)](https://www.jmlr.org/papers/v21/20-729.html).
    * lifelines ([docs](lifelines.readthedocs.org), [github](https://github.com/CamDavidsonPilon/lifelines/)): R-package with an (experimental) layer for compatibility with Python's scikit-learn.
    * PySurvival ([github](https://square.github.io/pysurvival/index.html), [churn prediction tutorial](https://square.github.io/pysurvival/tutorials/churn.html)): an open source python package for Survival Analysis modeling - *the modeling concept used to analyze or predict when an event is likely to happen*. It is built upon the most commonly used machine learning packages such [NumPy](http://www.numpy.org/), [SciPy](https://www.scipy.org/) and [PyTorch](https://pytorch.org/).
  * [Bones mètriques](https://scikit-survival.readthedocs.io/en/stable/user_guide/evaluating-survival-models.html)?
    * **Brier score ([wiki](https://en.wikipedia.org/wiki/Brier_score)):** measures the accuracy of probabilistic predictions. 
      * For unidimensional predictions, it is strictly equivalent to the mean squared error as applied to predicted probabilities. The Brier score is applicable to tasks in which predictions must assign probabilities to a set of mutually-exclusive discrete outcomes or classes. 
      * $BS = \frac{1}{N}\sum_{t=1}^N (f_t - o_t)^2$ , with $f_t$: forecast probability of the event happening at time $t$, $o_t$: actual outcome (={0,1}) at time $t$, $N$: number of forecasting instances; lower BS is better.
      * ==> It is **inadequate for very rare, or very frequent, events** (i.e., very imbalanced datasets): in our case, it may work well for shorter-term predictions than longer-term ones (or the other way around).
    * **Concordance index** or **C-index**: a generalization of the area under the ROC curve (AUC) that can take into account censored data. It represents the global assessment of the model discrimination power, i.e., the model’s ability to correctly provide **a reliable *ranking* of the survival times** based on the individual risk scores. It assesses whether the order in which events are predicted to occur agrees with the order in which they actually occur, independently of whether it gets the absolute timing of events.
      * $C-{\text{index}} = \frac{\sum_{i,j} 1_{T_j < T_i} \cdot 1_{\eta_j > \eta_i} \cdot \delta_j }{ \sum_{i,j} 1_{T_j < T_i} \cdot \cdot \delta_j } = \frac{\sum_{i,j} \Theta(T_i- T_j) \cdot \Theta(\eta_j - \eta_i) \cdot \delta_j }{ \sum_{i,j} \Theta(T_i - T_j) \cdot \cdot \delta_j }$
        with $\eta_j$ = risk score of unit $j$; $1_{T_j < T_i} = 1 \text{ if } T_j < T_i \text{ else } 0 = \Theta(T_i - T_j)$; $1_{\eta_j > \eta_i} = 1 \text{ if } \eta_j > \eta_i \text{ else } 0 = \Theta(\eta_j - \eta_i)$ 
        C-index = 1 optimal (all predictions correctly ordered); C-index = 0: no prediction in the right ordinal position.
    * Time-dependent ROC
* Explicabilitat de les prediccions de churn: SHAP values o similar.

### Model causal

A partir del que hem après en els punts anterior, podem definir un model causal? 

* Quines variables poden determinar que un client vulgui marxar? (Aspecte qualitatiu, diferent de l'explicatiu ofert per Shapley values.) --> Creació d'un DAG.
* Quines accions (promocions, cupons, canvis de tarifa, inclusió de 'regals' en el paquet que s'entrega...) per part de DegustaBox poden influir en la decisió del client de marxar o quedar-se?

Caldrà analitzar les dades que tenim sobre accions dutes a terme: promocions, canals de benviguda, serveis entregats amb retard o no entregats, etc.

## dv 2021-10-29 10:00-11:00 Trobada JMP-AA

* Si queremos hacer diferentes modelos para diferentes países:
  * Cuántos modelos? Uno por país? O uno para "fast churners" (ES, FR) y uno para slow churners (resto)? 
  * Qué países quiere priorizar DegustaBox en su análisis?
  * Cuál será la escala temporal de churn que les preocupa (M=1-2 meses o M~6 meses)?

### Variables disponibles

* Datos del "profiling survey"
* **Datos numéricos (float, int):**

  * Age
  * User interaction: number of surveys filled in by client?
  * User interaction with the web = # times the user logs in
  * User points = ??
* **Datos categóricos:**

  * MasterChannel > SubChannel: último canal de promoción antes de inscribirse; núm. valores? frecuencias (value_counts)? Se puede descartar alguno? Exploración de datos sugiere que algún canal tiene comportamiento distinto?
  * Lead Channel: primer canal de promoción por el que el clienteo conoció a DegustaBox. ¿Cómo tenemos acceso a esta información? Cómo de fiable es? Núm. de valores y frequencias?
  * Sex
  * Cancellation reason
  * Country - ¿cuántos hay? ¿Mejor agruparlos de alguna manera (e.g., fast-churning vs. slow-churning) para mitigar el curse of dimensionality?
  * Region within country (3 levels of aggregation) - puede llevar a curse of dimensionality también. Agrupar (e.g., East coast, West coast, Midwest)?
  * Stockout in 1st month? Did user not receive their petition in 1st month due to lack of supply from DB side?
  * Interaction with Welcome Email = ??
  * Payment type: value_counts?
  * Subscription type: value_counts? mensual, trimestral o semestral
  * Registered with coupon?
  * Delivery type: at_home vs. in_shop
* ¿De qué datos tenemos **información temporal** (i.e., cuándo ocurrió)?

  * [x] Birthday
  * [x] Signup date
  * [ ] Payment type change
  * [ ] Subscription type change
  * [ ] Delivery type change
  * [ ] Deliveries with delay? How many, with what delay?
  * [ ] Number and date of user complaints?
  * [ ] Coupons or other promotions: when received? how many received? how many used?
  * [ ] Other ?

## 2021-10-29 10:00 - 11:00

### Discussion

* Business goal of the project: determinar customer lifetime value en especial en relació a 

  * Canal d'entrada.
  * Tipus de subscripció: { 1 mes, 3 mesos, 6 mesos }. Hi ha 1 únic nivell de subscripció o preu mensual; l'únic que canvia és al durada (que comporta descompte; el que no hi ha és categoria o capsa "bàsica" vs. "premium").
  * Cost d'adquisició del client.

* Treballen amb Jira i fan sprints. Adjunta el **pla de tasques** que ha previst:

  ![image](/Users/jmur/FEINA/0-TecnioSpring/projectes/DegustaBox/imgs/20211029-AA-plan_tareas.png)

* Farà servir Python per a construir els models predictius. Pensa seguir aquest tutorials - li'n podem donar feedback:
  - https://randerson112358.medium.com/predict-customer-churn-using-python-machine-learning-b92f39685f4c
  - https://towardsdatascience.com/predict-customer-churn-in-python-e8cd6d3aaa7

* Està duent a terme l'anàlisi de les variables que li vam demanar (rang de cadascuna, freqüències de valors). Com a primera indicació del volum de dades que tenen i la seva  distribució geogràfica, tenen dades per a aquests números de clients:
  | País_id | País | Num_clientes | Num_clientes_activos |
  | ---: | :--- | ------: | ------: |
  | 1 | ES | 86,704 | 5000 |
  | 2 | UK | 77,868 | |
  | 3 | DE | 108,197 | |
  | 4 | FR | 84,956 | 15000 |
  | 5 | ITA | 66,107 | |

* Diu que hi ha un alt nivell de churn a tots els paísos (perden molts clients però també en fan de nous -- no sembla una bona estratègia per créixer!).
* El seu **model "heurístic"** (basat en experiència de la gent del departament de Customers) té una "precisió" aproximada del 85-90% (see <img src="/Users/jmur/FEINA/0-TecnioSpring/projectes/DegustaBox/imgs/20211029-AA-current_accuracy.png" alt="image_accuracy" style="zoom:50%;" />
  * El que fan es predir el número de gent que marxarà; tenen 3 models (optimistic, realista, pessimista), e.g., { 90, 100, 130} .
  * Després observen quants han marxat realment, e.g., 103.
  * Fent la ràtio d'aquests números ells obtenen la seva "accuracy" per a cada model.
  * Les xifres que em mostra són d'un accuracy = { 15.37%, 11,29% } per a { realistic, optimistic }. Comenta que ho ha fet al revés, i de fet aquests números són l'error; la **ratio d'encert diu que és d'un 85% &ndash; 89%**. Això sembla incorrecte, com és que la previsió "optimista" és millor que la "realista"? (Potser ha estat "un bon mes" i la predicció optimista ha funcionat millor.) D'altra banda, si el model heurístic actual només encertés un 10-15% seria un baseline molt fàcil de superar :-).
  * En tot cas, el que presenta és només una mesura d'accuracy global, i en cap cas tenim idea de quantes prediccions individuals han encertat realment (*precisió* i *recall* serien mesures molt més adequades!).
* Degut al comportament diferenciat per paísos, el més adequat sembla ser fer **un model per país**.
  * Pregunto si sap **per quin país voldrien començar**. Es tracta que el primer sempre porta més feina fins que resols tots els problemes de data cleaning i feature engineering. 
  * El país amb més clients (actius) diu que és FR --> consultarà si comencem per aquí. **TODO [AA]: Ho consultarà.**
* Comenta el diferent tipus d'_estats_ que poden tenir els usuaris en el sistema:
  * `Active`
  * `Inactive`: ha fallat el pagament per alguna raó; es reintenta automàticament; si no hi ha èxit en **2 mesos**, el client passa a estar `Cancelled`.
  * `Ready  to cancel`: està al corrent de pagament però ha indicat que vol cancel·lar; és a dir, tan bon punt rebi la capsa del mes en curs passarà a ser `Cancelled`: horitzó temporal immediat (**1-2 setmanes**).
  * `Paused`: el client no ha cancel·lat el fet de ser membre, però no està pagant ni rebent capses.
  * `Cancelled`
  * `Eliminated`: `Cancelled` i a més l'usuari ha demanat que s'eliminin les seves dades (GDPR).
* A més, des de màrketing treballen amb 2 conceptes adicionals:
  * `Recoveries`: clients en estat `Cancelled`però amb un historial de >=5 capses/mensualitats (per tant, tenien un interès demostrat): se'ls ha intentat recuperar oferint-los ofertes (e.g., 20% descompte...). Tenen dades del tipus d'oferta que se'ls ha fet.
  * `Reactivations`: usuaris que estan inactius; tenen dades dels passos que estan fent per mirar de recuperar-los (e.g., confirmar que la targeta no està caducada)
* Data quality:
  * **Estats & temporalitat:** diu que tenen informació temporal de tots els canvis d'estat. Això haurà de ser molt útil per a l'entrenament del model de **survival analysis**. 
  * **Campanyes de recuperació:** diu que també tenen informació temporal i del tipus d'ofertes o contactes que han fet amb `recoveries`i `reactivations`. Això hauria de ser molt útil per a construir el **model causal**.
  * **Geografia:** parlem de la qualitat i fine-graining de les dades geogràfiques:
    * Voldran un model diferent per a cada país.
    * Dins de cada país, quin nivell de desagregació? És probable que no sigui útil fer un fitting a nivell de ciutat/poble. Ens quedem a nivell de regió? O podria ser més útil fer una classificació de les ciutats en tamany gran/mitjà/petit? Això semblaria una bona idea, però caldria fer una feina de **feature engineering** i buscar dades externes sobre tamanys de nuclis poblacionals. 
      * Possibles fonts de dades via UE: veure https://ec.europa.eu/eurostat/web/cities/data/database o https://appsso.eurostat.ec.europa.eu/nui/show.do?dataset=urb_cpop1&lang=en (són el mateix)
      * Per a UK -> ONS: https://www.ons.gov.uk/peoplepopulationandcommunity/populationandmigration/populationestimates/datalist?filter=datasets
      * Comenta que les dades poden ser força brutes (la gent escrivia un camp lliure); fa poc han començat a fer-ho via codi postal i desplegable, que hauria d'oferir dades més netes. Per tant, una utilització d'aquests camps probablement requerirà una inversió en **data cleaning**.
    * Ell comenta que potser no volen desagregar per regió o tamany de ciutat perquè no seria una variable accionable.
      * Dic que sí que pot ser-ho en el sentit que els pot alertar e.g. que el servei de distribució a ciutats mitjanes (Tarragona, Girona) no és bo --> Això sí és informació accionable: l'empresa pot decidir canviar d'empresa de distribució a tal regió, o deixar de servir certes ciutats/regions. En pren nota.
      * **TODO [AA]:** Queda pendent que consulti si volen fer desagregació, a quin nivell, i/o fer-ho per ciutats grans/mitjanes/petits.
  * Parlem d'altres variables que tenen per a tots els usuaris, així com del que poden obtenir via els **surveys**:
    * Del survey inicial tenen un 78% de respostes que sembla força bo.
    * Hi ha dades que potser no siguin molt informatives. Amb el CEO han pensat que les més rellevants podrien ser:
      1. What was the main reason you subscribed to Degusta Box?
      2. Where did you hear about/see Degusta Box for the first time?
      3. What is your current employment situation? { Full-time employed, Part-time, At-home, Student }
      4. What is your average monthly net household income? (Tenim dubtes de la fiabilitat d'aquesta resposta; caldria veure si han donat números o havien de triar dins d'un bracket.)
      5. Think about how you and/or your household members were shopping during the last 6 months. Which statement describes best your situation? (No sabem les possibles respostes.)

### **TODOs** - Next meeting: Friday 05/11/2021 10:00 AM

* AA: Check with stakeholders prioritization of a country: FR?
* AA: Check with stakeholders desired level of geographical disaggregation.
* [x] JMP: Check-out the tutorials AA has found as guides to follow to set-up the first churn prediction model.
  * **Done** - discarded randerson112358 tutorial (wrong LabelEncoder, wrong StandardScaler); other tutorial ok. Also suggested https://learnpython.com/blog/python-customer-churn-prediction/ - Emailed these comments to AA on Tue 02.11.2021.
  * Checked and run on Colab the **Survival Analysis tutorial** suggested by JV (email 31.10.2021), see https://allendowney.github.io/SurvivalAnalysisPython/index.html

### Duration

* Meeting lasted 1h (10:00-11:00) + 15 min note taking.
* 30 min dedicated to my TODO (check-out tutorials). 

## dv 2021-11-05 10:00-10:30 Trobada JMP-AA

### Pre-meeting - thoughts on tutorials

* Uses `https://randerson112358.medium.com/predict-customer-churn-using-python-machine-learning-b92f39685f4c
  * Uses `scikitlearn.LabelEncoder().fit_transform(df[column])` on non-numerical columns to make them numerical (e.g., PhoneService, MultipleLines, OnlineBackup, StreamingTV...). 
    * According to sklearn documentation, this method "Encoded target labels with value between 0 and n_classes-1... **should be used to encode target values, *i.e.* `y`, and not the input `X`.**" It follows that its usage in the tutorial is not as intended.
  * Then, it uses `X = StandardScaler().fit_transform(X)`allegedly to "scale the data to be values between 0 and 1 inclusively".
    * However, sklearn tells us that StandardScaler "standardizes features by removing the mean and scaling to unit variance.", i.e., new data will be in range (-inf, inf) but with values typically in (-1, 1). Most important: no bloody need to do anything for binary data { 0, 1 } !!

### Meeting discussion

* Diu que han parlat de començar per ES o FR, ell està **començant amb ES**, que sembla el més sensat (és on podem tenir més intuició per entendre resultats).
* Respecte el punt de desagregació geogràfica, diu que managment no té una idea clara i ha decidit ignorar aquests camps de moment.
* Parlem de com tractar variables categòriques --> li dic que per a MasterChannel i similars (amb ~10 categories) faci servir get_dummies. Millor ignorar de moment les columnes amb més valors diferents (e.g. Subchannel).
* Pregunto per l'equilibri entre els diferents tipus de clients (actius, inactius...). Les estadístiques globals, amb dades començant el 2015, són:
| User | Number | % |
| :--- | ---: | ---: |
| Active | 57,658 | 13.6 |
| Inactive | 4,247 | 1.0 |
| Ready to cancel | 770 | 0.2|
| Cancelled | 356,331 | 84.3 |
| Deleted | 3,444 | 0.8 |
| TOTAL |  422,450 | 100.0 |
  * Dic que això vol dir que un model que predís que tots els clients marxen l'encertaria un >85% de vegades (Cancelled + Ready to cancel + Deleted): aquest ha de ser el benchmark que volem superar.
  * Val la pena observar que l'encert "global" que va dir que té el personal que ho porta ara és del 85%, per tant ho estan fent realment aleatòriament!

### TODOs

* AA completará la limpieza de datos y preprocesado (e.g., one-hot-encoding con pandas.get_dummies).
* AA fiteará un primer modelo para hablar de resultados el viernes próximo.
* Quedamos de hablar el próximo viernes, con disponibilidad para intercambiar emails hasta entonces.

### Duration

* Meeting lasted 20 min (10:10-10:30) + 15 min note taking.
* 10 min dedicated to my TODO (check-out precision-recall ahead of next meeting). 

## dv 2021-11-12 16:30-16:50 Trobada JMP-AA

### Demana consulta curta després de primers resultats (email de les 13:02)

| Class         | Precision | Recall | F1-score | support |
| ------------- | --------- | ------ | -------- | ------: |
| 0 (cancelled) | 0.99      | 1.00   | 0.99     |   16254 |
| 1 (active)    | 0.97      | 0.83   | 0.90     |    1006 |

* Ha fet servir train_test_split=0.2
* Pensa que els resultats són molts bons.
  * Li dic que són bons, però que es fixi que les 2 classes estan molt descompensades, els casos "1" només representen un 6% del total -- per tant, un recall=0.83 en aquesta classe vol dir que prediu **més actius dels que hi ha"**.
  * Li dic que es miri els parametres del RandomForestClassifier per mirar de pujar aquest recall=0.83 i F1=0.90 per a la classe "1":
    * RandomForestClassifier: https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html
      * `max_depth`
      * `min_samples_split`
      * `min_samples_leaf`
      * potser també considerar `class_weight="balanced_sample"`
    * Mini-tutorial: https://machinelearningmastery.com/bagging-and-random-forest-for-imbalanced-classification/

* **TODO - Començar a revisar el tema SURVIVAL ANALYSIS per poder anar-lo guiant des de divendres vinent.**

## dv 2021-11-12 10:00 Trobada JMP-AA

### Pre-meeting

* **TODO - Començar a revisar el tema SURVIVAL ANALYSIS per poder anar-lo guiant des de divendres vinent.**
* **Qué tal ha progresado el modelo con 'balancing' de las clases (v. "mini-tutorial" link)**
* Thoughts on results sent over the week? What would be a nice result to have?
* Be prepared to discuss about metrics of success in classification problems:
  * **Precision = PPV := TP / (TP + FP)**: "How many of the items labelled by the model are truly relevant?"
  * **Sensitivity = Recall := TP / (TP + FN)** = TP / (P): "How many of the relevant items are selected by the model?"
  * Accuracy := (TP + TN) / (total pop)
  * F1 score = harmonic mean of Precision and Recall = 2 TP / (2 TP + FN + FP)
  * Miss rate = FN rate := FN / P = FN / (FN + TP) 
  * FP = "type I error"
  * FN = "type II error"
* Suggestions for next week: get deeper into understanding the data and the performance of our trained model:
  * Build a **dummy regressor** (one that always predicts the average over all the dataset). This is a pretty basic baseline, but we should definitely be beating it to claim any improvement. For guidance, see https://inria.github.io/scikit-learn-mooc/python_scripts/cross_validation_baseline.html
  * Learn about
    * imbalanced datasets, the confusion matrix, and changing the decision threshold in a classifier -> see https://inria.github.io/scikit-learn-mooc/python_scripts/metrics_classification.html

  * Perform some **balanced--cross-validation performance assessment**:
    * The goal is to have a better estimate of the "generalisation error" of the *trained* model to the problem it will encounter in the wild, where future-ACTIVE and future-INACTIVE are more closely balanced that in our historical dataset (where too many INACTIVE may be biasing the model).

    * As we have 16000 INACTIVE and 1000 ACTIVE in the remaining TEST dataset, do 100 times the following:
      * take at random 1000 rows from INACTIVE group, and join them to the 1000 ACTIVE rows; use `KFold(n_splits=10,shuffle=True)`from `scikit-learn` to do it, or better `sample=data[data['status']=='inactive'].sample(n=n_active, replace=False)` from pandas.
      * apply our fitted/trained classifier to this balanced dataset (1000:1000), and check out its performance metrics (precision, recall);
      * analyse statistics of metrics over the 100 realizations of the experiment (similar to the distribution of test scores in https://inria.github.io/scikit-learn-mooc/python_scripts/cross_validation_grouping.html)
      * The key idea is that we've trained our model with a fairly imbalanced dataset (16:1) while now we're testing it on 1:1 balanced datasets: does it work well? 
        * If it just learned to say mostly "INACTIVE", it will work very poorly.
        * If it didn't really capture the features that distinguish the 1000 ACTIVE users from the mass of INACTIVE ones, again it's performance won't be much better than change (~50%) in each experiment.

## dv 2021-11-19 10:00-10:45 Trobada JMP-AA, Jürgen

* 30 min trobada, 15 min prendre notes i enviar emails amb info sobre reinstal·lació sklearn etc.
* Assisteix el **CEO, Jürgen Schnatterer.**
  * Ens presentem, li comento causalitat i com les eines de causal data science permeten extraure informació causal no només de randomized control trials sinó també de dades amb biaix en l'assignació de tractament. Comparteixo el [video causal](https://datascience.barcelona/service/ciencia-de-dades-causal-video/) que hem fet amb Giny.
  * Comenta que just acaben d'acabar un "experiment", han ofert que la 6a capsa fos al 50% si el client es mantenia fins aquell moment. Diu que no ha anat del tot bé; dic que tanmateix l'anàlisi de les dades pot ajudar a identificar un subgrup de client per als quals sí que funcionés. Ell menciona especialment la disparitat de resultats per països.
* Amb el CEO i Alejandro parlem de les prediccions que fan actualment, el seu objectiu principal és predir les comandes que ells mateixos han de fer, és a dir, **volen saber el volum de clients** que tindran (estimar el % que marxen i quants de nous poden entrar); això ho fan de manera recurrent **cada mes**. Actualment no fan res de predicció individualitzada. El seu principal _concern_ és si el **canal d'entrada (amb costos associats)** té un paper important en l'attrition rate, per re-focalitzar esforços en la captura de clients.
* Alejandro diu que no ha pogut avançar en resultats durant la setmana perquè van tenir un problema amb un update de la base de dades, i a més "sklearn li ha desaparegut de la instal·lació de Spyder" -- això és un petit problema intern seu, però li enviaré alguna ajuda de com intentar resoldre-ho.
* Parlem força de la problemàtica d'entrenar l'algoritme amb unes dades tan desequilibrades com les seves (per a Espanya, un històric de 60k client però només 5k actius).
* Quedem que m'enviarà al llarg del dia o dilluns, on cop ho tingui tot de nou en marxa, els resultats actuals, i ens veiem de nou DIMARTS vinent.
  * AA diu que convidarà **Sílvia**, que és la persona que ha portat l'experiment de la 6a capsa al 50%: a quins països ho han ofert? Quants clients? Quina distribució per canals d'entrada? Quins efectes en retenció han observat (i com es compara amb els costos)?

## dm 2021-11-23 12:00-13:00 Trobada JMP, JV-AA, Silvia, Jürgen

* Assisteix Silvia que és la que ha portat un "experiment" de retenció de clients: 

  * Van segmentar clients per països i per temps que feia que eren clients (1-5 mesos);
  * Llavors, a la meitat els van oferir que la 6a capsa/mensualitat seria al 50% si continuaven de clients llavors; a l'altre meitat no li van oferir.
  * Han fet seguiment per veure impacte sobre permanència en els diferents països, han conclòs que només ha generat algun benefici a ESP, mentre que als altres països hi han perdut.
  * Tenint en compte que a ESP és on més turnover hi ha, ja té sentit: no és del tot sorprenent que els alemanys que ja es pensaven quedar 6 mesos (o més) hagin seguit fent-ho... i potser s'han beneficiat d'una promo, així que l'empresa hi ha perdut.
  * Tampoc sembla molt brillant haver fet l'oferta a gent que duia 5 mesos - aquests ja tenien força números de quedar-se fins al 6è mes...
  * En tot cas, han de ser dades útils per identificar les característiques dels clients més susceptibles de respondre a ofertes per a continuar. Potser en el futur és pot millor la part financera si enlloc del 50% es fa només un 25%.
  * NB: El randomization era sobre oferir l'oferta -- llavors els clients podien acceptar-la o no (havien de fer click en un email o similar).
  * Quedem que ens mirarem les dades per veure què se'n pot extreure, en particular per a nosaltres (pel tema de "respondre a estímuls") sembla important veure si hi ha una caiguda important de clients al 7è mes entre els que van acceptar l'oferta per la 6a capsa.

* 1h trobada, 15 min prendre notes i enviar email sobre **Partial Dependence Plots**:

* > El tipo de figura que comentaba Jordi para visualizar el impacto de cada  variable sobre las predicciones se llama Partial Dependence Plot (PDP) o Individual Conditional Expectation (ICE) plot. Puedes crearlos desde  sklearn haciendo:
  >
  > > from sklearn.inspection import PartialDependenceDisplay
  > >
  > > features = [0, 1, (0, 1)]
  > >
  > > PartialDependenceDisplay.from_estimator(clf, X, features)
  >
  > Aquí:
  >
  > - clf es tu clasificador entrenado;
  >
  > - X_train los datos usados para entrenar el clasificador;
  >
  > - features es una lista con enteros o pares de enteros;
  >
  > - - si features[i] es un entero, ese número se corresponde con la variable cuyo efecto quieres visualizar (en el ejemplo de arriba, eso se hace con las variables núm. 0 y 1)
  >   - si features[i] es un tuple de enteros, entonces la figura representará la dependencia sobre las dos variables correspondientes.
  >
  > Más información, incluyendo las limitaciones de esta cuantificación del  impacto de una variable así como algunas figuras, para que veas mejor lo que puedes esperar, en el manual de sklearn [aquí](https://scikit-learn.org/stable/modules/partial_dependence.html) y en [esta página](https://christophm.github.io/interpretable-ml-book/pdp.html) sobre interpretable machine learning.

## dv 2021-11-26 10:00-10:45 Trobada JMP-AA

* 40 min trobada, 50 min prendre notes, consultar tutorials de Survival Analysis i enviar-li email.

* Comencem molt a poc a poc: AA ha copiat les 3 línies de codi que li havia passat però no ha sabut substituir "clf" pel nom del seu classificador ("classifier"). Ho fem, i l'ajudo online sobre el seu codi a arreglar uns errors que tenia que feien que els covariates X tinguessin diverses columnes amb el mateix nom (tot i significar coses diferents). Fet això, la comanda per generar el partial dependence plot sembla que funciona, però triga força estona en generar cap output; potser emprar 60k files ja ho té.

* Quedem que ell hi seguirà treballant, i li dic que comenci a pensar en explorar les dades de cara al survival analysis. Algunes idees que li dono:

  * Fer un histograma amb el número de client que marxen al cap de {1-3 mesos, 4-6, 7-12, 13+} separats per alguna variable que, segons el seu coneixement de negoci, pugui ser important, com ara el canal d'entrada/reclutament, país, etc.

  * Li comento que en part, l'exercici que volem fer és predir quant de temps un client es quedarà a l'empresa. Per tant, anant un pas més enllà del model classificador que ha estat treballant fins ara, el que pot explorar és construir un predictor del temps de permanència. Per a això, pot limitar-se a utilitzar per al training dades dels clients que ja sabem que han marxat; això no ha de ser problema, perquè tenen moltes dades històriques.

  * Ell em demana algun tutorial que pugui recomanar-li de survival analysis. Li passo els següents:

    **Tutorials Survival Analysis**:

    * Sklearn: https://scikit-survival.readthedocs.io/en/stable/user_guide/00-introduction.html
    * **PySurvival - churn prediction:** https://square.github.io/pysurvival/tutorials/churn.html

    El PySurvival sembla particularment llegible i fàcil d'implementar, però cal posar esment en les columnes:

    * 'T' (*time*): target values describing the time when the event of interest or censoring    occurred.
    * 'E' (*event*): values that indicate if the event of interest occurred, i.e.: E[i]=1 corresponds to an event [=cancellation/death/device-broken/etc.], and E[i] = 0 means censoring, for all i.

  * Per entendre-ho millor, pot ser útil mirar l'[altre tutorial](https://square.github.io/pysurvival/tutorials/maintenance.html#4-exploratory-data-analysis) sobre "**predictive maintenance**".

## dm 2021-12-17 10:00-10:45 Trobada JMP-AA

* 45 min trobada, 30 min prenent notes, 1 fent TODOs (recompte d'hores, instal·lació de pysurvival amb Anaconda, enviar emails) = **total: 2:00** 
* Pre-meeting:
  * Ha aconseguit completar l'anàlisi de partial dependence plots? Alguna lliçó interessant?
  * Ha provat de construir un model predictiu del temps de permanència a partir dels casos coneguts de cancel·lacions històriques?
  * He tingut temps de mirar-se i/o provar d'implementar els models de survival analysis que li vaig passar divendres (PySurvival, scikit-survival)?
* Com anem amb el recompte d'hores:
  * **To-Do - recompte d'hores fins ara**
* Pysurvival:
  * Le requiere paquetes de Microsoft C++ ??
  * **To-Do: mirar com instal·lar pysurvival amb Anaconda: algun repositori especial?**
* Discussió entre client retention i customer life-time value (LTV):
  * A Espanya tenen una fracció important de clients que re-activen de tant en tant, potser per 1 caixa o per 2-4. Això pot ser en resposta a promocions específiques (e.g., setembre 2021). A Espanya, de 4000 caixes enviades al setembre 2021:
    * Unes 290 van ser caixes de clients que estaven actius a l'agost (van rebre caixa), però aquesta va ser la seva última caixa (no van rebre a l'octubre);
    * Unes 310 caixes eren de client "cancel·lats" a l'agost (no havien rebut caixa); van rebre la de setembre. A l'octubre, hi havia una fracció important que tornava a estar cancel·lat (i.e., només havien activat per rebre la caixa de la promo).
  * En comparació, l'efecte de fluctuació temporal és molt menor a Alemanya: van enviar unes 15.000 caixes, de les quals només unes 600 corresponien a "reactivacions".
  * Aquesta naturalesa "fluctuant" dels clients i el seu caràcter actiu/cancel·lat potser no s'adequa molt bé a un survival anàlisis, on típicament considerem una cancel·lació/mort com a definitiva. 
    * Si fem l'analogia amb els casos de càncer, el que és definitiu és la mort (per càncer o per altra causa) del pacient. Mentre això no ocorre, es considera el pacient viu o "actiu". El que pot ser és que no se'n tingui nova informació des de fa temps. També es pot considerar el pacient com a plenament recuperat passats 5 anys. En el nostre cas, podríem considerar tots els clients actius i definir la "mort" de manera efectiva si porten X mesos sense reactiva (posem, 12 mesos).
  * Cal distingir per tant 2 problemes que corresponen a 2 KPIs del negoci, i que requeririen anàlisis diferents:
    * **Retenció de client** "nou"/"actiu"/"en la seva primera activació". 
      * KPIs: Aquesta anàlisi permetria:
        * Fer estimacions més fiables sobre el **volum de comandes** de capses que DegustaBox necessita fer de cara al mes que ve.
        * Identificar quins **canals de captura de clients** funcionen millor en aquest sentit (clients que, sense oferir-los cap promoció addicional, es mantenen fidels). 
      * Dades: Podem analitzar les dades de clients fins a la primera cancel·lació.
      * Metodologia: Per a aquest problema seria adequat un model de **survival analysis** en primer lloc. També seria susceptible de fer una **anàlisi causal**: quines ofertes o promocions podem fer per evitar que un client cancel·li en primer lloc? 
    * **Lifetime value** d'un client. 
      * KPIs: Caldria especificar quina mètrica és més adequada pel negoci: **número de capses (totals o per 12 mesos) o ingressos generats**, si tenim en compte que es pot estar beneficiant de promocions esporàdiques?
      * Dades: Aquí pemetríem que un client estés actiu o inactiu/cancel·lat, el que volem és predir el valor generat pel client. 
      * Metodologia: Per a aquest problema un model de survival analysis pot no ser el més adequat. Aquí es podria fer un **model de predicció** (en funció de les coses que sabem d'un client, quins ingressos genera en 12 mesos, o 24, etc.?), i també seria susceptible de fer una **anàlisi causal**: quines promocions són més eficients per a reactivar clients cancel·lats? Fem promocions d'un 50% o d'un 25%? Per a tots els clients de DegustaBox o només per als d'Espanya?
    * **La pregunta clau**, que han de respondre els decision-makers, és: **És més efectiu retenir un client permanentment, o és preferible deixar-los inactius durant uns mesos si al cap d'1 o 3 anys han acabat comprant més?** Donats els recursos finits disponibles per a tirar endavant aquest projecte, cal prioritzar una anàlisi sobre l'altra.

## dm 2021-12-21 12:00-xx Trobada JMP-AA

* No futher meetings happened in Dec 2021



## dc 2022-01-12 10:00-10:45 Trobada JMP-AA

* 45 min trobada, 30 min prenent notes, 1h (llegint resultats enviats dilluns, consultant documentació lifelines, escrivint notes prèvies) = **total: 02:15** 

* El dilluns m'ha enviat resultats de dues famílies de models:

  * **Predicció (classificació) de churn d'un mes al següent.** Els scores són de 0.89-0.90 per SVM, DecisionTree, LogisticReg, k-NN, i de 0.92 per RandomForest.

  * **Predicció del temps fins a cancel·lació.** Per a això, ha fet un survival analysis amb el paquet [lifelines](https://lifelines.readthedocs.io/en/latest/Survival%20Regression.html). 

    * Com a mesures de fiabilitat dels resultats tenim:

      * comparació: 'baseline estimation': breslow -- **Què vol dir això?**
      * partial log-likelihood: -33207 -- és molt o poc això?
      * **concordance: 0.68 -- és molt o poc això? Sembla correcte (entre 0.55 i 0.75).**
      * partial AIC [Akaike Info Criterion]: 66478 -- és molt o poc això?
      * log-likelihood ratio test: 433.28 on 31 df
      * [Guidelines](https://lifelines.readthedocs.io/en/latest/Survival%20Regression.html):
        * In this author’s opinion, the best way to measure predictive performance is evaluating the **log-likelihood on out-of-sample data**.
        * AIC: For **within-sample validation, the AIC** is a great metric for comparing models as it relies on the log-likelihood.
        * Concordance-index, also known as the c-index: evaluates the accuracy of the *ranking* of predicted time. It is in fact a generalization of AUC.
          * [Here](https://stats.stackexchange.com/a/478305/11867) is an excellent introduction & description of the c-index for new users.
          * Fitted survival models typically have a concordance index **between  0.55 and 0.75** (this may seem bad, but even a perfect model has a lot of  noise than can make a high score impossible).

    * Els resultats suggereixen: 'Flyer' i 'Co-marketing' tenen un efecte notable en augmentar el log(HR): el risc de cancel·lació augmenta en:

      | variable          | coef=log(HR) | exp(coef)  | s.e.(coef) |
      | ----------------- | ------------ | ---------- | ---------- |
      | flyer             | 1.29*        | 3.63       | 0.51       |
      | co-marketing      | 0.76*        | 2.14       | 0.34       |
      | AWIN, email in db | 0.51, 0.50   | 1.67, 1.64 | .09, 0.08  |
      | gift              | -0.60        | 0.55       | 0.31       |
      | persurv (??)      | -0.66*       | 0.52       | 0.05       |

    * Els més **significatius** són `persurv` (significat??) i unes quantes variables amb coeff~0.5 (AWIN, email in db, direct deals, social media...). `gift` té una variació molt gran, com també força `flyer` i `co-marketing`.

      * Convindria veure si hi ha duplicitat en les variables, que pugui millorar el fit i reduir la incertesa en coeficients. Per exemple, és possible que flyer i co-marketing vinguin a dir el mateix. Corresponen realment a pràctiques diferents i *excloents* implementades per la gent de CRM? Potser convindria re-unir-les en una única variable "marketing".
      * És curiós / sorprenent que hi hagi mitja dotzena de variables que semblen tenir un efecte tan gran com $0.50 \Rightarrow exp(coef) \approx 1.64$ (AWIN, email, deals, social media...). De nou, caldria entendre com és que, aparentment, tantes variables influeixin tant. Potser cal mirar si hi ha subpoblacions que responen a una variable o altre? Però llavors l'efecte s'hauria reduit, o la variabilitat (s.e.) augmentat. Sembla sorprenent. En tot cas, si tot això són variables corresponents a accions que l'empresa pot fer, això apunta a diferents opcions de cara endavant. També ens pot estar suggerint la presència de *confounders*: per exemple, algú que et dóna l'email pot estar més implicat amb el negoci, i té més números de seguir. Això es veuria més clar amb un **DAG** --> causal analysis.

* Suggeriments:

  * Per al survival analysis amb lifelines:
    * Fer **cross-validation** per veure com d'estables són els scores que dóna. En cross-validations, es fa servir les dades 'test' que no s'han fet servir per training per calcular el score -- per tant aquí convindria utilitzar scoring_method="log-likelihood" (que sembla que és el default scoring_method, així que no cal indicar-ho).
    * Plotejar **survival_probability_calibration(model, data, t0)** per alguns valors respresentatius de t0, e.g., t0=1 (probab. de cancel·lació a 1 mes), t0=3, 6, 12. **Té sentit el que doni la figura?**
  * Tant per a survival-analysis com per al problema de classificació a 1-mes, explorar si hi ha redundància entre variables (`direct`, `direct deals`, `gift`, `coupon`?). Per a classificació no és tan important, però per a survival analysis, i per a planejar intervencions per a retenir clients sí -- sobretot cal pensar un DAG que distingueixi les variables que podem canviar de les que no (sex, age).

* RESUM REUNIÓ:

  * La prioritat dels stakeholders és estimar la probabilitat que un client cancel·li a 1 o 3 mesos vista, i com a segona prioritat establir la importància relativa de cada canal d'entrada.

  * El model de de classificació RandomForest per a la **predicció a 1 mes** sembla que ho va prou bé:

    * Va entrenar amb dades històriques per al mes d'octubre, per predir cancel·lacions a novembre. Va predir un 18% de cancel·lacions (Espanya). Van comparar amb el que va passar, i van cancel·lar un 15%, per tant la predicció és força bona. En magnitud, la predicció és comparable (i lleugerament millor) que la que feien fins ara -- però amb la diferència que ara la predicció és personalitzada per a cada client, mentre que abans era una predicció bulk sobre número de cancel.lacions.
    * Li dic que tot això sembla molt bo, però que li convé generar un model per a cada mes, ja que les prediccions d'octubre no seran bones per a gener. No ha de ser gaire esforç generar aquests 12 models i els ha de ser útil. Insisteixo que generi prediccions per a febrer que puguin comprovar amb el que passi a fi de mes.

  * Pel que fa al survival analysis amb lifelines:

    * Em comenta el significat de *persurv = (núm. de surveys contestats)/(núm. de capses rebudes)*. En principi és indicatiu de l'engagement de l'usuari -- però en realitat té un biaix perquè molts usuaris que només es queden un mes responen a 1 qüestionari: les dades mostren un pic gran a persurv=1, i després una distribució àmplia i skewed que tira cap a persurv -> 0. Per tant, **en realitat, *persurv* està anticorrelacionat amb la probabilitat de supervivència.**

    * Altres variables interessants són les que apareixen en majúscules a la figura: aquestes són els diferents **canals d'entrada**. Els resultats *suggereixen* que FLYER, CO-MARKETING i AWIN són canals d'entrada que generen clients amb alta probabilitat de permanència. Tanmateix, donat el que hem après de persurv (que el sentit de la correlació pot està confós per un confounder), caldria pensar com van aquestes variables, i si té sentit que diferents canals d'entrada impliquin un Hazard-Ratio que sigui (FLYER, CO-MARKETING, AWIN) = (3.6, 2.14, 1.67) vegades superior que el 'baseline' -- semblen factors enormes. Indicatiu que la hipòtesi del Cox model no és vàlida?

      * **Hipòtesi del Cox Model (proportional hazards ratio assumption):** "the unique effect of a unit increase in a covariate is multiplicative with respect to the [hazard rate](https://en.wikipedia.org/wiki/Hazard_rate)." És a dir, la funció de risk (hazard function), o probabilitat que un event ocorri (mort, cancel·lació), és de la forma:
        $\lambda(t|X) = \lambda_{0}(t) \exp( \sum_i \beta_i X_i)=\exp(\beta_0(t) + \sum_i \beta_i X_i)$
        on $\lambda_{0}(t)$ és la funció de risc de base i descriu com el risc de l'esdeveniment depèn del temps (típicament, una exponencial si pensem en una desintegració radioactiva, però en processos biològics pot tenir altres formes).
        * La [interpretació](https://lifelines.readthedocs.io/en/latest/Survival%20Regression.html) dels factors $\exp(\beta X)$ és: 
          $\exp(\beta X) = \frac{ \textrm{probab. que individus amb X=True cancel·lin a temps t}} { \textrm{probab. que individus amb X=False cancel·lin a temps t}}$
          és a dir: en quina proporció tenir `X=True` incrementa la probabilitat de cancel·lació. 

      * Una forma típica per a $lambda_0(t)$ és la funció de Weibull basada en la hipòtesi de fallida accelerada (*accelerated failure time (AFT) models*): 
        * **AFT assumption:** La prob. de supervivència de d'una subpoblació A té la mateixa dependència en temps que la d'una altra subpoblació B excepte per un rescalat del temps: $S_A(t) = S_B(t/\lambda(X))$ (és a dir, $\lambda(X)$ dóna un *acceleration factor* que depèn de covariables que defineixen les subpoblacions (X), però no depèn del temps).
        * **Proportional hazards assumption (Cox model):** $\lambda(x) = \exp(\beta_0 + \sum \beta_i X_i)$, d'on hem tret la dependència temporal de $\beta_0(t)$ d'acord amb l'AFT assumption.
        * **Weibull form for survival function $S(t)$:** $S(t) \rightarrow H(t) = (t/\lambda(X))^{\rho}$. 
        * Altogether: **Weibull AFT model:** $S(t) = \left( \frac{t}{\exp( \beta_0 + \sum_i \beta_i X_i)} \right)^\rho$

  * Debat:

    * Jo li he insistit un parell de vegades que les dades que tenen ara i que els indiquen quin són els usuaris amb més risc els han de permetre **dissenyar experiments** per explorar quines són les millors estratègies per a **retenció de clients**.
    * La seva resposta apunta que ell (AA) està força satisfet amb el model actual de predicció amb random forests i els resultats del survival analysis, però no se'l veu molt posat en voler explorar com caldria dissenyar experiments per millorar la presa de decisions per a retenir clients.
    * Caldrà veure quin és el feedback intern que rep de part dels stakeholders, i què voldrien fer amb les hores que manquen per arribar al total contractat inicialment de 20h. Per la meva banda, crec que estaria força bé poder tenir una reunió de nou amb l'equip de Clients (Silvia) per pensar com millor fer ús internament a futur de les prediccions que ara generaran, i com crear nova informació (*intelligence*) que els permeti millorar a llarg termini la retenció i satisfacció dels clients.

## dm 2022-01-26 11:00-12:00 Trobada JMP-AA

* Meeting a petició d'AA per valorar resultats que ha obtingut amb lifelines.

  * Durada: 1h, més 15 min prenent notes. Després, 15 min parlant-ho amb JV.

* Té un dashboard amb Tableau molt bonic on mostra les corbes de supervivència per cada país, rang d'edat, i per diferents canals d'entrada. 

* El que voldria és poder predir quants mesos més sobreviuran els usuaris que estan actius. Això ho parlem i ho pot fer seguint la part de ["Prediction on censored subjects"](https://lifelines.readthedocs.io/en/latest/Survival%20Regression.html#prediction-on-censored-subjects):

  > ```python
  > # Fit Cox Proportional Hazards model to data:
  > cph = CoxPHFitter().fit(dataset, "canctime", "churn")
  > 
  > # filter down to just censored subjects to predict remaining survival:
  > censored_subjects = dataset.loc[~dataset['churn'].astype(bool)]
  > 
  > # predict new survival function
  > cph.predict_survival_function(censored_subjects, conditional_after=censored_subjects_last_obs)
  > 
  > # predict median remaining life given last observation:
  > censored_subjects_last_obs = censored_subjects['canctime']
  > cph.predict_median(censored_subjects, conditional_after=censored_subjects_last_obs)
  > ```

* En fer això, observem alguna cosa estranya amb usuaris amb vida predict_median -> 29 malgrat que tenen 'canctime' = 3.0. Identifiquem que són usuaris que han cancel·lat però tornat a apuntar-se; aquest en concret va cancel·lar per primera vegada als 3 mesos, però tenia un total de capses rebudes 'boxes' = 26. Hem comprovat que el model cph utilitzava internament 'boxes' per calcular la median lifetime crear un nou usuari igual al "problemàtic" però on hem fet test_user['boxes']=0; per a aquest, la predicted_median tenint en compte la darera observació era de només 2 mesos.
* A partir d'això, Alejandro diu que recalcularà les survival curves amb un nou model creat fent servir 'boxes' com a indicador de "customer lifetime value". També aplicarà el model de regressió per a estimar els usuaris que poden cancel·lar el més proper. Ho presentarà als usuaris interns (Jürgen et al.). Un cop hagin arribat a un acord intern sobre la seva satisfacció amb els models desenvolupats, podem fer una reunió a 3 bandes (AA, Jürgen+decisionmakers, Jordis) per pensar propers passos.

 
