Cosinusovereenkomst tussen 2 getallenlijsten

Ik wil de cosinusovereenkomst tussen twee lijsten berekenen, laten we zeggen bijvoorbeeld lijst 1 die dataSetI is en lijst 2 die dataSetII.

Stel dat dataSetI [3, 45, 7, 2] is en dataSetII [2, 54, 13, 15]. De lengte van de lijsten is altijd gelijk. Ik wil cosinus-overeenkomst rapporteren als een getal tussen 0 en 1.

dataSetI = [3, 45, 7, 2]
dataSetII = [2, 54, 13, 15]
def cosine_similarity(list1, list2):
  # How to?
  pass
print(cosine_similarity(dataSetI, dataSetII))

Antwoord 1, autoriteit 100%

Je moet SciPy proberen. Het heeft een aantal nuttige wetenschappelijke routines, bijvoorbeeld “routines voor het numeriek berekenen van integralen, het oplossen van differentiaalvergelijkingen, optimalisatie en schaarse matrices.” Het gebruikt de supersnelle geoptimaliseerde NumPy voor het kraken van getallen. Zie hier voor installatie.

Houd er rekening mee dat ruimtelijke.afstand.cosine de afstand berekent, en niet de overeenkomst. U moet dus de waarde van 1 aftrekken om de overeenkomst te krijgen.

from scipy import spatial
dataSetI = [3, 45, 7, 2]
dataSetII = [2, 54, 13, 15]
result = 1 - spatial.distance.cosine(dataSetI, dataSetII)

Antwoord 2, autoriteit 91%

een andere versie gebaseerd op alleen numpy

from numpy import dot
from numpy.linalg import norm
cos_sim = dot(a, b)/(norm(a)*norm(b))

Antwoord 3, autoriteit 44%

U kunt de functie cosine_similarity gebruiken van sklearn.metrics.pairwise docs

In [23]: from sklearn.metrics.pairwise import cosine_similarity
In [24]: cosine_similarity([[1, 0, -1]], [[-1,-1, 0]])
Out[24]: array([[-0.5]])

Antwoord 4, autoriteit 19%

Ik denk niet dat prestaties hier veel uitmaken, maar ik kan het niet laten. De functie zip() kopieert beide vectoren volledig (eigenlijk meer een matrixtransponering) om de gegevens in “pythonische” volgorde te krijgen. Het zou interessant zijn om de implementatie van moeren-en-bouten te timen:

import math
def cosine_similarity(v1,v2):
    "compute cosine similarity of v1 to v2: (v1 dot v2)/{||v1||*||v2||)"
    sumxx, sumxy, sumyy = 0, 0, 0
    for i in range(len(v1)):
        x = v1[i]; y = v2[i]
        sumxx += x*x
        sumyy += y*y
        sumxy += x*y
    return sumxy/math.sqrt(sumxx*sumyy)
v1,v2 = [3, 45, 7, 2], [2, 54, 13, 15]
print(v1, v2, cosine_similarity(v1,v2))
Output: [3, 45, 7, 2] [2, 54, 13, 15] 0.972284251712

Dat gaat door de C-achtige ruis van het één voor één extraheren van elementen, maar kopieert geen bulkarray en krijgt alles wat belangrijk is gedaan in een enkele for-lus en gebruikt een enkele vierkantswortel.

ETA: afdrukaanroep bijgewerkt als functie. (Het origineel was Python 2.7, niet 3.3. De huidige draait onder Python 2.7 met een from __future__ import print_function-instructie.) De uitvoer is hoe dan ook hetzelfde.

CPYthon 2.7.3 op 3.0GHz Core 2 Duo:

>>> timeit.timeit("cosine_similarity(v1,v2)",setup="from __main__ import cosine_similarity, v1, v2")
2.4261788514654654
>>> timeit.timeit("cosine_measure(v1,v2)",setup="from __main__ import cosine_measure, v1, v2")
8.794677709375264

Dus de niet-pythonische manier is in dit geval ongeveer 3,6 keer sneller.


Antwoord 5, autoriteit 11%

zonder invoer

math.sqrt(x)

kan worden vervangen door

x** .5

zonder numpy.dot() te gebruiken, moet u uw eigen puntfunctie maken met behulp van lijstbegrip:

def dot(A,B): 
    return (sum(a*b for a,b in zip(A,B)))

en dan is het gewoon een kwestie van de cosinus-overeenkomstformule toepassen:

def cosine_similarity(a,b):
    return dot(a,b) / ( (dot(a,a) **.5) * (dot(b,b) ** .5) )

Antwoord 6, autoriteit 8%

Ik heb een benchmark gedaan op basis van verschillende antwoorden in de vraag en het volgende fragment zou wees de beste keuze:

def dot_product2(v1, v2):
    return sum(map(operator.mul, v1, v2))
def vector_cos5(v1, v2):
    prod = dot_product2(v1, v2)
    len1 = math.sqrt(dot_product2(v1, v1))
    len2 = math.sqrt(dot_product2(v2, v2))
    return prod / (len1 * len2)

