2012-11-28 29 views
2

我有很多字典包含我音樂庫中每位藝術家的加權標籤,我希望找到更相似的藝術家(也許具有相似性等級?),給定一個加權標籤字典。尋找更具有類似產品信息加權數據

例如:

tags = { 
    'grails': { 
     'post-rock': 100, 
     'instrumental': 53, 
     'experimental': 38, 
     'ambient': 30, 
     'post rock': 14, 
     'psychedelic': 11, 
     'Psychedelic Rock': 6, 
     'Progressive rock': 6, 
     'rock': 4, 
     'instrumental rock': 3, 
     'atmospheric': 3, 
     'american': 3, 
     'space rock': 1 
    }, 
    'camel': { 
     'Progressive rock': 100, 
     'classic rock': 28, 
     'art rock': 24, 
     'Progressive': 18, 
     'rock': 17, 
     'symphonic prog': 7, 
     'british': 6, 
     'Symphonic Rock': 4, 
     'Canterbury Scene': 3, 
     'prog rock': 3, 
     'prog': 3, 
     'Psychedelic Rock': 2, 
     'space rock': 1 
    }, 
    'mozart': { 
     'Classical': 100, 
     'mozart': 30, 
     'instrumental': 21, 
     'composers': 16, 
     'opera': 13, 
     'piano': 11, 
     'Wolfgang Amadeus Mozart': 9, 
     'symphonic': 9, 
     'orchestral': 8, 
     'austrian': 5 
    } 
    # etc. 
} 


best_matches({ 
      'Progressive rock': 100, 
      'experimental': 33, 
      'classic rock': 26, 
      'Progressive': 23, 
      'rock': 23, 
      'art rock': 12, 
      'psychedelic': 5, 
      'prog rock': 5, 
      'british': 5, 
      'prog': 4, 
      'Experimental Rock': 3, 
      'Avant-Garde': 3, 
      'Psychedelic Rock': 3, 
      'Jazz Rock': 2 
     }, tags) 

# should output camel, then grails, then mozart 

我聽說了一些推薦算法如坡度之一,但我不知道是否有更簡單的方法做這種與Python計算,並且這將是最快的算法「比較」所有這些字典。

+0

你是什麼意思的 「重量」 嗎? –

+0

每個標記的權重是字典的第二個值。例如,如果它的值爲100或較大,則意味着該標籤完美地描述了藝術家,並且在比較過程中應該被認爲比其他人更重要。對不起,我不知道我是否清楚自己。 – Nicolas

+0

你的藝術家並不都具有相同的標籤。您需要考慮如何處理缺失的標籤:是否與權重爲0或其他固定值的標籤相同,或者常用標籤的數量是否對計算出的相似性有一定的正面影響? –

回答

1

如果將每種音樂類型視爲向量空間中的維度,則可以嘗試cosine similarity或歐幾里德距離。餘弦相似性是特別容易,它只是L2標準化積:

def intersect(a, b): 
    """Intersection of a and b.""" 
    return (k for k in a if k in b) 

def dot(a, b): 
    """Dot product of values in a and b.""" 
    return sum((a[k] * b[k]) for k in intersect(a, b)) 

def l2norm(a): 
    """L2 norm, aka Euclidean length, of a regarded as a vector.""" 
    return sqrt(sum(v ** 2 for v in a.itervalues())) 

def similarity(a, b): 
    """Cosine similarity of a and b.""" 
    return dot(a, b)/(l2norm(a) * l2norm(b)) 

如果所有的權重/分值都是非負的,這將返回零和一之間的數字與一個意義的完美匹配。您可以在任何有關信息檢索的教科書中閱讀關於餘弦相似性的更多信息,例如Manning, Raghavan and Schütze

+0

謝謝,這真的很有趣! – Nicolas

1

您應該將每個標記視爲向量空間中的一個維度,並應用cosine similarity

例如:

import numpy as np 

def cosine_similarity(dict1, dict2): 
    sim = float(sum([dict1[k] * dict2[k] for k in intersect(dict1,dict2)])) 
    return sim/(norm_values(dict1) * norm_values(dict2)) 

def norm_values(dict): 
    v = np.array(dict.values()) 
    return np.sqrt(np.sum(np.square(v))) 

def intersect(dict1,dict2): 
    return list(set(dict1.keys()) & set(dict2.keys())) 

tags = { 
    'grails': { 
     'post-rock': 100, 
     'instrumental': 53, 
     'experimental': 38, 
     'ambient': 30, 
     'post rock': 14, 
     'psychedelic': 11, 
     'Psychedelic Rock': 6, 
     'Progressive rock': 6, 
     'rock': 4, 
     'instrumental rock': 3, 
     'atmospheric': 3, 
     'american': 3, 
     'space rock': 1 
    }, 
    'camel': { 
     'Progressive rock': 100, 
     'classic rock': 28, 
     'art rock': 24, 
     'Progressive': 18, 
     'rock': 17, 
     'symphonic prog': 7, 
     'british': 6, 
     'Symphonic Rock': 4, 
     'Canterbury Scene': 3, 
     'prog rock': 3, 
     'prog': 3, 
     'Psychedelic Rock': 2, 
     'space rock': 1 
    }, 
    'mozart': { 
     'Classical': 100, 
     'mozart': 30, 
     'instrumental': 21, 
     'composers': 16, 
     'opera': 13, 
     'piano': 11, 
     'Wolfgang Amadeus Mozart': 9, 
     'symphonic': 9, 
     'orchestral': 8, 
     'austrian': 5 
    } 
} 
query = { 
    'Progressive rock': 100, 
    'experimental': 33, 
    'classic rock': 26, 
    'Progressive': 23, 
    'rock': 23, 
    'art rock': 12, 
    'psychedelic': 5, 
    'prog rock': 5, 
    'british': 5, 
    'prog': 4, 
    'Experimental Rock': 3, 
    'Avant-Garde': 3, 
    'Psychedelic Rock': 3, 
    'Jazz Rock': 2 
} 

for t in tags: 
    print "{}: {}".format(t, cosine_similarity(tags[t], query)) 

這將產生:

mozart: 0.0 
grails: 0.141356488829 
camel: 0.944080602442 
+0

謝謝,它效果很好! – Nicolas