元のページ

ステージ3-5: 類似度や距離の例 (情報工学実験 3 : データマイニング班)

目次

想定環境

数学的な「距離(空間)」と「類似度(空間)」に必要な要件

数学的な「距離(空間)」の定義 数学的な「類似度(空間)」の定義

cosine類似度による特徴ベクトルの類似度

#cosine類似度
def cosine_similarity(vec1, vec2):
    u'''コサイン類似度。
    vec1, vec2 は同次元の特徴ベクトル(リスト型)。
    文章の類似度を測るために使われる指標の一つ。
    vec1とvec2が似ているほど+1に近い値、似ていないほど-1に近い値を返す。
    vec1, vec2のなす角度θに対するcosθを求めるため、以下のような値を返す。
        ・ベクトルの向きが一致している時に最大値1。
        ・直行している時に0。
        ・向きが真逆の時に-1。
    >>> len(vec1) == len(vec2)
    True
    '''
    import math
    numerator = sum([vec1[x]*vec2[x] for x in range(len(vec1))])
    
    sum1 = sum([vec1[x]**2 for x in range(len(vec1))])
    sum2 = sum([vec2[x]**2 for x in range(len(vec2))])
    denominator = math.sqrt(sum1) * math.sqrt(sum2)
    
    if not denominator:
        return 0.0
    else:
        return float(numerator) / denominator

cosine_similarity([1,1,1], [1,1,1]) #同一なので1.0
cosine_similarity([1,1,1], [2,2,2]) #向きは同一なので1.0
cosine_similarity([1,1,1], [0,1,1]) #ほぼ同じ向きなので+1に近い値
cosine_similarity([1,1,1], [0,0,1]) #大分向きが異なるが反対方向ではないためまだ正の値
cosine_similarity([1,1,1], [0,0,0]) #直行しているため0.0
cosine_similarity([1,1,1], [0,0,-1]) #向きが逆方向になったため負の値
cosine_similarity([1,1,1], [0,-1,-1]) #更に向きが逆方向に向いたため-1に近い負の値
cosine_similarity([1,1,1], [-1,-1,-1]) #向きが真逆なので-1.0

#以下で使用している scipy.spatial.distance.pdist() でもコサイン類似度に似た指標
#を算出できるが、pdist('cosine')は「コサイン距離」を求めている点に注意。




ユークリッド距離と標準ユークリッド距離

#ユークリッド距離
import scipy.spatial.distance as dist

# 以下では2ベクトル間の距離を求めるやり方を例示していますが、
# 第1引数にm個の行列を列挙し、まとめて「組み合わせ全ての距離」を求めることができます。

dist.pdist([[1,1,1], [1,1,1]], 'euclidean') #同一なので0.0
dist.pdist([[1,1,1], [1,1,1]]) #同一なので0.0
dist.pdist([[1,1,1], [2,2,2]]) #向きは同じだが大きさが異なるので正の値
dist.pdist([[1,1,1], [0,0,0]]) #上記と同じ距離にあるため同じ値を返す

dist.pdist([[1,1,1], [0,1,1]]) #距離的に近いのでより小さな正の値
dist.pdist([[1,1,1], [0,0,1]]) #上記より少し離れたのでやや大きな正の値
dist.pdist([[1,1,1], [0,0,-1]]) #更に離れた正の値
dist.pdist([[1,1,1], [0,-1,-1]]) #更に離れた正の値
dist.pdist([[1,1,1], [-1,-1,-1]]) #更に離れた正の値

dist.pdist([[1,1,1], [1,1,1000]]) #一部の属性に引きずられた値


#標準ユークリッド距離
# 一部の素性が他と比べて非常に大きいとき、その一部の素性に引きずられた距離となるのを防ぐため、
# ユークリッド距離を分散でならした(割った)値を求める。
# *デフォルトではベクトル間の分散を求めて割るため、
#  同一値となる素性が1カ所でもあると NaN (不定) になってしまう。
dist.pdist([[1,1,1], [1,1,1]], 'seuclidean') #同一だらけで NaN
dist.pdist([[1,1,1], [0,0,1]], 'seuclidean') #3番目の素性が同一のためNaN
dist.pdist([[1,1,1], [2,2,2]], 'seuclidean') #ただのユークリッド距離よりも大きな値を返す。
dist.pdist([[1,1,1], [-1,-1,-1]], 'seuclidean') #ユークリッド距離的には上記より離れているはずだが、同一距離となる。
dist.pdist([[1,1,1], [0,0,1000]], 'seuclidean') #ユークリッド距離的にかなり離れているが、同一距離。





参考サイト一覧