Python:Jaccard 相似度和距离

发布时间:2022-08-26 阅读 341

Stata连享会   主页 || 视频 || 推文 || 知乎 || Bilibili 站

温馨提示: 定期 清理浏览器缓存,可以获得最佳浏览体验。

New! lianxh 命令发布了:
随时搜索推文、Stata 资源。安装:
. ssc install lianxh
详情参见帮助文件 (有惊喜):
. help lianxh
连享会新命令:cnssc, ihelp, rdbalance, gitee, installpkg

课程详情 https://gitee.com/lianxh/Course

课程主页 https://gitee.com/lianxh/Course

⛳ Stata 系列推文:

PDF下载 - 推文合集

作者:梁淑珍 (华侨大学)
邮箱13514084150@163.com

编者按:本文主要整理自「Jaccard similarity and Jaccard distance in Python」,特此致谢!


目录


1. 前言

Jaccard 相似度,广泛应用于数据之间相似程度的计算,如集合相似度、文本相似度等。本文的 Python 实例需要使用到 scipysklearnnumpy 三个模块,具体安装命令如下:

pip install scipy
pip install sklearn
pip install numpy

2. Jaccard 相似度的定义

Jaccard 相似度 (又称 Jaccard 相似系数,或 Jaccard 指数),是用来计算两个集合之间相似度的统计量,并且可以拓展至文本相似度的计算。在 Python 中,主要用 Jaccard 相似度来计算两个集合或非对称二元变量的相似度。在数学上,Jaccard 相似度可以表示为交集与并集之比。以集合 A 和集合 B 为例:

Jaccard 相似度的计算公式为:

公式的分子部分为两个集合的交集,如下图黄色部分所示:

公式的分母部分为两个集合的并集,如下图黄色部分所示:

在数学上,Jaccard 相似度可以理解为上图交集元素个数与并集元素个数之比,具体地:

  • 如果两个集合相等,例如 A={1,2,3} 和 B={1,2,3},那么 Jaccard 相似度为 1;
  • 如果两个集合元素完全不同,例如 A={1,2,3} 和 B={4,5,6},那么 Jaccard 相似度为 0;
  • 如果两个集合有部分相同元素,例如 A={1,2,3} 和 B={3,4,5},那么 Jaccard 相似度介于 0 和 1。

3. Jaccard 相似度的计算

考虑以下两个集合:A={1,2,3,5,7} 和 B={1,2,4,8,9},在图中可以表示为:

第一步:找到两个集合的交集。在本例中,AB={1,2}

第二步:找到两个集合的并集。在本例中,AB={1,2,3,5,7,4,8,9}

第三步:计算比率。

4. Jaccard 距离的定义

与 Jaccard 相似度不同,Jaccard 距离测量的是两个集合不相似程度。在数学上,可以表示为交集的补集与并集之比。同样以集合 A 和集合 B 为例:

Jaccard 距离的公式为:

Jaccard 距离的分子还能表示为:

可以更直观地理解为两个集合间的差异,如下图黄色部分所示:

Jaccard 距离的分母与 Jaccard 相似度相同,均为两个集合的并集。

在数学上,Jaccard 距离可以理解为集合差异元素个数与并集元素个数之比。具体地:

  • 如果两个集合相等,例如 A={1,2,3} 和 B={1,2,3},那么 Jaccard 距离为 0;
  • 如果两个集合元素完全不同,例如 A={1,2,3} 和 B={4,5,6},那么 Jaccard 距离为 1;
  • 如果两个集合有部分相同元素,例如 A={1,2,3} 和 B={3,4,5},那么 Jaccard 距离介于 0 和 1。

5. Jaccard 距离的计算

考虑以下两个集合:A={1,2,3,5,7} 和 B={1,2,4,8,9},在图中可以表示为:

第一步:找到两个集合交集的补集。

第二步:找到两个集合的并集。在本例中,AB={1,2,3,5,7,4,8,9}

第三步:计算比率。

6. 非对称二元变量的相似度和距离

本节将讨论 Jaccard 相似度和 Jaccard 距离在非对称二元变量上的具体应用。

二元变量,顾名思义只有两个类别或状态。当取值为 0 时,表示该状态不出现;当取值为 1 时,表示该状态出现。例如,smoker 表示患者对象,1 表示患者抽烟,0 表示患者不抽烟。如果是对称二元变量,则其两种属性具有相同的权重,即不同状态用 0 或 1 编码并无偏好 (例如,用 0 和 1 编码表示性别变量)。

非对称二元变量的两种结果重要程度不同。例如核酸检测的结果分为阳性和阴性,阳性结果用 1 进行编码 (几率更低,结果更重要),阴性结果用 0 进行编码。给定两个非对称二元变量对象,两个对象都取 1 的情况比两个对象都取 0 更重要、更有意义。

假设现有两个 n 维向量 A 和 B,Jaccard 相似度的计算公式为:

Jaccard 距离的计算公式为:

其中,

  • M11 表示两个向量对应分量均为 1 的数量;
  • M01 表示两个向量对应分量分别为 0 和 1 的数量;
  • M10 表示两个向量对应分量分别为 1 和 0 的数量;
  • M00 表示两个向量对应分量均为 0 的数量。

并且 M11+M01+M10+M00=n

我们通过一个简易案例进行理解,例如一家商店销售 6 种商品 (苹果、西红柿、鸡蛋、牛奶、咖啡、糖),现有两个顾客的购买记录:

  • 顾客 A 购买:苹果、牛奶和咖啡
  • 顾客 B 购买:鸡蛋、牛奶和咖啡

