Python相似度计算【大总结】

0、标签匹配、加权求和

示例1:每一位的算法及权重都相同

import numpy as np
a = np.array([1, 1, 1, 0, 0])
b = np.array([0, 1, 1, 1, 0])
weights = np.array(range(1, 6))
# 与运算
c = a & b
print(c, np.average(c), np.average(c, weights=weights))
# 异同
c = a == b
print(c, np.average(c), np.average(c, weights=weights))

示例2:每一位的有各自的算法及权重

a = ['a', 'b', 125, 400, 0, 1, 'e', 'f']
b = ['c', 'b', 150, 100, 1, 1, {'d', 'e'}, {'g', 'h'}]
weights = [.2, .2, .1, .1, .1, .1, .1, .1]
scores = []
for i in range(8):
    if i in (0, 1):
        equality = 1 if a[i] == b[i] else -1  # 比较异同
        scores.append(weights[i] * equality)
    elif i in (2, 3):
        difference = 1-abs(a[i]-b[i])/(a[i]+b[i])  # 差异百分比
        scores.append(weights[i] * difference)
    elif i in (4, 5):
        and_operation = (a[i] * b[i])  # 与运算
        scores.append(weights[i] * and_operation)
    elif i in (6, 7):
        include = 1 if a[i] in b[i] else 0  # 包含关系
        scores.append(weights[i] * include)
print(scores, sum(scores))  # [-0.2, 0.2, 0.09, 0.04, 0.0, 0.1, 0.1, 0.0] 0.33

1、集合运算

S i m i l a r i t y = A ∩ B A ∪ B Similarity = \frac{A \cap B}{A \cup B} Similarity=ABAB

def similarity(a, b):
    try:
        return len(a & b) / len(a | b)
    except ZeroDivisionError:
        return -1e-4

m = set('abcd')
n = set('bcde')
print(similarity(m, n))  # 0.6

2、编辑距离

动态规划矩阵

import numpy as np, pandas as pd

def edit_distance(w1, w2):
    l1, l2 = len(w1) + 1, len(w2) + 1
    matrix = np.zeros(shape=(l1, l2), dtype=np.int8)

    for i in range(l1):
        matrix[i][0] = i
    for j in range(l2):
        matrix[0][j] = j

    for i in range(1, l1):
        for j in range(1, l2):
            delta = 0 if w1[i - 1] == w2[j - 1] else 1
            matrix[i][j] = min(matrix[i - 1][j - 1] + delta,
                               matrix[i - 1][j] + 1,
                               matrix[i][j - 1] + 1)

    print(pd.DataFrame(
        matrix, index=[''] + list(w1), columns=[''] + list(w2)))

    return matrix[-1][-1]

ed = edit_distance('abc', 'abbcc')
print('edit_distance:', ed)


编辑距离百分比

def edit_distance(w1, w2):
    l1, l2 = len(w1) + 1, len(w2) + 1
    matrix = [[0 for j in range(l2)] for i in range(l1)]
    for i in range(l1):
        matrix[i][0] = i
    for j in range(l2):
        matrix[0][j] = j
    for i in range(1, l1):
        for j in range(1, l2):
            delta = 0 if w1[i - 1] == w2[j - 1] else 1
            matrix[i][j] = min(matrix[i - 1][j - 1] + delta,
                               matrix[i - 1][j] + 1,
                               matrix[i][j - 1] + 1)
    return matrix[-1][-1] / (l1 / 2 + l2 / 2 - 1)

poem1 = '''《将进酒》——李白
君不见黄河之水天上来,奔流到海不复回。君不见高堂明镜悲白发,朝如青丝暮成雪。
人生得意须尽欢,莫使金樽空对月。天生我材必有用,千金散尽还复来。
烹羊宰牛且为乐,会须一饮三百杯。岑夫子,丹丘生,将进酒,杯莫停。与君歌一曲,请君为我倾耳听。
钟鼓馔玉不足贵,但愿长醉不复醒。古来圣贤皆寂寞,惟有饮者留其名。
陈王昔时宴平乐,斗酒十千恣欢谑。主人何为言少钱,径须沽取对君酌。
五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。'''.replace('\n', '')
poem2 = '''《惜樽空》——李白
君不见黄河之水天上来,奔流到海不复回。君不见床头明镜悲白发,朝如青云暮成雪。
人生得意须尽欢,莫使金樽空对月。天生吾徒有俊才,千金散尽还复来。
烹羊宰牛且为乐,会须一饮三百杯。岑夫子,丹丘生,与君哥一曲,请君为我倾。
钟鼓玉帛岂足贵,但用长醉不复醒。古来贤圣皆死尽,惟有饮者留其名。
陈王昔时宴平乐,斗酒十千恣欢谑。主人何为言少钱,径须沽取对君酌。
五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。'''.replace('\n', '')
print(edit_distance(poem1, poem2))  # 0.15158924205378974

