【问题标题】:Optimizing Matrix Traversal/General Code Optimization优化矩阵遍历/通用代码优化
【发布时间】:2019-12-16 14:47:37
【问题描述】:

我有两个矩阵。一个是大小 (CxK),另一个是大小 (SxK)(其中 S、C 和 K 都有可能非常大)。我想使用余弦相似度函数(大小为 [CxS])将这些输出矩阵组合起来。当我运行我的代码时,需要很长时间才能产生输出,我想知道是否有任何方法可以优化我目前拥有的内容。 [注意,两个输入矩阵通常非常稀疏]

我之前使用两个 for index,row 循环遍历每个矩阵,但后来我切换到了 while 循环,这显着改善了我的运行时间。

A #this is one of my input matrices (pandas dataframe)
B #this is my second input matrix (pandas dataframe)
C = pd.DataFrame(columns = ['col_1'  ,'col_2'  ,'col_3'])

i=0
k=0
while i <= 5:
    col_1 = A.iloc[i].get('label_A')
    while k < 5:
        col_2 = B.iloc[k].get('label_B')
        propensity = cosine_similarity([A.drop('label_A', axis=1)\
            .iloc[i]], [B.drop('label_B',axis=1).iloc[k]])
        d = {'col_1':[col_1], 'col_2':[col_2], 'col_3':[propensity[0][0]]}
        to_append = pd.DataFrame(data=d)
        C = C.append(to_append)
        k += 1
    k = 0
    i += 1

现在我的循环只在每个矩阵的 5 个项目上运行,生成一个 5x5 矩阵,但我显然希望这适用于非常大的输入。这是我第一次做这样的事情,所以请让我知道是否可以改进代码的任何方面(用于保存矩阵的数据类型,如何遍历它们,更新输出矩阵等)。

提前谢谢你。

【问题讨论】:

  • 你使用的是 sklearn 的 cosine_similarity 函数吗? scikit-learn.org/stable/modules/generated/…
  • @jTables 是的,抱歉没有导入它。我将每个输入矩阵的关键字向量传递给它,并将结果存储在输出矩阵中。
  • 很遗憾我今天没有时间回答这个问题,如果我有时间仍然没有回答,我会调查一下。一般来说,循环数据帧会很慢,使用 apply 会快得多。如果我不需要任何 pandas 功能,我还使用了底层的 numpy 数组(您可以使用 .values 获得)。事实证明,这总是比在我的应用程序中使用数据框更快。 pandas.pydata.org/pandas-docs/stable/reference/api/…

标签: python pandas numpy matrix scipy


【解决方案1】:

在将标签移动到索引后,通过将整个数组传递给cosine_similarity,可以更轻松、更快地完成此操作:

import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
import time

c = 50
s = 50
k = 100

A = pd.DataFrame( np.random.rand(c,k))
B = pd.DataFrame( np.random.rand(s,k))
A['label_A'] = [f'A{i}' for i in range(c)]
B['label_B'] = [f'B{i}' for i in range(s)]
C = pd.DataFrame()

# your program
start = time.time()
i=0
k=0
while i < c:
    col_1 = A.iloc[i].get('label_A')
    while k < s:
        col_2 = B.iloc[k].get('label_B')
        propensity = cosine_similarity([A.drop('label_A', axis=1)\
            .iloc[i]], [B.drop('label_B',axis=1).iloc[k]])
        d = {'col_1':[col_1], 'col_2':[col_2], 'col_3':[propensity[0][0]]}
        to_append = pd.DataFrame(data=d)
        C = C.append(to_append)
        k += 1
    k = 0
    i += 1
print(f'elementwise: {time.time() - start:7.3f} s')

# my solution
start = time.time()
A = A.set_index('label_A')
B = B.set_index('label_B')
C1 = pd.DataFrame(cosine_similarity(A, B), index=A.index, columns=B.index).stack().rename('col_3')
C1.index.rename(['col_1','col_2'], inplace=True)
C1 = C1.reset_index()
print(f'whole array: {time.time() - start:7.3f} s')

# verification
assert(C[['col_1','col_2']].to_numpy()==C1[['col_1','col_2']].to_numpy()).all()\
       and np.allclose(C.col_3.to_numpy(), C1.col_3.to_numpy())

【讨论】:

  • 所以这非常有效,但还有另一个问题。我也在尝试这样做以进行项目到项目推荐,当我将数据框的索引和列设置为相同的值时,例如C1 = pd.DataFrame(cosine_similarity(A, A), index=A.index, columns=A.index).stack().reset_index(),我收到错误ValueError: cannot insert A.index, already exists。知道如何解决吗?
  • @kshoe94 我更新了我的答案,以便它在重置索引之前重命名列也适用于这种情况。
猜你喜欢
  • 2015-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-09
  • 1970-01-01
  • 1970-01-01
  • 2020-03-10
  • 1970-01-01
相关资源
最近更新 更多