Metadata-Version: 2.1
Name: marketing-attribution-models
Version: 1.0.8
Summary: Metodos de atribuicao de midia
Home-page: https://github.com/DP6/Marketing-Attribution-Models
Author: Andre Tocci
Author-email: andre.tocci@dp6.com.br
License: Apache License 2.0
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Requires-Python: >=3.5
Description-Content-Type: text/markdown
Requires-Dist: numpy
Requires-Dist: pandas
Requires-Dist: matplotlib
Requires-Dist: seaborn

# Marketing Attribution Models

## 1. Sobre a Classe
Classe em Python desenvolvida para soluÃ§Ãµes de problemas de atribuiÃ§Ã£o de mÃ­dia em Marketing Digital.

## 2. Sobre AtribuiÃ§Ã£o Multicanal
No contexto digital, antes de conversÃ£o, o usuÃ¡rio Ã© impactado por diversos pontos de contato, podendo gerar jornadas cada vez mais longas e complexas. 

*Como atribuir os crÃ©ditos das conversÃµes e otimizar o investimento em mÃ­dia online?*

Para resolver esse problema, utilizamos **Modelos de AtribuiÃ§Ã£o**.


### 2.1 Tipos de Modelos

#### Modelos HeurÃ­sticos

- **Last Interaction**:
    - Modelo padrÃ£o de atribuiÃ§Ã£o tanto do Google Analytics, quanto de ferramentas de mÃ­dia como Google Ads e Facebook Business manager;
    - Atribui todo o resultado da conversÃ£o para o Ãºltimo ponto de contato.

- **Last non-Direct Click**:
    - Todo o trÃ¡fego direto Ã© ignorado, e 100% do crÃ©dito da venda vai para o Ãºltimo canal por meio do qual o cliente chegou ao site antes de concluir a conversÃ£o.

- **First Interaction**:
    - Atribui todo o resultado da conversÃ£o para o primeiro ponto de contato.

- **Linear**:
    - Cada ponto de contato no caminho de conversÃ£o.

- **Time Decay**:
    - Os pontos de contato mais prÃ³ximos em termos de tempo da venda ou conversÃ£o recebem a maior parte do crÃ©dito. 

- **Position Based**:
    - No modelo de atribuiÃ§Ã£o Com base na posiÃ§Ã£o, 40% do crÃ©dito Ã© atribuÃ­do a cada primeira e Ãºltima interaÃ§Ã£o, e os 20% de crÃ©dito restantes sÃ£o distribuÃ­dos uniformemente para as interaÃ§Ãµes intermediÃ¡rias.


#### Modelos AlgorÃ­tmicos

#### **Shapley Value**

Conceito vindo da Teoria dos Jogos, para distribuir a contribuiÃ§Ã£o de cada jogador em um jogo de cooperaÃ§Ã£o.

Atribui os crÃ©ditos das conversÃµes calculando a contribuiÃ§Ã£o de cada canal presente na jornada, utilizando permutaÃ§Ãµes de jornadas com e sem o canal em questÃ£o.


**Por exemplo**, como podemos atribuir as 19 conversÃµes na jornada abaixo?

Natural Search > Facebook > Direto > **$19** 


O Shapley Value de cada canal Ã© calculado com base em observaÃ§Ãµes, isto Ã©, para cada jornada, Ã© preciso ter o valores de conversÃ£o para todas as combinaÃ§Ãµes que a compÃµe. 


Natural Search > **$7** <br/>
Facebook > **$6** <br/>
Direto > **$4** <br/>
Natural Search > Facebook > **$15** <br/>
Natural Search > Direto > **$7** <br/>
Facebook > Direto > **$9** <br/>
Natural Search > Facebook > Direto > **$19** <br/>


O nÃºmero de iteraÃ§Ãµes aumenta exponencialmente com o nÃºmero de canais: da ordem de 2^N, sendo N o nÃºmero de canais.

Assim, para uma jornada com 3 canais sÃ£o necessÃ¡rias 8 cÃ¡lculos. **Para jornadas com mais de 15 canais, se torna praticamente inviÃ¡vel.**


