Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 超大数据集的余弦相似性_Python_Numpy_Dataframe_Cosine Similarity - Fatal编程技术网

Python 超大数据集的余弦相似性

Python 超大数据集的余弦相似性,python,numpy,dataframe,cosine-similarity,Python,Numpy,Dataframe,Cosine Similarity,我在计算100维向量的大列表之间的余弦相似性时遇到问题。当我使用sklearn.metrics.pairwise import cosine_similarity中的时,我会在我的16 GB机器上获得MemoryError。每个数组都非常适合我的内存,但是我在np.dot()内部调用期间得到MemoryError 下面是我的用例以及我目前如何处理它 这是我的100维父向量,我需要与其他50万个相同维的不同向量(即100)进行比较 下面是我的子向量(本例中有一些虚构的随机数) 我的最终目标是获得与

我在计算100维向量的大列表之间的余弦相似性时遇到问题。当我使用sklearn.metrics.pairwise import cosine_similarity中的
时,我会在我的16 GB机器上获得
MemoryError
。每个数组都非常适合我的内存,但是我在
np.dot()
内部调用期间得到
MemoryError

下面是我的用例以及我目前如何处理它

这是我的100维父向量,我需要与其他50万个相同维的不同向量(即100)进行比较

下面是我的子向量(本例中有一些虚构的随机数)

我的最终目标是获得与父向量具有非常高的余弦相似性的前N个子向量(其名称如
child\u vector_1
及其相应的余弦分数)

我目前的方法(我知道它效率低下且占用内存):

步骤1:创建以下形状的超级数据框

parent_vector         1,    2,    3, .....,    100   
child_vector_1        2,    3,    4, .....,    101   
child_vector_2        3,    4,    5, .....,    102   
child_vector_3        4,    5,    6, .....,    103   
......................................   
child_vector_500000   3,    4,    5, .....,    103
第2步:使用

from sklearn.metrics.pairwise import cosine_similarity
cosine_similarity(df)
获取所有向量之间的成对余弦相似性(如上图数据帧所示)

步骤3:制作一个元组列表,以存储
,如
子向量1
,以及所有此类组合的值,如余弦相似数

第4步:使用列表的
sort()
获取top-N,这样我就可以得到子向量名以及它与父向量的余弦相似性分数

PS:我知道这是非常低效的,但我想不出更好的方法 快速计算每个子向量之间余弦相似性的方法 和父向量,并获得前N个值

非常感谢您的任何帮助。

即使您的(500000,100)数组(父数组及其子数组)适合存储 它上面的任何成对度量都不会。原因是,顾名思义,成对度量计算任意两个孩子的距离。为了存储这些距离,您需要一个(500000500000)大小的浮点数组,如果我的计算正确的话,它将占用大约100GB的内存

谢天谢地,你的问题有一个简单的解决办法。如果我理解正确的话,你只想知道孩子和父母之间的距离,这将导致一个长度为500000的向量,很容易存储在内存中

要做到这一点,您只需要为仅包含父向量的余弦相似性提供第二个参数

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

df = pd.DataFrame(np.random.rand(500000,100)) 
df['distances'] = cosine_similarity(df, df.iloc[0:1]) # Here I assume that the parent vector is stored as the first row in the dataframe, but you could also store it separately

n = 10 # or however many you want
n_largest = df['distances'].nlargest(n + 1) # this contains the parent itself as the most similar entry, hence n+1 to get n children

希望这能解决您的问题。

此解决方案速度极快

child_vectors = np.array(child_vector_1, child_vector_2, ....., child_vector_500000)
input_norm = parent_vector / np.linalg.norm(parent_vector, axis=-1)[:, np.newaxis]
embed_norm =  child_vectors/ np.linalg.norm(child_vectors, axis=-1)[:, np.newaxis]
cosine_similarities = np.sort(np.round(np.dot(input_norm, embed_norm.T), 3)[0])[::-1]
paiswise_distances = 1 - cosine_similarities

我甚至无法将整个语料库存储在内存中,因此我的解决方案是逐步加载它,并在较小的批次上计算余弦相似性,始终保留最少/最多的
n
(取决于您的用例)相似项:

data = []
iterations = 0
with open('/media/corpus.txt', 'r') as f:
    for line in f:
        data.append(line)
        if len(data) <= 1000:
            pass
        else:
            print('Getting bottom k, iteration {x}'.format(x=iterations))
            data = get_bottom_k(data, 500)
            iterations += 1
filtered = get_bottom_k(data, 500) # final most different 500 texts in corpus


def get_bottom_k(corpus:list, k:int):
    pairwise_similarity = make_similarity_matrix(corpus) # returns pairwise similarity matrix
    sums = csr_matrix.sum(pairwise_similarity, axis=1)  # Similarity index for each item in corpus. Bigger > more
    sums = np.squeeze(np.asarray(sums))
    # similar to other txt.
    indexes = np.argpartition(sums, k, axis=0)[:k] # Bottom k in terms of similarity (-k for top and [-k:])
    return [corpus[i] for i in indexes]
data=[]
迭代次数=0
将open('/media/corpus.txt',r')作为f:
对于f中的行:
data.append(行)
如果len(数据)更多
总和=np.压缩(np.asarray(总和))
#与其他txt类似。
索引=np.argpartition(和,k,轴=0)[:k]#在相似性方面的底部k(-k表示顶部和[-k:])
返回[索引中i的语料库[i]

到目前为止,这是一个最佳解决方案,但这是迄今为止我发现的最简单的解决方案,可能会对某些人有所帮助。

能否提供一些示例数据以供使用。此外,请提供小样本数据和所需输出的工作解决方案,以便so社区能够提出更有效的替代方案。@sgokhales,即使我面临同样的问题。你解决问题了吗?即使我面临同样的问题,我的数据帧的大小也是
(32593,12)
我需要计算所有对的余弦相似性,即32593*32593,它不适合内存。我该如何处理这种情况?你能提供一个时间估计吗?
child_vectors = np.array(child_vector_1, child_vector_2, ....., child_vector_500000)
input_norm = parent_vector / np.linalg.norm(parent_vector, axis=-1)[:, np.newaxis]
embed_norm =  child_vectors/ np.linalg.norm(child_vectors, axis=-1)[:, np.newaxis]
cosine_similarities = np.sort(np.round(np.dot(input_norm, embed_norm.T), 3)[0])[::-1]
paiswise_distances = 1 - cosine_similarities
data = []
iterations = 0
with open('/media/corpus.txt', 'r') as f:
    for line in f:
        data.append(line)
        if len(data) <= 1000:
            pass
        else:
            print('Getting bottom k, iteration {x}'.format(x=iterations))
            data = get_bottom_k(data, 500)
            iterations += 1
filtered = get_bottom_k(data, 500) # final most different 500 texts in corpus


def get_bottom_k(corpus:list, k:int):
    pairwise_similarity = make_similarity_matrix(corpus) # returns pairwise similarity matrix
    sums = csr_matrix.sum(pairwise_similarity, axis=1)  # Similarity index for each item in corpus. Bigger > more
    sums = np.squeeze(np.asarray(sums))
    # similar to other txt.
    indexes = np.argpartition(sums, k, axis=0)[:k] # Bottom k in terms of similarity (-k for top and [-k:])
    return [corpus[i] for i in indexes]