使用Python进行杰卡德距离的非对称计算
Using Python for asymmetric calculation of jaccard distance
我有一些 SAS 编码,我正试图将其转换为 Python。我在计算非对称数据的 jaccard 距离时遇到了困难——在计算中应该忽略零。我确实在 jaccard 上找到了一些例子,但它们没有计算不对称距离。在我尝试重新发明轮子之前,只是检查一下图书馆是否有这个可用。如果有人可以引导我朝着正确的方向前进,我将不胜感激。
我的测试数据集包含 5 headers 和 5 行
H0 H1 H2 H3 H4
A 1 1 1 1 0
B 1 0 1 1 0
C 1 1 1 1 0
D 0 0 1 1 1
E 1 1 0 1 0
下面是 shorthand 和使用 SAS 计算的预期结果(距离):
. | A | B | C | D | E
A | 0 | 0.25| 0 | 0.6 | 0.25
B | 0.25| 0 | 0.25| 0.5 | 0.5
C | 0 | 0.25| 0 | 0.6 | 0.25
D | 0.6 | 0.5 | 0.6 | 0 | 0.8
E | 0.25| 0.5 | 0.25| 0.8 | 0
但是,在 python 中使用 jaccard,我得到如下结果:
. |A | B | C | D | E
A |1.00 | 0.43 | 0.61 | 0.55 | 0.46
B |0.43 | 1.00 | 0.52 | 0.56 | 0.49
C |0.61 | 0.52 | 1.00 | 0.48 | 0.53
D |0.55 | 0.56 | 0.48 | 1.00 | 0.49
E |0.46 | 0.49 | 0.53 | 0.49 | 1.00
下面是我试验过的代码。我是 Python 的新手,所以我可能犯了一个明显的错误。我在底部添加了 SAS 代码,以防有人需要它作为参考:
Python代码:
np.random.seed(0)
df = pd.DataFrame(np.random.binomial(1, 0.5, size=(100, 5)),
columns=list('ABCDE'))
print(df.head())
jac_sim = 1 - pairwise_distances(df.T, metric = "jaccard")
jac_sim = pd.DataFrame(jac_sim, index=df.columns, columns=df.columns)
import itertools
sim_df = pd.DataFrame(np.ones((5, 5)), index=df.columns, columns=df.columns)
for col_pair in itertools.combinations(df.columns, 2):
sim_df.loc[col_pair] = sim_df.loc[tuple(reversed(col_pair))] =
jaccard_similarity_score(df[col_pair[0]], df[col_pair[1]])
print(sim_df)
SAS 代码:
proc import datafile = '/home/xxx/xxx.csv'
out = work.Binary2 replace
dbms = CSV;
GUESSINGROWS=MAX;
run;
proc sort;
by VAR1;
run;
title ’Data Clustering of BN’;
proc distance data=Binary2 method=djaccard absent=0 out=distjacc;
var anominal (r0--r4);
id VAR1;
run;
我发现了一些明显的错误。首先,您需要创建 size=(5,5)
:
的矩阵
import pandas as pd
import numpy as np
from sklearn.metrics import pairwise_distances, jaccard_similarity_score
np.random.seed(0)
df = pd.DataFrame(np.random.binomial(1, 0.5, size=(5, 5)).T, columns=list('ABCDE'))
print(df.T)
第二,如果你只打印头部,你不会看到矩阵有超过 5 行。只有 5 行,这两个:
print(df.T.head())
print(df.T)
打印相同的结果:
0 1 2 3 4
A 1 1 1 1 0
B 1 0 1 1 0
C 1 1 1 1 0
D 0 0 1 1 1
E 1 1 0 1 0
经过上述更改后可以使用 pairwise_distances
:
jac_sim = pairwise_distances(df.T.astype(bool), metric = "jaccard")
jac_sim = pd.DataFrame(jac_sim, index=df.columns, columns=df.columns)
print(jac_sim)
为了得到想要的结果:
A B C D E
A 0.00 0.25 0.00 0.6 0.25
B 0.25 0.00 0.25 0.5 0.50
C 0.00 0.25 0.00 0.6 0.25
D 0.60 0.50 0.60 0.0 0.80
E 0.25 0.50 0.25 0.8 0.00
上面代码中还有.astype(bool)
是为了防止在运行pairwise_distance
.
时出现警告
在应用转置 .T
时必须小心,因为 pairwise_distance
似乎更适合列而不是行。
有函数jaccard_similarity_score
import itertools
sim_df = pd.DataFrame(np.zeros((5, 5)), index=df.columns, columns=df.columns)
for col_pair in itertools.combinations(df.columns, 2):
sim_df.loc[col_pair] = sim_df.loc[tuple(reversed(col_pair))] = \
1 - jaccard_similarity_score(df[col_pair[0]], df[col_pair[1]], normalize = True)
print(sim_df)
我得到了一个不同的矩阵:
A B C D E
A 0.0 0.2 0.0 0.6 0.2
B 0.2 0.0 0.2 0.4 0.4
C 0.0 0.2 0.0 0.6 0.2
D 0.6 0.4 0.6 0.0 0.8
E 0.2 0.4 0.2 0.8 0.0
仔细观察jaccard_similarity_score
:
print(df['A'])
print(df['B'])
jaccard_similarity_score(df['A'], df['B'], normalize = True)
显示没有排除零结果:
0 1
1 1
2 1
3 1
4 0
Name: A, dtype: int32
0 1
1 0
2 1
3 1
4 0
Name: B, dtype: int32
Out[123]: 0.8
因为结果是 4 个相似 / 5 个总计 = 0.8,而不是 3 个相似非零值 / 4 个总非零值 = 0.75。
我有一些 SAS 编码,我正试图将其转换为 Python。我在计算非对称数据的 jaccard 距离时遇到了困难——在计算中应该忽略零。我确实在 jaccard 上找到了一些例子,但它们没有计算不对称距离。在我尝试重新发明轮子之前,只是检查一下图书馆是否有这个可用。如果有人可以引导我朝着正确的方向前进,我将不胜感激。
我的测试数据集包含 5 headers 和 5 行
H0 H1 H2 H3 H4
A 1 1 1 1 0
B 1 0 1 1 0
C 1 1 1 1 0
D 0 0 1 1 1
E 1 1 0 1 0
下面是 shorthand 和使用 SAS 计算的预期结果(距离):
. | A | B | C | D | E
A | 0 | 0.25| 0 | 0.6 | 0.25
B | 0.25| 0 | 0.25| 0.5 | 0.5
C | 0 | 0.25| 0 | 0.6 | 0.25
D | 0.6 | 0.5 | 0.6 | 0 | 0.8
E | 0.25| 0.5 | 0.25| 0.8 | 0
但是,在 python 中使用 jaccard,我得到如下结果:
. |A | B | C | D | E
A |1.00 | 0.43 | 0.61 | 0.55 | 0.46
B |0.43 | 1.00 | 0.52 | 0.56 | 0.49
C |0.61 | 0.52 | 1.00 | 0.48 | 0.53
D |0.55 | 0.56 | 0.48 | 1.00 | 0.49
E |0.46 | 0.49 | 0.53 | 0.49 | 1.00
下面是我试验过的代码。我是 Python 的新手,所以我可能犯了一个明显的错误。我在底部添加了 SAS 代码,以防有人需要它作为参考:
Python代码:
np.random.seed(0)
df = pd.DataFrame(np.random.binomial(1, 0.5, size=(100, 5)),
columns=list('ABCDE'))
print(df.head())
jac_sim = 1 - pairwise_distances(df.T, metric = "jaccard")
jac_sim = pd.DataFrame(jac_sim, index=df.columns, columns=df.columns)
import itertools
sim_df = pd.DataFrame(np.ones((5, 5)), index=df.columns, columns=df.columns)
for col_pair in itertools.combinations(df.columns, 2):
sim_df.loc[col_pair] = sim_df.loc[tuple(reversed(col_pair))] =
jaccard_similarity_score(df[col_pair[0]], df[col_pair[1]])
print(sim_df)
SAS 代码:
proc import datafile = '/home/xxx/xxx.csv'
out = work.Binary2 replace
dbms = CSV;
GUESSINGROWS=MAX;
run;
proc sort;
by VAR1;
run;
title ’Data Clustering of BN’;
proc distance data=Binary2 method=djaccard absent=0 out=distjacc;
var anominal (r0--r4);
id VAR1;
run;
我发现了一些明显的错误。首先,您需要创建 size=(5,5)
:
import pandas as pd
import numpy as np
from sklearn.metrics import pairwise_distances, jaccard_similarity_score
np.random.seed(0)
df = pd.DataFrame(np.random.binomial(1, 0.5, size=(5, 5)).T, columns=list('ABCDE'))
print(df.T)
第二,如果你只打印头部,你不会看到矩阵有超过 5 行。只有 5 行,这两个:
print(df.T.head())
print(df.T)
打印相同的结果:
0 1 2 3 4
A 1 1 1 1 0
B 1 0 1 1 0
C 1 1 1 1 0
D 0 0 1 1 1
E 1 1 0 1 0
经过上述更改后可以使用 pairwise_distances
:
jac_sim = pairwise_distances(df.T.astype(bool), metric = "jaccard")
jac_sim = pd.DataFrame(jac_sim, index=df.columns, columns=df.columns)
print(jac_sim)
为了得到想要的结果:
A B C D E
A 0.00 0.25 0.00 0.6 0.25
B 0.25 0.00 0.25 0.5 0.50
C 0.00 0.25 0.00 0.6 0.25
D 0.60 0.50 0.60 0.0 0.80
E 0.25 0.50 0.25 0.8 0.00
上面代码中还有.astype(bool)
是为了防止在运行pairwise_distance
.
在应用转置 .T
时必须小心,因为 pairwise_distance
似乎更适合列而不是行。
有函数jaccard_similarity_score
import itertools
sim_df = pd.DataFrame(np.zeros((5, 5)), index=df.columns, columns=df.columns)
for col_pair in itertools.combinations(df.columns, 2):
sim_df.loc[col_pair] = sim_df.loc[tuple(reversed(col_pair))] = \
1 - jaccard_similarity_score(df[col_pair[0]], df[col_pair[1]], normalize = True)
print(sim_df)
我得到了一个不同的矩阵:
A B C D E
A 0.0 0.2 0.0 0.6 0.2
B 0.2 0.0 0.2 0.4 0.4
C 0.0 0.2 0.0 0.6 0.2
D 0.6 0.4 0.6 0.0 0.8
E 0.2 0.4 0.2 0.8 0.0
仔细观察jaccard_similarity_score
:
print(df['A'])
print(df['B'])
jaccard_similarity_score(df['A'], df['B'], normalize = True)
显示没有排除零结果:
0 1
1 1
2 1
3 1
4 0
Name: A, dtype: int32
0 1
1 0
2 1
3 1
4 0
Name: B, dtype: int32
Out[123]: 0.8
因为结果是 4 个相似 / 5 个总计 = 0.8,而不是 3 个相似非零值 / 4 个总非零值 = 0.75。