You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Jensen-Shannon散度的分半信度:矩阵构建与计算问题

构建个体响应的Jensen-Shannon散度矩阵及热力图

步骤1:合并数据并设置复合索引

首先将两个DataFrame合并,用ID和group作为复合索引,确保矩阵的行和列能唯一标识每个个体:

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

# 原始数据
df_1 = pd.DataFrame({'ID': ['a', 'b', 'c', 'd', 'e', 'f'], 
                     'response': [["apple", "berry", "cherry"],
                                  ["pear", "pineapple", "plum"],
                                  ["blue_berry"],
                                  ["orange", "lemon"],
                                  ["tomato", "pumpkin"],
                                  ["avocado", "strawberry"]], 
                     'group': [1, 2, 1, 2, 1, 2]})

df_2 = pd.DataFrame({'ID': ['A', 'B','C', 'D', 'E', 'F'], 
                     'response': [["pear", "plum", "cherry"],
                                  ["orange", "lemon", "lime", "pineapple"],
                                  ["pumpkin"],
                                  ["tomato", "strawberry"],
                                  ["avocado", "apple"],
                                  ["berry", "cherry", "apple"]], 
                     'group': [1, 2, 1, 2, 1, 2]})

# 合并DataFrame并设置复合索引
df_combined = pd.concat([df_1, df_2], ignore_index=True)
df_combined = df_combined.set_index(['ID', 'group'])

步骤2:转换响应为统一概率分布

JSD要求输入是等长且和为1的概率分布,因此先收集所有出现过的响应项,再将每个个体的响应列表转换为对应分布:

# 收集所有唯一响应项
all_items = set()
for resp in df_combined['response']:
    all_items.update(resp)
all_items = sorted(list(all_items))

# 将响应列表转为概率分布
def response_to_dist(response):
    dist = np.zeros(len(all_items))
    for item in response:
        idx = all_items.index(item)
        dist[idx] += 1
    total = dist.sum()
    return dist / total if total != 0 else dist

# 生成所有个体的分布矩阵
dist_matrix = np.array([response_to_dist(resp) for resp in df_combined['response']])

步骤3:修正JSD函数处理零值

原函数未处理零值会导致NaN,加入小epsilon避免除以0和对数无意义的情况:

def jsdiv(P, Q, epsilon=1e-10):
    """计算两个概率分布的Jensen-Shannon散度"""
    def _kldiv(A, B):
        # 加入epsilon避免数值异常
        A = A + epsilon
        B = B + epsilon
        A = A / A.sum()
        B = B / B.sum()
        return np.sum(A * np.log2(A / B))
    
    P = np.array(P)
    Q = np.array(Q)
    M = 0.5 * (P + Q)
    return 0.5 * (_kldiv(P, M) + _kldiv(Q, M))

步骤4:构建JSD得分矩阵

遍历所有个体对,计算两两JSD得分,生成方阵:

n = len(df_combined)
jsd_matrix = np.zeros((n, n))

for i in range(n):
    for j in range(n):
        jsd_matrix[i, j] = jsdiv(dist_matrix[i], dist_matrix[j])

# 转换为带复合索引的DataFrame
jsd_df = pd.DataFrame(jsd_matrix, index=df_combined.index, columns=df_combined.index)

步骤5:绘制热力图

用seaborn可视化JSD矩阵,直观展示个体响应的相似度(JSD越小,分布越相似):

plt.figure(figsize=(12, 10))
sns.heatmap(jsd_df, annot=True, cmap='coolwarm', fmt='.4f')
plt.title('个体响应的Jensen-Shannon散度热力图')
plt.xlabel('个体(ID+Group)')
plt.ylabel('个体(ID+Group)')
plt.show()

内容的提问来源于stack exchange,提问作者psychcoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 11:05:28