2 নম্বর তালিকার মধ্যে কোসিন সাদৃশ্য


119

আমাকে দুটি তালিকার মধ্যে কোসাইন মিল খুঁজে বের করতে হবে , উদাহরণস্বরূপ তালিকার 1 যা এবং তালিকা 2 যা তা বলা যাক । আমি নিম্পি বা একটি পরিসংখ্যান মডিউল এর মতো কিছু ব্যবহার করতে পারি না । সময় ব্যয় কমাতে আমার অবশ্যই সাধারণ মডিউল (গণিত ইত্যাদি) ব্যবহার করতে হবে (এবং যতটা সম্ভব কমপক্ষে মডিউল)।dataSetIdataSetII

আসুন বলে dataSetIহয় [3, 45, 7, 2]এবং dataSetIIহয় [2, 54, 13, 15]। তালিকাগুলির দৈর্ঘ্য সর্বদা সমান।

অবশ্যই, কোসাইন মিলটি 0 থেকে 1 এর মধ্যে এবং এর স্বার্থে এটি তৃতীয় বা চতুর্থ দশমিক সহ গোল হবে format(round(cosine, 3))

সাহায্য করার জন্য আপনাকে আগাম অনেক ধন্যবাদ।


29
এটিকে একটি সাধারণ সাধারণ রেফারেন্স হিসাবে তৈরি করার জন্য এই হোমওয়ার্ক প্রশ্ন থেকে SO আত্মাকে যেভাবে পিষ্ট করেছে তা আমি পছন্দ করি। ওপি বলে, " আমি আপা ব্যবহার করতে পারি না , আমাকে অবশ্যই পথচারীদের গণিতের পথে যেতে হবে", এবং উপরের উত্তরটি "আপনার অনর্থক চেষ্টা করা উচিত, এটি আঙ্গুল ব্যবহার করে"। এসও মেকানিক্স জনপ্রিয় প্রশ্নের একটি সোনার ব্যাজ দেয়।
নিকানা রেকলাভিকস

1
নিকানা রেকলাভিক্স, এটি একটি দুর্দান্ত বিষয়। স্ট্যাকওভারফ্লোতে আমার আরও প্রায়ই সমস্যা ছিল। এবং আমার বেশ কয়েকটি পূর্ববর্তী প্রশ্নের "সদৃশ" হিসাবে চিহ্নিত বেশ কয়েকটি প্রশ্ন ছিল কারণ মডারেটররা আমার প্রশ্নটি কী অনন্য করেছে তা বুঝতে সময় নেননি take
এলআরকে

@ নিকানা রেকলাভিক্স, এটি দুর্দান্ত। তার প্রোফাইল দেখুন, এটি এসও এর শীর্ষস্থানীয়দের মধ্যে একজনের গল্প বলে .01% অবদানকারী, আপনি জানেন?
নাথান চ্যাপেল

উত্তর:


174

আপনার সাইকপাই চেষ্টা করা উচিত । উদাহরণস্বরূপ এটির একাধিক দরকারী বৈজ্ঞানিক রুটিন রয়েছে, "সংখ্যার সাথে সংখ্যার গণনা করার জন্য রুটিনগুলি, ডিফারেনশিয়াল সমীকরণ, অপ্টিমাইজেশন এবং স্পার্স ম্যাট্রিকেস সমাধান করা।" এটি তার নম্বর ক্রাঞ্চিংয়ের জন্য সুপারফাস্ট অনুকূলিত NumPy ব্যবহার করে। ইনস্টল করার জন্য এখানে দেখুন ।

নোট spatial.distance.cosine নির্ণয় যে দূরত্ব , এবং সাদৃশ্য। সুতরাং, আপনি পেতে 1 থেকে মান বিয়োগ আবশ্যক আদল

from scipy import spatial

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

122

numpyশুধুমাত্র উপর ভিত্তি করে অন্য সংস্করণ

from numpy import dot
from numpy.linalg import norm

