computar similaridade jaccard no dataframe
autodidata em python, estou tentando melhorar então qualquer ajuda é muito bem-vinda, muito obrigado! Quero calcular uma similaridade de jaccard em uma coluna do meu dataframe combinando critérios em outra coluna. df se parece com isto:
name bag number item quantity
sally 1 BANANA 3
sally 2 BREAD 1
franck 3 BANANA 2
franck 3 ORANGE 1
franck 3 BREAD 4
robert 4 ORANGE 3
jenny 5 BANANA 4
jenny 5 ORANGE 2
Com cerca de 80 itens categóricos, o número da sacola (amostra) é exclusivo para um comprador, mas eles podem ter mais de um e as quantidades variam de 0 a 4. Eu gostaria de iterar através do número da sacola para comparar o conteúdo com uma similaridade de jaccard ou distância de cada par de bolsa. Se possível com a opção de considerar a quantidade como peso de comparação. o resultado ideal seria um dataframe como aquela matriz Python Pandas Distance usando similaridade jaccard
Eu sinto que a solução está em algum lugar entre este> Como calcular a similaridade do jaccard a partir de um dataframe pandas e como aplicar uma função personalizada a grupos em um dataframe dask, usando várias colunas como entrada de função
Estou pensando que devo iterar por meio de uma máscara para configurar as duas variáveis da função jaccard. Mas em todos os exemplos que vejo, os itens a comparar estão em colunas diferentes. Então, estou meio perdida aqui ... muito obrigado por ajudar! Felicidades
Respostas
Resolver a versão mais fácil e não ponderada do problema pode ser feito com as seguintes etapas:
crie uma tabela dinâmica com seu dataframe atual
p = df.pivot_table( index='bag_number', columns='item', values='quantity', ).fillna(0) # Convert NaN to 0siga o exemplo em sua pergunta vinculada para calcular a distância de Jaccard com
scipyfrom scipy.spatial.distance import jaccard, pdist, squareform m = 1 - squareform(pdist(p.astype(bool), jaccard)) sim = pd.DataFrame(m, index=p.index, columns=p.index)
Resultado:
bag_number 1 2 3 4 5
bag_number
1 1.000000 0.000000 0.333333 0.000000 0.500000
2 0.000000 1.000000 0.333333 0.000000 0.000000
3 0.333333 0.333333 1.000000 0.333333 0.666667
4 0.000000 0.000000 0.333333 1.000000 0.500000
5 0.500000 0.000000 0.666667 0.500000 1.000000
A versão ponderada é apenas um pouco mais complicada. A pdistfunção só oferece suporte a um vetor que será aplicado a todas as comparações, portanto, você precisará criar uma função de similaridade (ou distância) personalizada. De acordo com a Wikipedia , a versão ponderada pode ser calculada da seguinte forma:
import numpy as np
def weighted_jaccard_distance(x, y):
arr = np.array([x, y])
return 1 - arr.min(axis=0).sum() / arr.max(axis=0).sum()
Agora você pode calcular a similaridade ponderada
sim_weighted = pd.DataFrame(
data=1 - squareform(pdist(p, weighted_jaccard_distance)),
index=p.index,
columns=p.index,
)
Resultado:
bag_number 1 2 3 4 5
bag_number
1 1.00 0.000000 0.250000 0.000000 0.500000
2 0.00 1.000000 0.142857 0.000000 0.000000
3 0.25 0.142857 1.000000 0.111111 0.300000
4 0.00 0.000000 0.111111 1.000000 0.285714
5 0.50 0.000000 0.300000 0.285714 1.000000