熊猫矩阵计算直到对角线

Sri*_*mar 6 python pandas

我正在使用 python 中的 Pandas 进行矩阵计算。

我的原始数据是字符串列表的形式(每行都是唯一的)。

id     list_of_value
0      ['a','b','c']
1      ['d','b','c']
2      ['a','b','c']
3      ['a','b','c']
Run Code Online (Sandbox Code Playgroud)

我必须用一行和所有其他行计算分数

分数计算算法:

Step 1: Take value of id 0: ['a','b','c'],
Step 2: find the intersection between id 0 and id 1 , 
        resultant = ['b','c']
Step 3: Score Calculation => resultant.size / id(0).size
Run Code Online (Sandbox Code Playgroud)

在 id 0 和 id 1,2,3 之间重复步骤 2,3,对于所有 id 都类似。

创建 N * N 矩阵:

-  0    1    2  3
0  1    0.6  1  1
1  0.6  1    1  1 
2  1    1    1  1
3  1    1    1  1
Run Code Online (Sandbox Code Playgroud)

目前我正在使用熊猫傻瓜方法来计算分数:

s = pd.get_dummies(df.list_of_value.explode()).sum(level=0)
s.dot(s.T).div(s.sum(1))
Run Code Online (Sandbox Code Playgroud)

但是在矩阵的对角线之后计算有重复,直到对角线的分数计算就足够了。例如:

计算 ID 0 的分数,将只到 ID(row,column) (0,0), score for ID(row,column) (0,1),(0,2),(0,3) 可以从 ID(row,column) (1,0),(2,0),(3,0) 复制。

详细计算: 基质样品 我需要计算直到对角线,即直到黄色框(矩阵的对角线),白色值已经在绿色阴影区域(参考)中计算出来,我只需要将绿色阴影区域转置为白色。

我怎么能在熊猫中做到这一点?

Nig*_*ain 8

首先,这里是对您的代码的分析。首先将所有命令分开,然后在您发布它时。

%timeit df.list_of_value.explode()
%timeit pd.get_dummies(s)
%timeit s.sum(level=0)
%timeit s.dot(s.T)
%timeit s.sum(1)
%timeit s2.div(s3)
Run Code Online (Sandbox Code Playgroud)

上述分析返回以下结果:

Explode   : 1000 loops, best of 3: 201 µs per loop
Dummies   : 1000 loops, best of 3: 697 µs per loop
Sum       : 1000 loops, best of 3: 1.36 ms per loop
Dot       : 1000 loops, best of 3: 453 µs per loop
Sum2      : 10000 loops, best of 3: 162 µs per loop
Divide    : 100 loops, best of 3: 1.81 ms per loop
Run Code Online (Sandbox Code Playgroud)

将您的两行放在一起会导致:

100 loops, best of 3: 5.35 ms per loop
Run Code Online (Sandbox Code Playgroud)

使用一种不同的方法,较少依赖 Pandas 的(有时是昂贵的)功能,通过跳过上三角矩阵和对角线的计算,我创建的代码只需要大约三分之一的时间。

Explode   : 1000 loops, best of 3: 201 µs per loop
Dummies   : 1000 loops, best of 3: 697 µs per loop
Sum       : 1000 loops, best of 3: 1.36 ms per loop
Dot       : 1000 loops, best of 3: 453 µs per loop
Sum2      : 10000 loops, best of 3: 162 µs per loop
Divide    : 100 loops, best of 3: 1.81 ms per loop
Run Code Online (Sandbox Code Playgroud)

随着df给出

100 loops, best of 3: 5.35 ms per loop
Run Code Online (Sandbox Code Playgroud)

对此代码的分析导致运行时间仅为 1.68 毫秒。

1000 loops, best of 3: 1.68 ms per loop
Run Code Online (Sandbox Code Playgroud)

更新

无需对整个 DataFrame 进行操作,只需选择所需的系列即可大大提高速度。

三种迭代系列中条目的方法已经过测试,所有这些方法在性能方面或多或少是相同的。

import numpy as np

# create a matrix filled with ones (thus the diagonal is already filled with ones)
df2 = np.ones(shape = (len(df), len(df)))
for i in range(len(df)):
    d0 = set(df.iloc[i].list_of_value)
    d0_len = len(d0)
    # the inner loop starts at i+1 because we don't need to calculate the diagonal
    for j in range(i + 1, len(df)):
        df2[j, i] = len(d0.intersection(df.iloc[j].list_of_value)) / d0_len
# copy the lower triangular matrix to the upper triangular matrix
df2[np.mask_indices(len(df2), np.triu)] = df2.T[np.mask_indices(len(df2), np.triu)]
# create a DataFrame from the numpy array with the column names set to score<id>
df2 = pd.DataFrame(df2, columns = [f"score{i}" for i in range(len(df))])
Run Code Online (Sandbox Code Playgroud)

熊猫有很多陷阱。例如,总是通过df.iloc[0]而不是访问 DataFrame 或 Series 的行df[0]。两者都有效,但df.iloc[0]速度要快得多。

第一个矩阵的时序有 4 个元素,每个元素的列表大小为 3,因此速度提高了大约 3 倍。

1000 loops, best of 3: 443 µs per loop
Run Code Online (Sandbox Code Playgroud)

当使用更大的数据集时,我得到了更好的结果,加速比超过 11:

# operating on the DataFrame
10 loop, best of 3: 565 ms per loop

# operating on the Series
10 loops, best of 3: 47.7 ms per loop
Run Code Online (Sandbox Code Playgroud)

更新 2

当根本不使用 Pandas 时(在计算过程中),你会得到另一个显着的加速。因此,您只需要将要操作的列转换为列表。

df = pd.DataFrame(
    [[['a','b','c']],
     [['d','b','c']],
     [['a','b','c']],
     [['a','b','c']]],
     columns = ["list_of_value"])
Run Code Online (Sandbox Code Playgroud)

在问题中提供的数据上,与第一次更新相比,我们只看到稍微好一点的结果。

1000 loops, best of 3: 363 µs per loop
Run Code Online (Sandbox Code Playgroud)

但是当使用更大的数据(100 行,列表大小为 15)时,优势变得明显:

100 loops, best of 3: 5.26 ms per loop
Run Code Online (Sandbox Code Playgroud)

这是所有建议方法的比较:

+----------+-----------------------------------------+
|          | Using the Dataset from the question     |
+----------+-----------------------------------------+
| Question | 100 loops, best of 3: 4.63 ms per loop  |
+----------+-----------------------------------------+
| Answer   | 1000 loops, best of 3: 1.59 ms per loop |
+----------+-----------------------------------------+
| Update 1 | 1000 loops, best of 3: 447 µs per loop  |
+----------+-----------------------------------------+
| Update 2 | 1000 loops, best of 3: 362 µs per loop  |
+----------+-----------------------------------------+
Run Code Online (Sandbox Code Playgroud)