cos_sim = dot(a, b)/(norm(a)*norm(b))

3
সংজ্ঞা হিসাবে খুব পরিষ্কার, তবে np.inner(a, b) / (norm(a) * norm(b))বুঝতে আরও ভাল হয়। ভেক্টর dotহিসাবে একই ফলাফল পেতে পারেন inner
বেলটার

15
FYI এই সমাধানটি ব্যবহারের চেয়ে আমার সিস্টেমে উল্লেখযোগ্যভাবে দ্রুত scipy.spatial.distance.cosine
ওজাহ

দ্বারা সংজ্ঞা কোসাইন আদল রেঞ্জ @ZhengfangXin থেকে -1 1
dontloo

2
এমনকি সংক্ষিপ্ত:cos_sim = (a @ b.T) / (norm(a)*norm(b))
পরিসংখ্যান

এটি এখন পর্যন্ত অন্যদের তুলনায় দ্রুততম পদ্ধতির।
জেসন ইউ

73

আপনি cosine_similarityফাংশন ফর্ম ডক্স ব্যবহার করতে পারেনsklearn.metrics.pairwise

In [23]: from sklearn.metrics.pairwise import cosine_similarity

In [24]: cosine_similarity([[1, 0, -1]], [[-1,-1, 0]])
Out[24]: array([[-0.5]])

21
কেবলমাত্র একটি অনুস্মারক যে ইনপুট ডেটা হিসাবে এক মাত্রার অ্যারেগুলি পাস করা স্কেলের্ন সংস্করণ ০.০ dep এ অবমূল্যায়ন করা হয়েছে এবং এটি 0.19-এ মান বাড়িয়ে তুলবে।
চং টাং

4
এই অবমূল্যায়নের সতর্কতা দিয়ে স্কেলের্ন দিয়ে এটি করার সঠিক উপায় কী?
এলিয়ট

2
@ এলিয়ট ওয়ান_ডিমেনশন_আররে.রেহাপ (-1,1)
bobo32

2
@ বোবো 32 কোসাইন_সাম্যতা (এনপি.আররে ([1, 0, -1])। পুনঃ আকার (-1,0), এনপি.আররে ([- 1, -1, 0])। পুনঃ আকার (-1,0)) তুমি বোঝাতে চাও? কিন্তু ফলাফলটি কী বোঝায় যে এটি ফিরে আসে? এটি একটি নতুন 2 ডি অ্যারে, কোসাইন মিল নয়।
ইসবিস্টার

10
এটি আরও একটি বন্ধনী দিয়ে বন্ধ করুনcosine_similarity([[1, 0, -1]], [[-1,-1, 0]])
আয়ুষ

34

আমি মনে করি না এখানে পারফরম্যান্সের বিষয়টি খুব বেশি, তবে আমি প্রতিরোধ করতে পারি না। জিপ () ফাংশনটি কেবলমাত্র "পাইথোনিক" ক্রমে ডেটা পাওয়ার জন্য উভয় ভেক্টরকে (একটি ম্যাট্রিক্স ট্রান্সপোজের বেশি, আসলে) সম্পূর্ণরূপে পুনরায় সংগ্রহ করে। বাদাম এবং বোল্ট বাস্তবায়নের সময়টি আকর্ষণীয় হবে:

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

এটি একসাথে এক সময় উপাদানগুলি বের করার সি-জাতীয় শব্দের মধ্য দিয়ে যায়, তবে কোনও বাল্ক অ্যারে অনুলিপি করে না এবং লুপের জন্য একক মধ্যে গুরুত্বপূর্ণ সমস্ত কাজ করে এবং একক বর্গমূল ব্যবহার করে।

ইটিএ: একটি ফাংশন হতে আপডেট হওয়া মুদ্রণ কল। (মূলটি পাইথন ২.7 ছিল, ৩.৩ নয়। বর্তমানটি পাইথন ২.7 এর অধীনে একটি from __future__ import print_functionবিবৃতি দিয়ে চালিত হয় ।) আউটপুট উভয় দিক থেকেই একই রকম।