O Shapley Value por padrÃ£o nÃ£o considera a ordem dos canais,mas sim a contribuiÃ§Ã£o da presenÃ§a dele na jornada.
Para levar isso em consideraÃ§Ã£o Ã© preciso aumentar a ordem do numero de combinaÃ§Ãµes. 

Disso vem a dificuldade em usar um mÃ©todo que considere a *ordem dos canais* para um grande nÃºmero N, pois, alÃ©m das 2^N interaÃ§Ãµes para o cÃ¡lculo do Shapley Value de um determinado canal i, **precisamos da *observaÃ§Ã£o* do canal i em todas as possÃ­veis posiÃ§Ãµes.**


**Pontos negativos do Shapley Value**
- Limita o nÃºmero de pontos de contato uma vez que o nÃºmero de iteraÃ§Ã£o Ã© da ordem de 2^N;
- Se nÃ£o ordenado, o Shapley Value considera que a contribuiÃ§Ã£o de um canal A Ã© a mesma se antecedido por B ou por C;
- Se ordenado, o nÃºmero de combinaÃ§Ãµes cresce muito e as jornadas devem estar disponÃ­veis, caso contrÃ¡rio atribui-se zero Ã quela jornada;
- Canais que estÃ£o poucos presentes ou presentes em jornadas longas vÃ£o ter pequenas contribuiÃ§Ãµes;


#### **Cadeias de Markov**
Uma cadeia de Markov Ã© um caso particular de processo estocÃ¡stico com a propriedade de que a distribuiÃ§Ã£o de probabilidade do prÃ³ximo estado depende apenas do estado atual e nÃ£o na sequÃªncia de eventos que o precederam.


Utilizando cadeias de markov no contexto de atribuiÃ§Ã£o multicanal, podemos calcular a probalidade de interaÃ§Ãµes entre os canais de mÃ­dia por meio da **Matriz de TransiÃ§Ã£o**.


Para encontrar a contribuiÃ§Ã£o de cada canal, utilizamos o **Removal Effect**: remove-se o canal em questÃ£o da jornada e calcula-se a probabilidade de conversÃ£o.

A atribuiÃ§Ã£o Ã© dada pela razÃ£o entre a diferenÃ§a da probabilidade total de conversÃ£o e a probabilidade de conversÃ£o sem o canal, e a probabilidade total de conversÃ£o original.

Quanto maior o removal effect, maior a contribuiÃ§Ã£o do canal para a conversÃ£o.


**Os processos markovianos nÃ£o possuem nenhum tipo de restriÃ§Ã£o em relaÃ§Ã£o a quantidade ou ordem dos canais e
considera a sequÃªncia de canais como uma parte fundamental do algoritmo**.


