パンダのデータフレームでユニオン(ジャッカードのインデックス)の交差を計算します

Aug 22 2020

私は次のようなデータフレームを持っています:

animal    ids
cat       1,3,4
dog       1,2,4
hamster   5        
dolphin   3,5

データフレームは非常に大きく、8万行を超え、ids列には数千を超えるIDが含まれている可能性があります。特定の行のIDは、コンマ区切りの文字列で一意になります。

Jaccardのインデックスを計算するデータフレームを構築したいと思います。つまり、動物の列の各項目と、和集合のids列の項目の共通部分です。

したがって、猫と犬を見ると、和集合は2(id 1と4)であり、和集合は4(id 1、2、3、4)であるため、Jaccardのインデックスは2/4 = 0.5です。この形式のデータセットがあると便利です。

            cat        dog        hamster    dolphin
cat         1          0.5        0          0.25
dog         0.5        1          0          0
hamster     0          0          1          0.5
dolphin     0.25       0          0.5        1

これは、動物の名前として行インデックスを使用することを意味します。これにより、関連するjaccardのインデックスを次のようにすばやく見つけることができます。

cat_dog_ji = df_new['cat']['dog']

回答

5 user3483203 Aug 22 2020 at 19:04

ここでstr.get_dummiesといくつかのscipyツールを使用できます。


from scipy.spatial import distance

u = df["ids"].str.get_dummies(",")
j = distance.pdist(u, "jaccard")
k = df["animal"].to_numpy()
pd.DataFrame(1 - distance.squareform(j), index=k, columns=k)

          cat  dog  hamster  dolphin
cat      1.00  0.5      0.0     0.25
dog      0.50  1.0      0.0     0.00
hamster  0.00  0.0      1.0     0.50
dolphin  0.25  0.0      0.5     1.00
3 ShubhamSharma Aug 22 2020 at 18:38

使用する:

d = df.assign(key=1, ids=df['ids'].str.split(','))
d = d.merge(d, on='key', suffixes=['', '_r'])

i = [np.intersect1d(*x).size / np.union1d(*x).size for x in zip(d['ids'], d['ids_r'])]
d = pd.crosstab(d['animal'], d['animal_r'], i, aggfunc='first').rename_axis(index=None, columns=None)

詳細:

使用するDataFrame.assign一時的な列を作成しkey、使用するSeries.str.split列にしますids。次に、を使用DataFrame.mergeして、データフレームdをそれ自体に基づく列とマージしますkey(基本的にクロス結合)。

print(d)

     animal        ids  key animal_r      ids_r
0       cat  [1, 3, 4]    1      cat  [1, 3, 4]
1       cat  [1, 3, 4]    1      dog  [1, 2, 4]
2       cat  [1, 3, 4]    1  hamster        [5]
3       cat  [1, 3, 4]    1  dolphin     [3, 5]
4       dog  [1, 2, 4]    1      cat  [1, 3, 4]
5       dog  [1, 2, 4]    1      dog  [1, 2, 4]
6       dog  [1, 2, 4]    1  hamster        [5]
7       dog  [1, 2, 4]    1  dolphin     [3, 5]
8   hamster        [5]    1      cat  [1, 3, 4]
9   hamster        [5]    1      dog  [1, 2, 4]
10  hamster        [5]    1  hamster        [5]
11  hamster        [5]    1  dolphin     [3, 5]
12  dolphin     [3, 5]    1      cat  [1, 3, 4]
13  dolphin     [3, 5]    1      dog  [1, 2, 4]
14  dolphin     [3, 5]    1  hamster        [5]
15  dolphin     [3, 5]    1  dolphin     [3, 5]

内部リスト内包表記np.interset1dとともに使用してnp.union1d、Jaccard'sインデックスを計算します。

print(i)
[1.0, 0.5, 0.0, 0.25, 0.5, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.5, 0.25, 0.0, 0.5, 1.0]

最後に、を使用pd.crosstabして単純なクロス集計を作成し、目的の形式で結果を取得します。

print(d)
          cat  dog  dolphin  hamster
cat      1.00  0.5     0.25      0.0
dog      0.50  1.0     0.00      0.0
dolphin  0.25  0.0     1.00      0.5
hamster  0.00  0.0     0.50      1.0