Het resultaat verbaast me dat de implementatie op basis van scipy niet de snelste is. Ik heb geprofileerd en vind dat cosinus in scipy veel tijd kost om een ​​vector van python-lijst naar numpy-array te casten.

voer hier de afbeeldingsbeschrijving in


Antwoord 7, autoriteit 4%

import math
from itertools import izip
def dot_product(v1, v2):
    return sum(map(lambda x: x[0] * x[1], izip(v1, v2)))
def cosine_measure(v1, v2):
    prod = dot_product(v1, v2)
    len1 = math.sqrt(dot_product(v1, v1))
    len2 = math.sqrt(dot_product(v2, v2))
    return prod / (len1 * len2)

Je kunt het afronden na het berekenen:

cosine = format(round(cosine_measure(v1, v2), 3))

Als je het heel kort wilt, kun je deze oneliner gebruiken:

from math import sqrt
from itertools import izip
def cosine_measure(v1, v2):
    return (lambda (x, y, z): x / sqrt(y * z))(reduce(lambda x, y: (x[0] + y[0] * y[1], x[1] + y[0]**2, x[2] + y[1]**2), izip(v1, v2), (0, 0, 0)))

Antwoord 8

Je kunt dit in Python doen met een eenvoudige functie:

def get_cosine(text1, text2):
  vec1 = text1
  vec2 = text2
  intersection = set(vec1.keys()) & set(vec2.keys())
  numerator = sum([vec1[x] * vec2[x] for x in intersection])
  sum1 = sum([vec1[x]**2 for x in vec1.keys()])
  sum2 = sum([vec2[x]**2 for x in vec2.keys()])
  denominator = math.sqrt(sum1) * math.sqrt(sum2)
  if not denominator:
     return 0.0
  else:
     return round(float(numerator) / denominator, 3)
dataSet1 = [3, 45, 7, 2]
dataSet2 = [2, 54, 13, 15]
get_cosine(dataSet1, dataSet2)

Antwoord 9

Numpy gebruiken om één lijst met getallen te vergelijken met meerdere lijsten (matrix):

def cosine_similarity(vector,matrix):
   return ( np.sum(vector*matrix,axis=1) / ( np.sqrt(np.sum(matrix**2,axis=1)) * np.sqrt(np.sum(vector**2)) ) )[::-1]

Antwoord 10

U kunt deze eenvoudige functie gebruiken om de cosinusovereenkomst te berekenen:

def cosine_similarity(a, b):
  return sum([i*j for i,j in zip(a, b)])/(math.sqrt(sum([i*i for i in a]))* math.sqrt(sum([i*i for i in b])))

Antwoord 11

Een andere versie, als je een scenario hebt waarin je een lijst met vectoren en een vraagvector hebt en je wilt de cosinusovereenkomst van de vraagvector met alle vectoren in de lijst berekenen, dan kun je dat in één keer doen in het onderstaande mode:

>>> import numpy as np
>>> A      # list of vectors, shape -> m x n
array([[ 3, 45,  7,  2],
       [ 1, 23,  3,  4]])
>>> B      # query vector, shape -> 1 x n
array([ 2, 54, 13, 15])
>>> similarity_scores = A.dot(B)/ (np.linalg.norm(A, axis=1) * np.linalg.norm(B))
>>> similarity_scores
array([0.97228425, 0.99026919])

Antwoord 12

Als je al gebruik maakt van PyTorch, zou je met hun CosineSimilarity-implementatie.

Stel dat je twee n-dimensionale numpy.ndarrays, v1 en v2 hebt, dwz hun vormen zijn beide (n,). Zo krijg je hun cosinus-overeenkomst:

import torch
import torch.nn as nn
cos = nn.CosineSimilarity()
cos(torch.tensor([v1]), torch.tensor([v2])).item()

Of stel dat je twee numpy.ndarrays w1 en w2 hebt, waarvan de vormen beide (m, n). Het volgende geeft je een lijst met cosinus-overeenkomsten, waarbij elk de cosinus-overeenkomst is tussen een rij in w1 en de corresponderende rij in w2:

cos(torch.tensor(w1), torch.tensor(w2)).tolist()

Antwoord 13

We kunnen de cosinus-overeenkomst eenvoudig berekenen met eenvoudige wiskundige vergelijkingen.
Cosinus_similarity = 1- (dotproduct van vectoren/(product van norm van de vectoren)). We kunnen elk twee functies definiëren voor berekeningen van puntproduct en norm.

def dprod(a,b):
    sum=0
    for i in range(len(a)):
        sum+=a[i]*b[i]
    return sum
def norm(a):
    norm=0
    for i in range(len(a)):
    norm+=a[i]**2
    return norm**0.5
    cosine_a_b = 1-(dprod(a,b)/(norm(a)*norm(b)))

Antwoord 14

Alle antwoorden zijn geweldig voor situaties waarin u NumPy niet kunt gebruiken. Als je kunt, is hier een andere benadering:

def cosine(x, y):
    dot_products = np.dot(x, y.T)
    norm_products = np.linalg.norm(x) * np.linalg.norm(y)
    return dot_products / (norm_products + EPSILON)

Houd ook rekening met EPSILON = 1e-07 om de verdeling veilig te stellen.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Other episodes