### 2.2 ReferÃªncias
- [Attribution Models in Marketing](https://data-science-blog.com/blog/2019/04/18/attribution-models-in-marketing/)
- [Attribution Theory: The Two Best Models for Algorithmic Marketing Attribution â€“ Implemented in Apache Spark and R](http://datafeedtoolbox.com/attribution-theory-the-two-best-models-for-algorithmic-marketing-attribution-implemented-in-apache-spark-and-r/)
- [Game Theory Attribution: The Model Youâ€™ve Probably Never Heard Of](https://clearcode.cc/blog/game-theory-attribution/)
- [Marketing Channel Attribution With Markov Models In R](https://www.bounteous.com/insights/2016/06/30/marketing-channel-attribution-markov-models-r/?ns=l)
- [Multi-Channel Funnels Data-Driven Attribution](https://support.google.com/analytics/topic/3180362?hl=en&ref_topic=3205717)
- [Marketing Multi-Channel Attribution model with R (part 1: Markov chains concept)](https://analyzecore.com/2016/08/03/attribution-model-r-part-1/)
- [Marketing Multi-Channel Attribution model with R (part 2: practical issues)](https://analyzecore.com/2017/05/31/marketing-multi-channel-attribution-model-r-part-2-practical-issues/)
- [ml-book/shapley](https://christophm.github.io/interpretable-ml-book/shapley.html)
- [Overview of Attribution modeling in MCF](https://support.google.com/analytics/answer/1662518?hl=en)

## 3. Importando a Classe


```python
>> pip install marketing_attribution_models
```


```python
from marketing_attribution_models import MAM
```

## 4. DemonstraÃ§Ã£o

### **Criando o objeto MAM**

**A criaÃ§Ã£o do objeto MAM** Ã© baseado em **dois formatos de Data Frame** e que Ã© guiado pelo parÃ¢metro group_channels:

*   **group_channels = True**. Espera-se receber uma base na qual **cada linha seria uma sessÃ£o da jornada do usuÃ¡rio**.
  * Esse data frame deve conter colunas representando ID do UsuÃ¡rio, indicaÃ§Ã£o booleana se houve ou nÃ£o transaÃ§Ã£o durante a sessÃ£o, timestamp da sessÃ£o e o canal na qual o usuÃ¡rio gerou a sessÃ£o;
*   **group_channels = False**. Recebe a base na qual a **jornada jÃ¡ foi agrupada** e que cada linha representa uma jornada completa de determinado usuÃ¡rio atÃ© a conversÃ£o. Para os usuÃ¡rios do Google Analytics, essa base pode ser gerada atravÃ©s da exportaÃ§Ã£o do relatÃ³rio de Top Conversion Paths na aba de Conversions.
  * Nesse caso a coluna de canais e time_till_conv_colname receberiam em cada linha uma jornada separada por um separador, ' > ' como padrÃ£o e que pode ser alterado no parÃ¢metro path_separator.

No nosso caso, iremos apresentar um exemplo na qual as jornadas ainda nÃ£o estÃ£o agrupadas, que cada linha representa uma jornada e que ainda nÃ£o temos um ID de Cada Jornada.

**Ponto de AtenÃ§Ã£o:**
A classe jÃ¡ contempla uma funÃ§Ã£o representada pelo parÃ¢metro create_journey_id_based_on_conversion, que caso seja True, serÃ¡ criado um ID da Jornada baseado nas colunas de ID do UsuÃ¡rio, passada no parÃ¢metro group_channels_id_list e a coluna que representa se houve ou nÃ£o conversÃ£o, passada no parÃ¢metro journey_with_conv_colname.

Nesse caso, serÃ£o ordenadas as sessÃµes de cada usuÃ¡rio e a cada transaÃ§Ã£o serÃ¡ criado um novo ID da Jornada. Entretanto, **encorajamos que seja criado um ID da Jornada com base no conhecimento de negÃ³cio de cada base explorada**. Podendo criar condiÃ§Ãµes expecÃ­ficas de tempo para que haja uma quebra de jornada, como por explempo se identificado que a jornada mÃ©dia de determidado negÃ³cio dura 1 semana atÃ© a conversÃ£o, podemos adotar um critÃ©rio que se determinado usuÃ¡rio nÃ£o interagir com o site por uma semana, sua jornada serÃ¡ quebrada, pois pode haver uma quebra de interesse.



Exemplificando como seria a configuraÃ§Ã£o dos parametros no cenÃ¡rio descrito acima com group_channels = True. 

1. Deve ser passado o **Pandas Data Frame** contendo a base de dados a ser analisada;
2. Indicar o formato da base em **group_channels**=True
3. Nome da coluna que contem os agrupamentos de canais em **channels_colname**;
4. Coluna Booleana indicando se houve ou nÃ£o conversÃ£o na sessÃ£o em **journey_with_conv_colname**;
5. Lista contendo os nomes das colunas que representam o ID da Jornada, podendo ser uma combinaÃ§Ã£o de colunas em **group_channels_by_id_list**. Mas nesse caso como estamos indicando que iremos criar um ID da Jornada no parÃ¢metro **create_journey_id_based_on_conversion = True**, basta indicar a coluna de ID do UsuÃ¡rio; 
6. Coluna representando a data em que ocorreu a sessÃ£o em **group_timestamp_colname**. Coluna que pode receber alÃ©m dos dias do ano, o horÃ¡rio em que a sessÃ£o ocorreu;
7. Por fim, em nosso caso, indicamos que iremos gerar um ID da Jornada a partir das colunas indicadas nos parÃ¢metros group_channels_by_id_list e journey_with_conv_colname, em **create_journey_id_based_on_conversion** = True



```python
attributions = MAM(df,
    group_channels=True,
    channels_colname = 'channels',
    journey_with_conv_colname= 'has_transaction',
    group_channels_by_id_list=['user_id'],
    group_timestamp_colname = 'visitStartTime',
    create_journey_id_based_on_conversion = True)
```

Para fins exploratÃ³rios e de aprendizado, implementamos uma forma de gerar uma **base de dados aleatÃ³ria** atravÃ©s do parÃ¢metro **random_df=True**. NÃ£o sendo necessÃ¡rio o preenchimento dos demais.


```python
attributions = MAM(random_df=True)
```

Assim que o objeto foi criado, podemos checar como ficou a **base apÃ³s a criaÃ§Ã£o do journey_id e o agrupamento das sessÃµes** em joranadas atravÃ©s do **atributo .DataFrame.**


```python
attributions.DataFrame
```
|  | journey_id | channels_agg | time_till_conv_agg | converted_agg | conversion_value |
| - | - | - | - | - | - |
| 0 | id:0_J:0 | Facebook | 0.0 | True | 1 |
| 1 | id:0_J:1 | Google Search | 0.0 | True | 1 |
| 2 | id:0_J:10 | Google Search > Organic > Email Marketing | 72.0 > 24.0 > 0.0 | True | 1 |
| 3 | id:0_J:11 | Organic | 0.0 | True | 1 |
| 4 | id:0_J:12 | Email Marketing > Facebook | 432.0 > 0.0 | True | 1 |
| ... | ... | ... | ... | ... | ... |
| 20341 | id:9_J:5 | Direct > Facebook | 120.0 > 0.0 | True | 1 |
| 20342 | id:9_J:6 | Google Search > Google Search > Google Search | 48.0 > 24.0 > 0.0 | True | 1 |
| 20343 | id:9_J:7 | Organic > Organic > Google Search > Google Search | 480.0 > 480.0 > 288.0 > 0.0 | True | 1 |
| 20344 | id:9_J:8 | Direct > Organic | 168.0 > 0.0 | True | 1 |
| 20345 | id:9_J:9 | Google Search > Organic > Google Search > Emai... | 528.0 > 528.0 > 408.0 > 240.0 > 0.0 | True | 1 |

Esse **atributo Ã© atualizado para cada modelo gerado** e nos casos dos resultados heurÃ­sticos, serÃ¡ adicionado uma coluna contendo a atribuiÃ§Ã£o dada por determinado modelo no final.

**AtenÃ§Ã£o:**
Os cÃ¡lculos dos modelos nÃ£o sÃ£o calculados com base no parÃ¢metro .DataFrame, caso ele seja alterado, os resultados nÃ£o serÃ£o afetados.


```python
attributions.attribution_last_click()
attributions.DataFrame
```

| | journey_id | channels_agg | time_till_conv_agg | converted_agg | conversion_value |
| - | - | - | - | - | - |
| 0 | id:0_J:0 | Facebook | 0.0 | True | 1 |
| 1 | id:0_J:1 | Google Search | 0.0 | True | 1 |
| 2 | id:0_J:10 | Google Search > Organic > Email Marketing | 72.0 > 24.0 > 0.0 | True | 1 |
| 3 | id:0_J:11 | Organic | 0.0 | True | 1 |
| 4 | id:0_J:12 | Email Marketing > Facebook | 432.0 > 0.0 | True | 1 |
| ... | ... | ... | ... | ... | ... |
| 20341 | id:9_J:5 | Direct > Facebook | 120.0 > 0.0 | True | 1 |
| 20342 | id:9_J:6 | Google Search > Google Search > Google Search | 48.0 > 24.0 > 0.0 | True | 1 |
| 20343 | id:9_J:7 | Organic > Organic > Google Search > Google Search | 480.0 > 480.0 > 288.0 > 0.0 | True | 1 |
| 20344 | id:9_J:8 | Direct > Organic | 168.0 > 0.0 | True | 1 |
| 20345 | id:9_J:9 | Google Search > Organic > Google Search > Emai... | 528.0 > 528.0 > 408.0 > 240.0 > 0.0 | True | 1 |


Como trabalhamos com um grande volume de dados, sabemos que nÃ£o Ã© possivel avaliar os resultados atribuÃ­dos para cada jornada que resultou em uma transaÃ§Ã£o. Assim, atravÃ©s da consulta do **atributo group_by_channels_models trazemos os resultados dos modelos agrupados por cada canal**. 

**AtenÃ§Ã£o:**
Os resultados agrupados nÃ£o se sobrescrevem caso o mesmo modelo seja calculado mais de uma vez e ambos resultados estarÃ£o presentes no atributo group_by_channels_models.


```python
attributions.group_by_channels_models
```




<div>

| channels | attribution_last_click_heuristic |
| -- | -- |
| Direct | 2133 |
| Email Marketing | 1033 |
| Facebook | 3168 |
| Google Display | 1073 |
| Google Search | 4255 |
| Instagram | 1028 |
| Organic | 6322 |
| Youtube | 1093 |



E como acontece com o .DataFrame, o **group_by_channels_models tambÃ©m Ã© atualizado para cada novo modelo rodado** e sem a limitaÃ§Ã£o de nÃ£o trazer os resultados algorÃ­timicos


```python
attributions.attribution_shapley()
attributions.group_by_channels_models
```

| | channels | attribution_last_click_heuristic | attribution_shapley_size4_conv_rate_algorithmic |
| - | - | - | - |
| 0 | Direct | 109 | 74.926849 |
| 1 | Email Marketing | 54 | 70.558428 |
| 2 | Facebook | 160 | 160.628945 |
| 3 | Google Display | 65 | 110.649352 |
| 4 | Google Search | 193 | 202.179519 |
| 5 | Instagram | 64 | 72.982433 |
| 6 | Organic | 315 | 265.768549 |
| 7 | Youtube | 58 | 60.305925 |

### **Sobre os modelos**

Todos os modelos heurÃ­sticos apresentam o mesmo comportamento quanto Ã  atualizaÃ§Ã£o dos **atributos .DataFrame e .group_by_channels_models** e tambÃ©m quanto ao **output do mÃ©todo** que irÃ¡ retornar uma **tupla contendo dois pandas Series**.


```python
attribution_first_click = attributions.attribution_first_click()
```

**O primeiro output** da tupla corresponde aos resultados na **granularidade de jornada**, similar ao resultado encontrado no .DataFrame


```python
attribution_first_click[0]
```




    0                          [1, 0, 0, 0, 0]
    1                                      [1]
    2              [1, 0, 0, 0, 0, 0, 0, 0, 0]
    3                                   [1, 0]
    4                                      [1]
                           ...                
    20512                               [1, 0]
    20513                            [1, 0, 0]
    20514    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    20515                            [1, 0, 0]
    20516                         [1, 0, 0, 0]
    Length: 20517, dtype: object



**JÃ¡ o segundo** corresponde aos resultados na **granularidade de canal**, similar ao resultado encontrado no .DataFrame


```python
attribution_first_click[1]
```

|  | channels | attribution_first_click_heuristic |
| - | - | - |
| 0 | Direct | 2078 |
| 1 | Email Marketing | 1095 |
| 2 | Facebook | 3177 |
| 3 | Google Display | 1066 |
| 4 | Google Search | 4259 |
| 5 | Instagram | 1007 |
| 6 | Organic | 6361 |
| 7 | Youtube | 1062 |

#### **CustomizaÃ§Ã£o dos modelos**

Dentre os modelos presentes na classe apenas o Last Click, o First Click e Linear nÃ£o possuem parametros customizÃ¡veis alÃ©m do **parametro group_by_channels_models**, que recebe um **valor booleano** e que caso **falso**, **nÃ£o irÃ¡ retornar os resultados dos modelos agrupados por canais**.

##### **Modelo Last Click Non** 

Foi criado para replicar o comportamento padrÃ£o do Google Analytics na qual o **trÃ¡fego Direto Ã© sobreposto** caso ocorra apÃ³s alguma interaÃ§Ã£o de outra origem dentro de determinado perÃ­odo.

Por padrÃ£o o parÃ¢metro but_not_this_channel recebe o valor 'Direct', mas pode ser alterado para outros canais / valores de acordo com os seus canais e agrupamentos.




```python
attributions.attribution_last_click_non(but_not_this_channel='Direct')[1]
```

| channels | attribution_last_click_non_Direct_heuristic |
| - | - | - |
| 0 | Direct | 11 |
| 1 | Email Marketing | 60 |
| 2 | Facebook | 172 |
| 3 | Google Display | 69 |
| 4 | Google Search | 224 |
| 5 | Instagram | 67 |
| 6 | Organic | 350 |
| 7 | Youtube | 65 |

##### **Modelo Position Based** 

Pode receber uma lista no parÃ¢metro **list_positions_first_middle_last** determinando os percentuais que serÃ£o atribuÃ­dos para o Ã­nicio, meio e fim da jornada de acordo com o contexto de negÃ³cio do seu cliente/dado. E que **por padrÃ£o** Ã© distribuÃ­do com os percentuÃ¡is **40% para o canal introdutor, 20% distribuÃ­do para os canais intermediÃ¡rios e 40% para o conversor.**


```python
attributions.attribution_position_based(list_positions_first_middle_last=[0.3, 0.3, 0.4])[1]
```

|  | channels | attribution_position_based_0.3_0.3_0.4_heuristic |
| - | - | - |
| 0 | Direct | 95.685085 |
| 1 | Email Marketing | 57.617191 |
| 2 | Facebook | 145.817501 |
| 3 | Google Display | 56.340693 |
| 4 | Google Search | 193.282305 |
| 5 | Instagram | 54.678557 |
| 6 | Organic | 288.148896 |
| 7 | Youtube | 55.629772 |

##### **Modelo Time Decay** 

Pode ser curtomizado quanto ao **percentual de decaimento** no parÃ¢metro **decay_over_time** e quanto ao **tempo em horas na qual esse percentual serÃ¡ aplicado** no parÃ¢metro **frequency**.

Contudo, vale salientar que caso haja mais pontos de contato entre os espaÃ§os de tempo do decaimento, o valor serÃ¡ distribuÃ­do igualmente para esses canais;

Exemplo de funcionamento do modelo:
- **Canais:** Facebook > Organic > Paid Search
- **Tempo atÃ© a ConversÃ£o:** 14 > 12 > 0
- **FrequÃªncia do decaimento:** 7
- **Resultados atribuÃ­dos:**
  - 25% para Facebook;
  - 25% para Organic;
  - 50% para Paid Search;



```python
attributions.attribution_time_decay(
    decay_over_time=0.6,
    frequency=7)[1]
```

|  | channels | attribution_time_decay0.6_freq7_heuristic |
| - | - | - |
| 0 | Direct | 108.679538 |
| 1 | Email Marketing | 54.425914 |
| 2 | Facebook | 159.592216 |
| 3 | Google Display | 64.350107 |
| 4 | Google Search | 192.838884 |
| 5 | Instagram | 64.611414 |
| 6 | Organic | 314.920082 |
| 7 | Youtube | 58.581845 |

##### **Markov Chains**

**Modelo de AtribuiÃ§Ã£o** baseado em **Cadeias de Markov** nos auxilia a solucionar o problema de atribuiÃ§Ã£o de mÃ­dia com uma **abordagem algorÃ­timica** baseada em dados que calcula a probabilidade de transiÃ§Ã£o entre canais.

Esse modelo se comporta como os demais quanto a atualizaÃ§Ã£o do .DataFrame e do .group_by_channels_models, alÃ©m de **retornar uma tupla** com os dois primeiros resultados representando os mesmos descritos anteriormente nos modelos heurÃ­sticos. Contudo, obtemos dois outputs, a **matriz de transiÃ§Ã£o** e o **removal effect**.

Como parÃ¢metro de entrada temos, a princÃ­pio, como indicar se irÃ¡ ser considerado ou nÃ£o a probabilidade de transiÃ§Ã£o para o mesmo estado.


```python
attribution_markov = attributions.attribution_markov(transition_to_same_state=False)
```

|  | channels | attribution_markov_algorithmic |
| - | - | - |
| 0 | Direct | 2305.324362 |
| 1 | Email Marketing | 1237.400774 |
| 2 | Facebook | 3273.918832 |
| 3 | Youtube | 1231.183938 |
| 4 | Google Search | 4035.260685 |
| 5 | Instagram | 1205.949095 |
| 6 | Organic | 5358.270644 |
| 7 | Google Display | 1213.691671 |

Essa configuraÃ§Ã£o **nÃ£o afeta os resultados agregados** e que sÃ£o atribuÃ­dos para cada canal, **mas sim os valores observados na matriz de transiÃ§Ã£o**. E como inficamos **transition_to_same_state=False** a linha diagonal, que representa a auto-transiÃ§Ã£o, aparece zerada.


```python
ax, fig = plt.subplots(figsize=(15,10))
sns.heatmap(attribution_markov[2].round(3), cmap="YlGnBu", annot=True, linewidths=.5)
```




![png](https://raw.githubusercontent.com/DP6/Marketing-Attribution-Models/master/readme-images/output_37_1.png)


**Removal Effect**, quarto output dos resultados attribution_markov, Ã© dada pela razÃ£o entre a diferenÃ§a da probabilidade total de conversÃ£o e a probabilidade de conversÃ£o sem o canal, e a probabilidade total de conversÃ£o original.


```python
ax, fig = plt.subplots(figsize=(2,5))
sns.heatmap(attribution_markov[3].round(3), cmap="YlGnBu", annot=True, linewidths=.5)
```




![png](https://raw.githubusercontent.com/DP6/Marketing-Attribution-Models/master/readme-images/output_39_1.png)


##### **Shapley Value**

Por fim, temos o segundo modelo algorÃ­tmico da classe MAM o **Shapley Value**, conceito vindo da **Teoria dos Jogos**, para distribuir a contribuiÃ§Ã£o de cada jogador em um jogo de cooperaÃ§Ã£o.

Modelo atribui os crÃ©ditos das conversÃµes calculando a contribuiÃ§Ã£o de cada canal presente na jornada, utilizando combinaÃ§Ãµes de jornadas com e sem o canal em questÃ£o. 

ParÃ¢metro **size limita quantidade de canais Ãºnicos na jornada**, por **padrÃ£o** Ã© definido como os **4 Ãºltimos**. Isso ocorre pois o nÃºmero de iteraÃ§Ãµes aumenta exponencialmente com o nÃºmero de canais. Da ordem de 2N, sendo N o nÃºmero de canais.   

A metodologia do cÃ¡lculo das contribuiÃ§Ãµes marginais pode variar atravÃ©s do **parÃ¢metro order**, que por padrÃ£o calcula a contribuiÃ§Ã£o da **combinaÃ§Ã£o dos canais independende da ordem em que aparecem** nas diferentes jornadas.



```python
attributions.attribution_shapley(size=4, order=True, values_col='conv_rate')[0]
```

|  | combinations | conversions | total_sequences | conversion_value | conv_rate | attribution_shapley_size4_conv_rate_order_algorithmic |
| - | - | - | - | - | - | - |
| 0 | Direct | 909 | 926 | 909 | 0.981641 | [909.0] |
| 1 | Direct > Email Marketing | 27 | 28 | 27 | 0.964286 | [13.948270234099155, 13.051729765900845] |
| 2 | Direct > Email Marketing > Facebook | 5 | 5 | 5 | 1.000000 | [1.6636366232390172, 1.5835883671498818, 1.752... |
| 3 | Direct > Email Marketing > Facebook > Google D... | 1 | 1 | 1 | 1.000000 | [0.2563402919193473, 0.2345560799963515, 0.259... |
| 4 | Direct > Email Marketing > Facebook > Google S... | 1 | 1 | 1 | 1.000000 | [0.2522517802130265, 0.2401286956930936, 0.255... |
| ... | ... | ... | ... | ... | ... | ... |
| 1278 | Youtube > Organic > Google Search > Google Dis... | 1 | 2 | 1 | 0.500000 | [0.2514214624662836, 0.24872101523605275, 0.24... |
| 1279 | Youtube > Organic > Google Search > Instagram | 1 | 1 | 1 | 1.000000 | [0.2544401477637237, 0.2541071889956603, 0.253... |
| 1280 | Youtube > Organic > Instagram | 4 | 4 | 4 | 1.000000 | [1.2757196742326997, 1.4712839059493295, 1.252... |
| 1281 | Youtube > Organic > Instagram > Facebook | 1 | 1 | 1 | 1.000000 | [0.2357631944623868, 0.2610913781266248, 0.247... |
| 1282 | Youtube > Organic > Instagram > Google Search | 3 | 3 | 3 | 1.000000 | [0.7223482210689489, 0.7769049003203142, 0.726... |

Por fim, parÃ¢metro na qual o Shapley Value serÃ¡ calculado pode ser alterado em **values_col**, que por padrÃ£o utiliza a **taxa de conversÃ£o** que Ã© uma forma de **considerarmos as nÃ£o conversÃµes no cÃ¡lculo do modelo**. Contudo, tambÃ©m podemos considerar no cÃ¡lculo o total de conversÃµes ou o valor gerados pelas conversÃµes, como demostrado abaixo. 


```python
attributions.attribution_shapley(size=3, order=False, values_col='conversions')[0]
```

|  | combinations | conversions | total_sequences | conversion_value | conv_rate | attribution_shapley_size3_conversions_algorithmic |
| - | - | - | - | - | - | - |
| 0 | Direct | 11 | 18 | 18 | 0.611111 | [11.0] |
| 1 | Direct > Email Marketing | 4 | 5 | 5 | 0.800000 | [2.0, 2.0] |
| 2 | Direct > Email Marketing > Google Search | 1 | 2 | 2 | 0.500000 | [-3.1666666666666665, -7.666666666666666, 11.8... |
| 3 | Direct > Email Marketing > Organic | 4 | 6 | 6 | 0.666667 | [-7.833333333333333, -10.833333333333332, 22.6... |
| 4 | Direct > Facebook | 3 | 4 | 4 | 0.750000 | [-8.5, 11.5] |
| ... | ... | ... | ... | ... | ... | ... |
| 75 | Instagram > Organic > Youtube | 46 | 123 | 123 | 0.373984 | [5.833333333333332, 34.33333333333333, 5.83333... |
| 76 | Instagram > Youtube | 2 | 4 | 4 | 0.500000 | [2.0, 0.0] |
| 77 | Organic | 64 | 92 | 92 | 0.695652 | [64.0] |
| 78 | Organic > Youtube | 8 | 11 | 11 | 0.727273 | [30.5, -22.5] |
| 79 | Youtube | 11 | 15 | 15 | 0.733333 | [11.0] |

### VisualizaÃ§Ã£o
E agora que temos os resultados atribuÃ­dos pelos diferentes modelos guardados em nosso objeto **.group_by_channels_models** de acordo com o nosso contexto de negÃ³cio podemos plotar um grÃ¡fico e comparar os resultados.


```python
attributions.plot()
```



![png](https://raw.githubusercontent.com/DP6/Marketing-Attribution-Models/master/readme-images/output_45_1.png)


Caso queira selecionar apenas os modelos algorÃ­timicos, podemos especifica-lo no **parÃ¢metro model_type**.


```python
attributions.plot(model_type='algorithmic')
```




![png](https://raw.githubusercontent.com/DP6/Marketing-Attribution-Models/master/readme-images/output_47_1.png)




