<jupyter_start><jupyter_text>Regras de AssociaçãoRegras de Associação identificam padrões comuns em itens de um grande conjunto de dados.Neste exercício, nós vamos analisar padrões de comportamento em uma plataforma de filmes (como o Netflix) onde as pessoas costumam assistir seus filmes e séries. Existem alguns padrões claros, como pessoas que gostam de super heróis ou aqueles que assistem a desenhos animados.Regras de Associação são geralmente escritas no formato: **{A} -> {B}**,  o que siginifica que existe uma forte relação entre os itens A e B. Por exemplo, uma possível regra válida para a plataforma de streams é **{Senhor dos Anéis} -> {O Hobbit}**. Se frequentemente uma pessoa que assiste a um filme também assiste a um outro, ou seja os filmes são asssitidos frequentemente juntos, então a plataforma de filmes poderia utilizar esse padrão para aumentar a visualização de alguns filmes, através de recomendações na plataforma.No exemplo acima, **{Senhor dos Anéis} -> {O Hobbit}**, {Senhor dos Anéis} é o **antecedente** e **{O Hobbit}** é o **consequente**. Antecedentes e consequentes podem ter múltiplos itens, por exemplo um regra válida é **{Thor: Ragnarok, Vingadores: Guerra Infinita}->{Vingadores: Ultimato}**. Por quê?Fácil de explicar para pessoas não-técnicasSem necessidade de grande preparação dos dados e engenharia de featuresBom início para explorar dados  Identificando padrões frequentes em usuários de streaming de vídeosNeste exemplo nós utilizaremos regras de associação para analisar um dataset de transações onde cada transação é composta pelos filmes que um mesmo usuário de uma plataforma de filmes assisitu dentro de um intervalo de tempo.Exemplo baseado no tutorial disponível em: https://medium.com/@fabio.italiano/the-apriori-algorithm-in-python-expanding-thors-fan-base-501950d55be9   Passo 1) Leitura do dataset<jupyter_code>import pandas as pd
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules
df = pd.read_csv('dataset_movies/movie_dataset.txt',header=None)
df.head()<jupyter_output><empty_output><jupyter_text>Cada linha do arquivo refere-se a um conjunto de filmes que um determinado usuário leu. Vamos considerar esse conjunto de filmes como sendo o conjunto de itens de uma transação.Entretanto, precisamos transforma os dados para deixá-lo num formato de um dataframe  onde cada coluna se refere a um filme e as linhas aos usuarios. Cada cálula contém 1 quando o usuário assitiu ao filme e 0 no caso contrário.<jupyter_code>import numpy as np
rows = df.shape[0]
filmes = set()
for i in range(rows):
    filmes = filmes.union(set(df.iloc[i].unique()))

np.nan in filmes
filmes.difference_update({np.nan})
df_ = pd.DataFrame(columns=filmes,data=np.zeros((rows,len(filmes))))
df_.head()
def set_units(x):
    return 1
for i in range(rows):
    df_.at[i, df.iloc[i].dropna()] = 1.
df_.head()<jupyter_output><empty_output><jupyter_text>O Algoritmo AprioriAlguns elementos são essenciais para o entendimento do algoritmo Apriori.  **Suporte**: é um número de vezes que o itemset aparece em diferentes transações dividido pelo número total de transações.$$supp(X) = \frac{|t \in T; X \subseteq t|}{|T|}$$Por exemplo, podemos analisar o suporte do filme "Jumanji" fazendo a seguinte operação.<jupyter_code>def supp(df_,X):
    union = np.prod(df_[X].values,axis=1)
    return len(np.nonzero(union)[0])/df_.shape[0]
supp(df_,["Jumanji"])
supp(df_,['Jumanji','Wonder Woman'])<jupyter_output><empty_output><jupyter_text>**Itemset Frequente**: Um conjunto $\{i_1,i_2, ..., i_n\}$ de itens é frequente quando o conjunto de itens ocorre com pelo menos a frequênciade um supporte mínimo, $min\_supp$. **Confiança**:é a indicação de quão frequente uma regra é verdadeira. Quanto maior a confiança, maior é chance de encontrarmos a regra no dataset. É dada por:$$conf(X \rightarrow Y) = supp(X \cup Y)/supp(X)$$Por exemplo, a confiança da regra **{Avengers} -> {Thor}** é dada por:<jupyter_code>def confidence(df_, X, Y):
    return supp(df_,X+Y)/supp(df_,X)
confidence(df_, ['Avengers'], ['Thor'])<jupyter_output><empty_output><jupyter_text>**Quando uma regra satisfaz a um mínimo suporte e confiança, dizemos que a regra é um regra de associação forte.**Em geral, a mineração de regras de associação pode ser definida como:1 - Encontrar todos os itemsets frequentes;2 - Gerar regras de associação fortes a partir desses itens.  Como funciona o algoritmo?* Chamado de **Apriori** pois requer um conhecimento prévio das propriedades do itens mais frequentes;* É um método iterativo onde $k$ itens são utilizados para para explorar $k+1$ itens;* **Ideia geral**: Primeiro encontre o o itemset frequente de tamanho 1 satisfazendo o mínimo suporte, denominado $L_1$. Depois utilize $L_1$ para encontrar $L_2$, os itens frequentes de tamanho 2. $L_2$ é utilizado para encontrar $L_3$ e assim por diante.* **Propriedade Apriori**: Todos os subconjuntos não vazios de um conjunto de itens frequente, também é frequente. Fonte: http://www.lessons2all.com/Apriori.php  Utilizando o algortimo apriori<jupyter_code>frequent_itemsets = apriori(df_, min_support=0.01, use_colnames=True)<jupyter_output><empty_output><jupyter_text>Visualizando itens frequentes<jupyter_code>frequent_itemsets.head()<jupyter_output><empty_output><jupyter_text>Computando regras de associação<jupyter_code>rules = association_rules(frequent_itemsets, metric="confidence", min_threshold=0.2)
rules.head()<jupyter_output><empty_output><jupyter_text>Suporte e confiança não são suficientes para filtrar regras interessantes. Uma medida de correlação também pode ser utilizada. O **lift** é uma medidade simples de correlação que mede se a corrência de um evento A é independente da ocorrência de um ecento B.**Lift**: O lift de uma regra é definido como:  $$lift(X \rightarrow Y): \frac{supp(X \cup Y)}{supp(X) \times supp(Y)}$$* lift 1: a ocorrência de X é independente da ocorrência de Y* lift > 1: possível dependência entre X e Y,  o que faz a regra útil para predizer futuros itens* lift < 1: a presença X tem um efeito negativo na de Y, e vice-versa.Por exemplo, a confiança da regra **{Avengers} -> {Thor}** é dada por:<jupyter_code>def lift(df_, X, Y):
    return supp(df_,X+Y)/(supp(df_,X)*supp(df_,Y))<jupyter_output><empty_output><jupyter_text>Visualizando regras com determinada confiança e lift<jupyter_code>rules[ (rules['lift'] > 1.) &
       (rules['confidence'] >= 0.4) ]
lift(df_,  ['Avengers'], ['Thor'])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09465273509526737, 'fraction_numerical': 0.00645359557467732, 'mean_word_length': 5.77315296566077, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 46, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '618670', 'license': 'MIT', 'n_tokens_mistral': 2326, 'n_tokens_neox': 2269, 'n_words': 777, 'path': '2019/03-Aprendizado_nao_Supervisionado/RegrasDeAssociacao.ipynb', 'repo_name': 'InsightLab/imersao-ciencia-de-dados-2019', 'size': '6508'}