允许字符转置

from nltk import edit_distance
a, b = 'abcd', 'abdc'
print(edit_distance(a, b), edit_distance(a, b, transpositions=True))  # 2 1

3、欧式距离和余弦距离

from sklearn.metrics.pairwise import euclidean_distances, cosine_distances
vectors = [[0, 1], [1, 1], [1, 0]]  # 3个项链
print(euclidean_distances(vectors))  # 欧氏距离
print(cosine_distances(vectors))  # 余弦距离

如图输出2个矩阵,分别计算3个向量的每两个向量之间的距离

4、余弦相似度

from sklearn.metrics.pairwise import cosine_similarity

5、TF-IDF文本相似度

点击此处查看TF-IDF文本相似度计算详细解析

"""
《长恨歌》——白居易
汉皇重色思倾国,御宇多年求不得。
杨家有女初长成,养在深闺人未识。
天生丽质难自弃,一朝选在君王侧。
回眸一笑百媚生,六宫粉黛无颜色。
春寒赐浴华清池,温泉水滑洗凝脂。
侍儿扶起娇无力,始是新承恩泽时。
云鬓花颜金步摇,芙蓉帐暖度春宵。
春宵苦短日高起,从此君王不早朝。
承欢侍宴无闲暇,春从春游夜专夜。
后宫佳丽三千人,三千宠爱在一身。
金屋妆成娇侍夜,玉楼宴罢醉和春。
姊妹弟兄皆列土,可怜光彩生门户。
遂令天下父母心,不重生男重生女。
骊宫高处入青云,仙乐风飘处处闻。
缓歌慢舞凝丝竹,尽日君王看不足。
渔阳鼙鼓动地来,惊破霓裳羽衣曲。
九重城阙烟尘生,千乘万骑西南行。
翠华摇摇行复止,西出都门百余里。
六军不发无奈何,宛转蛾眉马前死。
花钿委地无人收,翠翘金雀玉搔头。
君王掩面救不得,回看血泪相和流。
黄埃散漫风萧索,云栈萦纡登剑阁。
峨嵋山下少人行,旌旗无光日色薄。
蜀江水碧蜀山青,圣主朝朝暮暮情。
行宫见月伤心色,夜雨闻铃肠断声。
天旋地转回龙驭,到此踌躇不能去。
马嵬坡下泥土中,不见玉颜空死处。
君臣相顾尽沾衣,东望都门信马归。
归来池苑皆依旧,太液芙蓉未央柳。
芙蓉如面柳如眉,对此如何不泪垂。
春风桃李花开日,秋雨梧桐叶落时。
西宫南内多秋草,落叶满阶红不扫。
梨园弟子白发新,椒房阿监青娥老。
夕殿萤飞思悄然,孤灯挑尽未成眠。
迟迟钟鼓初长夜,耿耿星河欲曙天。
鸳鸯瓦冷霜华重,翡翠衾寒谁与共。
悠悠生死别经年,魂魄不曾来入梦。
临邛道士鸿都客,能以精诚致魂魄。
为感君王辗转思,遂教方士殷勤觅。
排空驭气奔如电,升天入地求之遍。
上穷碧落下黄泉,两处茫茫皆不见。
忽闻海上有仙山,山在虚无缥渺间。
楼阁玲珑五云起,其中绰约多仙子。
中有一人字太真,雪肤花貌参差是。
金阙西厢叩玉扃,转教小玉报双成。
闻道汉家天子使,九华帐里梦魂惊。
揽衣推枕起徘徊,珠箔银屏迤逦开。
云鬓半偏新睡觉,花冠不整下堂来。
风吹仙袂飘飖举,犹似霓裳羽衣舞。
玉容寂寞泪阑干,梨花一枝春带雨。
含情凝睇谢君王,一别音容两渺茫。
昭阳殿里恩爱绝,蓬莱宫中日月长。
回头下望人寰处,不见长安见尘雾。
惟将旧物表深情,钿合金钗寄将去。
钗留一股合一扇,钗擘黄金合分钿。
但教心似金钿坚,天上人间会相见。
临别殷勤重寄词,词中有誓两心知。
七月七日长生殿,夜半无人私语时。
在天愿作比翼鸟,在地愿为连理枝。
天长地久有时尽,此恨绵绵无绝期。
"""
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from numpy import argsort