সিপিওয়াইথন ২.7.৩ এ 3.0GHz কোর 2 জুটি

>>> 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

সুতরাং, অযৌক্তিক উপায়টি এই ক্ষেত্রে প্রায় 3.6 গুণ বেশি দ্রুত।


2
কি cosine_measureএই ক্ষেত্রে?
মেরোস

1
@ মেরোজ: cosine_measureএবং cosine_similarityকেবল একই গণনার বিভিন্ন বাস্তবায়ন। উভয় ইনপুট অ্যারেগুলিকে "ইউনিট ভেক্টরগুলিতে" স্কেল করার এবং বিন্দুর পণ্য গ্রহণের সমতুল্য।
মাইক হাউস্কি

3
আমি একই অনুমান করতে হবে। তবে এটি সহায়ক নয়। আপনি সময়ের সাথে দুটি অ্যালগরিদমের তুলনা উপস্থাপন করেছেন তবে তাদের মধ্যে একটি মাত্র উপস্থাপন করুন।
মেরোস

ওহ, দুঃখিত। cosine_measureএর আগে পাকাক্রিপজাক পোস্ট করা কোড। এই কোডটি "অন্যান্য" সমস্ত-মানক-পাইথন সমাধানের বিকল্প ছিল।
মাইক হাউস্কি

আপনাকে ধন্যবাদ, এটি দুর্দান্ত যেহেতু এটি কোনও লাইব্রেরি ব্যবহার করছে না এবং এটির পিছনে গণিতটি বোঝা স্পষ্ট
গ্রেপিট

18

কোন আমদানি ব্যবহার না করে

math.sqrt (x) এর

সঙ্গে প্রতিস্থাপন করা যেতে পারে

x ** .5

numpy.dot () ব্যবহার না করে আপনাকে তালিকা বোধগম্যতা ব্যবহার করে নিজের ডট ফাংশন তৈরি করতে হবে:

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

এবং তারপরে কোসাইন মিলের সূত্রটি প্রয়োগ করার এটি কেবল একটি সহজ বিষয়:

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

15

আমি প্রশ্নের বেশ কয়েকটি উত্তরের উপর ভিত্তি করে একটি মানদণ্ড করেছি এবং নিম্নলিখিত স্নিপেটকে সেরা পছন্দ বলে মনে করা হচ্ছে:

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)

ফলাফলটি আমাকে অবাক করে দেয় যে এর উপর ভিত্তি করে বাস্তবায়নটি scipyদ্রুততম নয়। আমি প্রোফাইল পেয়েছি এবং দেখতে পেয়েছি যে স্কিপিতে থাকা কোসাইন অজগর তালিকার থেকে ভ্যাক্টরটিকে ন্যম্পি অ্যারেতে কাস্ট করতে অনেক সময় নেয়।

এখানে চিত্র বর্ণনা লিখুন


আপনি এতটা নিশ্চিত যে এটি দ্রুততম?
জেরু লুক

: @JeruLuke আমি উত্তর খুব প্রারম্ভে আমার বেঞ্চমার্ক ফলাফলের লিংক আটকানো থাকেন gist.github.com/mckelvin/...
McKelvin

10
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)

আপনি এটি গণনার পরে গোল করতে পারেন:

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

আপনি যদি এটি সত্যিই সংক্ষিপ্ত চান, আপনি এই ওয়ান-লাইনারটি ব্যবহার করতে পারেন:

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)))

আমি এই কোডটি চেষ্টা করে দেখেছি বলে মনে হচ্ছে না। আমি v1 সত্তা [2,3,2,5], এবং v2 সত্তা দিয়ে চেষ্টা করেছি [3,2,2,0]। এটি 1.0এমনভাবে ফিরে আসে যেন তারা ঠিক একই রকম ছিল। কোন ধারণা কি ভুল?
রব আলসোদ

