Python:如何计算两个网络之间的jaccard索引?

Python:如何计算两个网络之间的jaccard索引?,python,pandas,complex-networks,Python,Pandas,Complex Networks,我有两个数据帧df1和df2,其中包含两个网络的边缘列表g1和g2,其中包含相同的节点但不同的连接。对于每个节点,我想比较两个网络之间的jaccard索引 我定义了计算jaccard索引的函数 def compute_jaccard_index(set_1, set_2): n = len(set_1.intersection(set_2)) return n / float(len(set_1) + len(set_2) - n) df1 i j 0

我有两个数据帧
df1
df2
,其中包含两个网络的边缘列表
g1
g2
,其中包含相同的节点但不同的连接。对于每个节点,我想比较两个网络之间的jaccard索引

我定义了计算jaccard索引的函数

def compute_jaccard_index(set_1, set_2):
    n = len(set_1.intersection(set_2))
    return n / float(len(set_1) + len(set_2) - n) 

df1  
     i   j
0    0   2
1    0   5
2    1   2
3    2   3
4    2   4
5    2   7


df2  
     i   j
0    0   2
1    0   5
2    0   1
3    1   3
4    2   4
5    2   7
我现在做的是:

tmp1 = pd.unique(df1['i'])
tmp2 = pd.unique(df2['i'])

JI = []
for i in tmp1:
    tmp11 = df1[df1['i']==i]
    tmp22 = df2[df2['i']==i]
    set_1 = list(tmp11['j'])
    set_2 = list(tmp22['j'])

    JI.append(compute_jaccard_index(set_1, set_2))

我想知道是否有更有效的方法

我总是发现利用scipy的稀疏矩阵和向量化操作比依赖python的set函数更快。下面是一个简单的函数 数据帧边缘列表到稀疏矩阵(有向和无向):

然后就是对二进制邻接矩阵的简单向量运算:

def sparse_jaccard(m1,m2):

    intersection = m1.multiply(m2).sum(axis=1)
    a = m1.sum(axis=1)
    b = m2.sum(axis=1)
    jaccard = intersection/(a+b-intersection)

    # force jaccard to be 0 even when a+b-intersection is 0
    jaccard.data = np.nan_to_num(jaccard.data)
    return np.array(jaccard).flatten() 
%timeit sparse_jaccard(sparse_adjmat(df1, N=N, directed=True, coli='i', colj='j'),sparse_adjmat(df2, N=N, directed=True, coli='i', colj='j'))
1.71 ms ± 109 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
为了进行比较,我创建了一个随机的pandas edge list函数,并将您的代码包装到以下函数中:

def erdos_renyi_df(N=100,m=400):
    df = pd.DataFrame(np.random.randint(0,N, size=(m,2)), columns = ['i','j'])
    df.drop_duplicates(['i','j'], inplace=True)
    df.sort_values(['i','j'], inplace=True)
    df.reset_index(inplace=True, drop=True)
    return df

def compute_jaccard_index(set_1, set_2):
    n = len(set_1.intersection(set_2))
    return n / float(len(set_1) + len(set_2) - n) 

def set_based_jaccard(df1,df2):
    tmp1 = pd.unique(df1['i'])
    tmp2 = pd.unique(df2['i'])
    JI = []
    for i in tmp1:
        tmp11 = df1[df1['i']==i]
        tmp22 = df2[df2['i']==i]
        set_1 = set(tmp11['j'])
        set_2 = set(tmp22['j'])

        JI.append(compute_jaccard_index(set_1, set_2))

    return JI
然后,我们可以通过创建两个随机网络来比较运行时:

N = 10**3
m = 4*N

df1 = erdos_renyi_df(N,m)
df2 = erdos_renyi_df(N,m)
并使用基于集合的方法计算每个节点的Jaccard相似性:

%timeit set_based_jaccard(df1,df2)
1.54 s ± 113 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
以及稀疏方法(包括转换为稀疏矩阵的开销):

如您所见,稀疏矩阵代码的速度大约快1000倍

%timeit sparse_jaccard(sparse_adjmat(df1, N=N, directed=True, coli='i', colj='j'),sparse_adjmat(df2, N=N, directed=True, coli='i', colj='j'))
1.71 ms ± 109 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)