"""读数据"""
seqs = __doc__.replace('《长恨歌》——白居易', '').replace('。', '').strip().split()
q_ls = [i.split(',')[0] for i in seqs]
a_ls = [i.split(',')[1] for i in seqs]

"""训练tfidf向量转换器"""
vectorizer = TfidfVectorizer(token_pattern='[\u4e00-\u9fa5]')
X = vectorizer.fit_transform(q_ls)

def ask(q, n=3):
    q = vectorizer.transform([q])  # tfidf向量化
    indexs = cosine_similarity(X, q).reshape(-1)  # 余弦相似度
    indexs = argsort(-indexs)  # 按索引倒排
    return [a_ls[i] for i in indexs[:n]]

"""测试"""
for q, a in zip(q_ls, a_ls):
    print(q, a)
    for e, i in enumerate(ask(q)):
        print(e, i)
    print('-' * 50)

while True:
    q = input('输入:').strip()
    for e, i in enumerate(ask(q)):
        print(e, i)

示例图的逻辑是:输入前一句,然后计算最接近的那几句,最终输出下一句

6、基于词向量的余弦相似度

from gensim.models import Word2Vec
model = Word2Vec(ls_of_words)  # ls_of_words是存放分词列表的列表
w2i = {w: i for i, w in enumerate(model.wv.index2word, 1)}
vectors = np.concatenate((np.zeros((1, 100)), model.wv.vectors), axis=0)
w2v = lambda w: vectors[w2i.get(w, 0)]