ফিক্স এখানে কাজ করে। চমৎকার কাজ! একটি কুরুচিপূর্ণ তবে দ্রুত পদ্ধতির জন্য নীচে দেখুন।
মাইক হাউস্কি

এই কোডটি কীভাবে অভিযোজিত করা সম্ভব হয় যদি দুটি ভেক্টরের জন্য নয় বরং ম্যাট্রিক্সের মধ্যে মিল খুঁজে বের করতে হয়? আমি ভেবেছিলাম আমি দ্বিতীয় ভেক্টরের পরিবর্তে একটি ম্যাট্রিক্স এবং ট্রান্সপোজড ম্যাট্রিক্স নিয়েছি, কিছুটা এটি কাজ করে বলে মনে হচ্ছে না।
ছাত্র

আপনি এটিকে আরও সহজ করতে এনপি.ডট (এক্স, ওয়াইটি) ব্যবহার করতে পারেন
ব্যবহারকারীর702846

3

আপনি সাধারণ ফাংশন ব্যবহার করে পাইথনে এটি করতে পারেন:

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)

3
এটি কোসাইনের একটি পাঠ্য বাস্তবায়ন। এটি সংখ্যার ইনপুট জন্য ভুল আউটপুট দেবে।
আলভাস

আপনি কেন "ছেদ = = সেট (vec1.keys ()) এবং সেট (vec2.keys ())" রেখায় সেট ব্যবহার করেছেন তা ব্যাখ্যা করতে পারেন।
ঘোস 3

এছাড়াও আপনার ফাংশনটি মানচিত্রের প্রত্যাশা করে বলে মনে হচ্ছে তবে আপনি এটি পূর্ণসংখ্যার তালিকা প্রেরণ করছেন।
ঘোস 3

3

নম্পি ব্যবহার করে একাধিক তালিকার (ম্যাট্রিক্স) সাথে সংখ্যার একটি তালিকার তুলনা করুন:

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]

1

কোসাইন মিলের জন্য গণনা করতে আপনি এই সাধারণ ফাংশনটি ব্যবহার করতে পারেন:

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])))

1
চাকা পুনরুদ্ধার কেন?
জেরু লুক

@ জেরুলুক সম্ভবত "একা দাঁড়িয়ে" উত্তর দিতে পারেন যার অতিরিক্ত আমদানির প্রয়োজন নেই (এবং সম্ভবত তালিকা থেকে নামিপ্রেতে রূপান্তর করতে হবে বা এরকম কিছু হতে পারে)
মার্কো অটিনা

1

আপনি যদি ইতিমধ্যে পাইটর্চ ব্যবহার করে থাকেন তবে আপনার কসিনসিমারিটি বাস্তবায়নের সাথে আপনার উচিত

ধরুন আপনার কাছে দ্বি- nমাত্রিক numpy.ndarrayগুলি রয়েছে v1এবং v2অর্থাত্ তাদের আকারগুলি উভয়ই (n,)। এখানে আপনি কীভাবে তাদের কোসাইন মিল খুঁজে পাবেন:

import torch
import torch.nn as nn

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

অথবা ধরুন আপনার দুটি numpy.ndarrayগুলি রয়েছে w1এবং w2যার আকার উভয়ই (m, n)। নিম্নলিখিতটি আপনাকে কোসাইন সাদৃশ্যগুলির একটি তালিকা পেয়েছে, প্রত্যেকটি এতে একটি সারি w1এবং এর সাথে সম্পর্কিত সারির মধ্যে কোসাইন মিল রয়েছে w2:

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

-1

সমস্ত উত্তরগুলি এমন পরিস্থিতিতে জন্য দুর্দান্ত যেখানে আপনি নম্পপি ব্যবহার করতে পারবেন না। যদি আপনি পারেন তবে এখানে অন্য পদ্ধতি:

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)

EPSILON = 1e-07বিভাগটি সুরক্ষিত করার বিষয়েও মনে রাখবেন ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.