通过上面的信息,可以构造下列矩阵:

Apple Tomato Eggs Milk Coffee Sugar
A 1 0 0 1 1 1
B 0 0 1 1 1 0

对于每一种商品而言,购买决策是一个二元变量,1 表示购买,0 表示不购买。接着,我们分两步计算 Jaccard 相似度和 Jaccard 距离:

第一步:寻找 M 值

数量 说明
(M_{11}) 2 A 和 B 都买了牛奶和咖啡
(M_{01}) 1 A 没买鸡蛋,B 买了鸡蛋
(M_{10}) 2 A 买了苹果和糖,但 B 都没买
(M_{00}) 1 A 和 B 都没买西红柿

且 M11+M01+M10+M00=6,与商品数相同,得到验证。

第二步:代入公式,则

  • Jaccard相似度:
  • Jaccard 距离:

7. Python 计算 Jaccard 相似度

在 Python 中定义两个集合:

A = {1, 2, 3, 5, 7}
B = {1, 2, 4, 8, 9}

构建函数计算 Jaccard 相似度,将集合 A 和集合 B 当做参数传入函数:

def jaccard_similarity(A, B):
    # 求集合 A 和集合 B 的交集
    nominator = A.intersection(B)
    # 求集合 A 和集合 B 的并集
    denominator = A.union(B)
    # 计算比率
    similarity = len(nominator)/len(denominator)
    return similarity
similarity = jaccard_similarity(A, B)
print(similarity)

结果为 0.25,与手动计算的结果相同。

8. Python 计算 Jaccard 距离

使用相同的数据计算 Jaccard 距离:

def jaccard_distance(A, B):
    #Find symmetric difference of two sets
    nominator = A.symmetric_difference(B)
    #Find union of two sets
    denominator = A.union(B)
    #Take the ratio of sizes
    distance = len(nominator)/len(denominator)
    return distance
distance = jaccard_distance(A, B)
print(distance)

结果为 0.75,与手动计算的结果相同。

9. Python 计算非对称二元变量

# 导入模块
import numpy as np
from scipy.spatial.distance import jaccard
from sklearn.metrics import jaccard_score

根据矩阵创建两个向量:

Apple Tomato Eggs Milk Coffee Sugar
A 1 0 0 1 1 1
B 0 0 1 1 1 0
A = np.array([1,0,0,1,1,1])
B = np.array([0,0,1,1,1,0])
similarity = jaccard_score(A, B)
distance = jaccard(A, B)
print(f'Jaccard similarity is equal to: {similarity}')
print(f'Jaccard distance is equal to: {distance}')

得到的结果为:

Jaccard similarity is equal to: 0.4
Jaccard distance is equal to: 0.6

10. Python 计算中文 Jaccard 相似度

import pandas as pd
import jieba
import re

# 调用数据
data = pd.read_excel("https://file.lianxh.cn/data/m/mda.xlsx")
stopwords = pd.read_csv("https://file.lianxh.cn/data/c/cn_stopwords.txt", names=["stopwords"])

# 定义分词函数def cut_words(text):
def cut_words(text):
    words_list = []
    text = re.sub("[\W\d]", "", text) # 替换符号和数字
    words = jieba.lcut(text)
    for word in words:
        if word not in list(stopwords["stopwords"]):
            words_list.append(word)
    return" ".join(words_list)

# 对文本分词
data["BusDA"] = data["BusDA"].apply(cut_words)
data

# 定义 jaccard 相似度函数
def jaccard_similarity(list1, list2):
    s1 = set(list1)
    s2 = set(list2)
    return float(len(s1.intersection(s2)) / len(s1.union(s2)))

jaccard_similarity(data["BusDA"][1], data["BusDA"][1])

11. 相关推文

Note:产生如下推文列表的 Stata 命令为:
lianxh python, m
安装最新版 lianxh 命令:
ssc install lianxh, replace

相关课程

免费公开课

最新课程-直播课

专题 嘉宾 直播/回看视频
最新专题 文本分析、机器学习、效率专题、生存分析等
研究设计 连玉君 我的特斯拉-实证研究设计-幻灯片-
面板模型 连玉君 动态面板模型-幻灯片-
面板模型 连玉君 直击面板数据模型 [免费公开课,2小时]
  • Note: 部分课程的资料,PPT 等可以前往 连享会-直播课 主页查看,下载。

课程主页

课程主页

关于我们

  • Stata连享会 由中山大学连玉君老师团队创办,定期分享实证分析经验。
  • 连享会-主页知乎专栏,700+ 推文,实证分析不再抓狂。直播间 有很多视频课程,可以随时观看。
  • 公众号关键词搜索/回复 功能已经上线。大家可以在公众号左下角点击键盘图标,输入简要关键词,以便快速呈现历史推文,获取工具软件和数据下载。常见关键词:课程, 直播, 视频, 客服, 模型设定, 研究设计, stata, plus, 绘图, 编程, 面板, 论文重现, 可视化, RDD, DID, PSM, 合成控制法

连享会小程序:扫一扫,看推文,看视频……

扫码加入连享会微信群,提问交流更方便

✏ 连享会-常见问题解答:
https://gitee.com/lianxh/Course/wikis

New! lianxhsongbl 命令发布了:
随时搜索连享会推文、Stata 资源,安装命令如下:
. ssc install lianxh
使用详情参见帮助文件 (有惊喜):
. help lianxh