vec1 = np.mean([w2v(w) for w in poem1], axis=0)
vec2 = np.mean([w2v(w) for w in poem2], axis=0

print(vec1 @ vec2 / (np.linalg.norm(vec1) * np.linalg.norm(vec2)))

7、最长公共子串

Longest Common Substring

import numpy as np

def lcs(s1, s2):
    l1, l2 = len(s1), len(s2)
    matrix = np.zeros((l1 + 1, l2 + 1), dtype=int)
    max_len = 0  # 最长匹配的长度
    p = 0  # 最长匹配对应在s1中的最后一位
    for i in range(len(s1)):
        for j in range(len(s2)):
            if s1[i] == s2[j]:
                matrix[i + 1, j+1] = matrix[i, j] + 1
                max_len, p = max([(max_len, p), (matrix[i + 1, j + 1], i + 1)])
    return s1[p - max_len: p]  # 返回最长子串及其长度

poem1 = '''《将进酒》——李白
君不见黄河之水天上来,奔流到海不复回。君不见高堂明镜悲白发,朝如青丝暮成雪。
人生得意须尽欢,莫使金樽空对月。天生我材必有用,千金散尽还复来。
烹羊宰牛且为乐,会须一饮三百杯。岑夫子,丹丘生,将进酒,杯莫停。与君歌一曲,请君为我倾耳听。
钟鼓馔玉不足贵,但愿长醉不复醒。古来圣贤皆寂寞,惟有饮者留其名。
陈王昔时宴平乐,斗酒十千恣欢谑。主人何为言少钱,径须沽取对君酌。
五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。'''.replace('\n', '')
poem2 = '''《惜樽空》——李白
君不见黄河之水天上来,奔流到海不复回。君不见床头明镜悲白发,朝如青云暮成雪。
人生得意须尽欢,莫使金樽空对月。天生吾徒有俊才,千金散尽还复来。
烹羊宰牛且为乐,会须一饮三百杯。岑夫子,丹丘生,与君哥一曲,请君为我倾。
钟鼓玉帛岂足贵,但用长醉不复醒。古来贤圣皆死尽,惟有饮者留其名。
陈王昔时宴平乐,斗酒十千恣欢谑。主人何为言少钱,径须沽取对君酌。
五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。'''.replace('\n', '')
print(lcs(poem1, poem2))

,惟有饮者留其名。陈王昔时宴平乐,斗酒十千恣欢谑。主人何为言少钱,径须沽取对君酌。五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。

8、最长公共子序列

The longest common subsequence

import numpy as np

def lcs(s1, s2):
    l1, l2 = len(s1), len(s2)
    # 生成字符串长度+1的零矩阵,保存对应位置匹配的结果
    m = np.zeros((l1 + 1, l2 + 1))
    # 记录转移方向
    d = np.empty_like(m, dtype=str)
    for i in range(l1):
        for j in range(l2):
            # 字符匹配成功,则该位置的值为左上方的值加1
            if s1[i] == s2[j]:
                m[i + 1, j + 1] = m[i, j] + 1
                d[i + 1, j + 1] = 'O'
            # 左值大于上值,则该位置的值为左值,并标记回溯时的方向
            elif m[i + 1, j] > m[i, j + 1]:
                m[i + 1, j + 1] = m[i + 1, j]
                d[i + 1, j + 1] = '←'
            # 上值大于左值,则该位置的值为上值,并标记方向↑
            else:
                m[i + 1, j + 1] = m[i, j + 1]
                d[i + 1, j + 1] = '↑'
    s = []
    while m[l1, l2]:  # 不为空时
        c = d[l1, l2]
        if c == 'O':  # 匹配成功,插入该字符,并向左上角找下一个
            s.append(s1[l1 - 1])
            l1 -= 1
            l2 -= 1
        if c == '←':  # 根据标记,向左找下一个
            l2 -= 1
        if c == '↑':  # 根据标记,向上找下一个
            l1 -= 1
    s.reverse()
    return ''.join(s)

poem1 = '''《将进酒》——李白
君不见黄河之水天上来,奔流到海不复回。君不见高堂明镜悲白发,朝如青丝暮成雪。
人生得意须尽欢,莫使金樽空对月。天生我材必有用,千金散尽还复来。
烹羊宰牛且为乐,会须一饮三百杯。岑夫子,丹丘生,将进酒,杯莫停。与君歌一曲,请君为我倾耳听。
钟鼓馔玉不足贵,但愿长醉不复醒。古来圣贤皆寂寞,惟有饮者留其名。
陈王昔时宴平乐,斗酒十千恣欢谑。主人何为言少钱,径须沽取对君酌。
五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。'''.replace('\n', '')
poem2 = '''《惜樽空》——李白
君不见黄河之水天上来,奔流到海不复回。君不见床头明镜悲白发,朝如青云暮成雪。
人生得意须尽欢,莫使金樽空对月。天生吾徒有俊才,千金散尽还复来。
烹羊宰牛且为乐,会须一饮三百杯。岑夫子,丹丘生,与君哥一曲,请君为我倾。
钟鼓玉帛岂足贵,但用长醉不复醒。古来贤圣皆死尽,惟有饮者留其名。
陈王昔时宴平乐,斗酒十千恣欢谑。主人何为言少钱,径须沽取对君酌。
五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。'''.replace('\n', '')
print(lcs(poem1, poem2))

《》——李白君不见黄河之水天上来,奔流到海不复回。君不见明镜悲白发,朝如青暮成雪。人生得意须尽欢,莫使金樽空对月。天生有,千金散尽还复来。烹羊宰牛且为乐,会须一饮三百杯。岑夫子,丹丘生,与君一曲,请君为我倾。钟鼓玉足贵,但长醉不复醒。古来圣皆,惟有饮者留其名。陈王昔时宴平乐,斗酒十千恣欢谑。主人何为言少钱,径须沽取对君酌。五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。

9、从属关系

e.g.
南海区 属于 佛山市 属于 广东省
南海区 match 南海区 = 100%
佛山市 match 南海区 = 50%
广东省 match 南海区 = 25%
禅城区 match 南海区 = 0%
district = {
    '广东省': '44',
    '广州市': '4401',
    '韶关市': '4402',
    '深圳市': '4403',
    '珠海市': '4404',
    '汕头市': '4405',
    '佛山市': '4406',
    '禅城区': '440604',
    '南海区': '440605',
}

def similarity(a, b):
    a, b = district[a], district[b]
    if a == b:
        return 1
    elif b == a[:len(b)]:  # b属于a
        return 1 / (len(a) - len(b))
    elif a == b[:len(a)]:  # a属于b
        return 1 / (len(b) - len(a))
    else:
        return 0

print(similarity('南海区', '南海区'))
print(similarity('佛山市', '南海区'))
print(similarity('广东省', '南海区'))
print(similarity('禅城区', '南海区'))

10、相关系数

import pandas as pd
df = pd.DataFrame({
    'a': [11, 22, 33, 44, 55, 66, 77, 88, 99],
    'b': [10, 24, 30, 48, 50, 72, 70, 96, 90],
    'c': [91, 79, 72, 58, 53, 47, 34, 16, 10],
    'd': [99, 10, 98, 10, 17, 10, 77, 89, 10]})
df_corr = df.corr()
# 可视化
import matplotlib.pyplot as mp, seaborn
seaborn.heatmap(df_corr, center=0, annot=True, cmap='YlGnBu')
mp.show()

相关系数矩阵

如图所示:a和b相关度较高,a和d相关度较低
可以通过一些规则 把相关度折算为相似度

11、协同过滤

https://yellow520.blog.csdn.net/article/details/120078590

用户物品稀疏矩阵
协同过滤ALS矩阵分解
用户隐语义矩阵
物品隐语义矩阵
用户与用户之间的相似度矩阵
用户物品预测矩阵
物品与物品之间的相似度矩阵

补充

相似度矩阵

def similar_matrix(ls, f):
    import seaborn, matplotlib.pyplot as mp
    le = len(ls)
    matrix = [[f(ls[i], ls[j]) for j in range(le)] for i in range(le)]
    seaborn.heatmap(matrix, center=1, annot=True)
    mp.show()

# 相似度 = 交集 / 并集
similarity = lambda a, b: len(a & b) / len(a | b)
a = set('abcd')
b = set('bcde')
c = set('abcde')
similar_matrix([a, b, c], similarity)

并行计算

import numpy as np
from multiprocessing import Pool, Manager
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity

def similarity_set(s1, s2, similarity):
    s1, s2 = set(list(s1)), set(list(s2))
    sim = len(s1 & s2) / len(s1 | s2)
    print('set', sim)
    similarity[0] = sim

def similarity_edit_distance(s1, s2, similarity):
    l1, l2 = len(s1) + 1, len(s2) + 1
    matrix = np.zeros((l1, l2), dtype=int)
    for i in range(l1):
        matrix[i, 0] = i
    for j in range(l2):
        matrix[0, j] = j
    for i in range(1, l1):
        for j in range(1, l2):
            delta = 0 if s1[i - 1] == s2[j - 1] else 1
            matrix[i, j] = min(matrix[i - 1, j - 1] + delta,
                               matrix[i - 1, j] + 1,
                               matrix[i, j - 1] + 1)
    sim = 1 - matrix[-1][-1] / (l1 + l2 - 2) * 2
    print('edit_distance', sim)
    similarity[1] = sim

def similarity_cosine(s1, s2, similarity):
    vec1, vec2 = CountVectorizer(token_pattern='.').fit_transform([s1, s2])
    sim = cosine_similarity(vec1, vec2)[0][0]
    print('cosine', sim)
    similarity[2] = sim

def mult(s1, s2):
    similarity = Manager().Array('f', [0, 0, 0])  # 共享数组
    functions = [similarity_set, similarity_edit_distance, similarity_cosine]
    pool = Pool(processes=len(functions))
    for func in functions:
        pool.apply_async(func, (s1, s2, similarity))
    pool.close()
    pool.join()
    print('average', np.average(similarity, weights=[.3, .2, .5]))

if __name__ == '__main__':
    poem1 = '''《将进酒》——李白
    君不见黄河之水天上来,奔流到海不复回。君不见高堂明镜悲白发,朝如青丝暮成雪。
    人生得意须尽欢,莫使金樽空对月。天生我材必有用,千金散尽还复来。
    烹羊宰牛且为乐,会须一饮三百杯。岑夫子,丹丘生,将进酒,杯莫停。与君歌一曲,请君为我倾耳听。
    钟鼓馔玉不足贵,但愿长醉不复醒。古来圣贤皆寂寞,惟有饮者留其名。
    陈王昔时宴平乐,斗酒十千恣欢谑。主人何为言少钱,径须沽取对君酌。
    五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。'''.replace('\n', '')
    poem2 = '''《惜樽空》——李白
    君不见黄河之水天上来,奔流到海不复回。君不见床头明镜悲白发,朝如青云暮成雪。
    人生得意须尽欢,莫使金樽空对月。天生吾徒有俊才,千金散尽还复来。
    烹羊宰牛且为乐,会须一饮三百杯。岑夫子,丹丘生,与君哥一曲,请君为我倾。
    钟鼓玉帛岂足贵,但用长醉不复醒。古来贤圣皆死尽,惟有饮者留其名。
    陈王昔时宴平乐,斗酒十千恣欢谑。主人何为言少钱,径须沽取对君酌。
    五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。'''.replace('\n', '')
    mult(poem1, poem2)
    # 自定义
    s1 = input('s1:').strip()
    s2 = input('s2:').strip()
    mult(s1, s2)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小基基o_O

您的鼓励是我创作的巨大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值