Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/344.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_Pandas_Algorithm_Numpy_Similarity - Fatal编程技术网

Python 成对相似/相似矩阵计算优化 问题定义 问题:

Python 成对相似/相似矩阵计算优化 问题定义 问题:,python,pandas,algorithm,numpy,similarity,Python,Pandas,Algorithm,Numpy,Similarity,如何优化计算大量向量的成对余弦相似性(估计值) 形式定义 对于包含向量的两个集合(A,B),需要为每个A和B生成成对余弦相似性sim(A_i,B_j)。(余弦相似矩阵也适用,因为它很容易从矩阵转换为成对矩阵。) 我为什么要寻求帮助 这看起来像是一个常见的问题,因为在计算生物学、推荐系统等领域需要计算这样的距离,但我还没有找到合理的解决方案 我解决不了的问题 根据定义,这个问题的复杂性是O(len_A*len_B*O(相似度函数)),所以A和B集合中的10^6个向量都会有巨大的运行时间 我

如何优化计算大量向量的成对余弦相似性(估计值)

形式定义 对于包含向量的两个集合(A,B),需要为每个A和B生成成对余弦相似性sim(A_i,B_j)。(余弦相似矩阵也适用,因为它很容易从矩阵转换为成对矩阵。)


我为什么要寻求帮助
这看起来像是一个常见的问题,因为在计算生物学、推荐系统等领域需要计算这样的距离,但我还没有找到合理的解决方案

我解决不了的问题 根据定义,这个问题的复杂性是O(len_A*len_B*O(相似度函数)),所以A和B集合中的10^6个向量都会有巨大的运行时间

我对未来方向的设想 看起来,我们在这里做了很多无用的工作,因为相似性不是独立的(如果我们有一个a_i的相似性,计算了一百万个向量,b_j与a_i非常相似-我们有b_j的相似性,计算了900k个向量,我们可以估计b_j与其余100k个向量的相似性)。我假设这里可能会用到索引之类的东西



其他细节
  • A和B不相交
  • 向量维数已降低到最小合理值
  • 不需要简单的for循环优化。简单地说,这里是这个优化的简称,最简单的循环是为了清晰地说明一个算法
  • 我很感兴趣的是,是否有一种算法也可以进行估计,所以如果我们有足够的相似性,但与真实情况不完全相同,这也没关系
  • 并行化没有必要
  • 据我所知,生成的相似性矩阵的大小将很大
  • 我还感兴趣的是,这是否是一种算法,它只允许从集合B中为集合A中的每个向量获取顶级相似向量
  • 非常感谢您的参赛作品。


    代码示例
    要求 生成虚拟数据 相似性生成函数 产生相似性 使用

    注意,这里D是距离,I是值的索引

    此外,value1和value2只是NumPy数组

    PS:首先安装faiss

    pip install faiss
    
    使用

    注意,这里D是距离,I是值的索引

    此外,value1和value2只是NumPy数组

    PS:首先安装faiss

    pip install faiss
    
    如何从欧几里得距离得到余弦相似性

    仅适用于顶部相似向量
    ,也是计算欧几里德距离的替代方法,特别是在只需要顶部相似向量而不需要整个相似矩阵的情况下

    用@Abhik Sarka提出的方法解决
    下面是我发布的确切问题的解决方案,使用@Abhik Sarkar提出的方法。要获得余弦相似性,请确保向量之前已归一化。 此解决方案还允许您根据需要生成尽可能多的相似性,而不是完整矩阵

    免责声明:解决方案的重点是可读性,而不是性能

    要求

    生成虚拟数据

    相似性生成函数

    产生相似性

    如何从欧几里得距离得到余弦相似性

    仅适用于顶部相似向量
    ,也是计算欧几里德距离的替代方法,特别是在只需要顶部相似向量而不需要整个相似矩阵的情况下

    用@Abhik Sarka提出的方法解决
    下面是我发布的确切问题的解决方案,使用@Abhik Sarkar提出的方法。要获得余弦相似性,请确保向量之前已归一化。 此解决方案还允许您根据需要生成尽可能多的相似性,而不是完整矩阵

    免责声明:解决方案的重点是可读性,而不是性能

    要求

    生成虚拟数据

    相似性生成函数

    产生相似性


    你需要相似性矩阵吗?一般来说-是的。我喜欢你的问题,我只是想提醒你,除了运行时间,你可能会遇到另一个问题。每组10^6个向量表示一个包含10^12个条目的相似矩阵。每个条目由64位的浮点表示,这意味着要存储矩阵,您将需要大约8 TB!也许你可以优化它(对称,对角线=1),但它的大小仍然很大。@Tinu谢谢你的评论。好提示。我了解这个问题,并且已经有了合适的存储空间。不幸的是,我还没有找到一个合适的替代方法来生成相似矩阵,这是一个罕见的情况:)-这就是为什么我一直在努力解决这个问题。实际上我错了-因为对于大多数算法,所有的矩阵都应该适合ram(而不是我预期的rom)。所以@Tinu的评论更有帮助,我只是无法理解:)你需要相似性矩阵吗?一般来说-是的。我喜欢你的问题,我只是想提醒你,除了运行时间,你可能会遇到另一个问题。每组10^6个向量表示一个包含10^12个条目的相似矩阵。每个条目由64位的浮点表示,这意味着要存储矩阵,您将需要大约8 TB!也许你可以优化它(对称,对角线=1),但它的大小仍然很大。@Tinu谢谢你的评论。好提示。我了解这个问题,并且已经有了合适的存储空间。不幸的是,我还没有找到一个合适的替代方法来生成相似矩阵,这是一个罕见的情况:)-这就是为什么我一直在努力解决这个问题。实际上我错了-因为对于大多数算法,所有的矩阵都应该适合ram(而不是我预期的rom)。所以@Tinu的评论更有帮助,我只是无法理解:)非常感谢你的回答。据我所见,它看起来
    def get_similarities(df_1: pd.DataFrame, df_2: pd.DataFrame, meaningful_features:list) -> pd.DataFrame:
        '''
        This function generates features based similarity scores, between two groups of objects
        
        Parameters
        ----------
        df_1: pandas.DataFrame
            DataFrame with features, and id_s of objects
        df_2: pandas.DataFrame
            DataFrame with features, and id_s of objects which has no id_s same to df_1
        meaningful_features: list
            Features columns to calculate similarity on
            
        Returns
        ----------
            similarities_of_objects: pandas.DataFrame
                DataFrame, with columns 'object_id_1', 'object_id_2', 'similarity', 
                where we have features similarity, for each object_1-object_2 pair. 
                Similarity - symmetric.  
        '''
    
        objects_1 = [] #  list of all objects from df_1
        objects_2 = [] #  list of all objects from df_2
        similarities = [] #  list of scores for object_1-object_2 pairs
    
        for object_1 in df_1['object_id_1'].unique():
            features_vector_1 = df_1[df_1['object_id_1'] == object_1][meaningful_features] # object_1 features vector
            
            for object_2 in df_2['object_id_2'].unique():
                features_vector_2 = df_2[df_2['object_id_2'] == object_2][meaningful_features] # object_2 features vector
                
                objects_1.append(object_1)
                objects_2.append(object_2)
                similarities.append(cosine_similarity(X = np.array(features_vector_1)
                                        ,Y = np.array(features_vector_2)).item()) # similarities of vectors 
        
        sim_o1_to_o2 = pd.DataFrame()
    
        sim_o1_to_o2['objects_1']= objects_1
        sim_o1_to_o2['objects_2']= objects_2
        sim_o1_to_o2['similarity']= similarities
    
        return sim_o1_to_o2
    
    get_similarities(df_1,df_2, ['feature_0', 'feature_1', 'feature_2'])
    
    import faiss
    
    dimension = 100
    
    value1 = np.random.random((n, dimension)).astype('float32')
    index = faiss.IndexFlatL2(d)
    index.add(value1)
    
    xq = value2
    k= len(value1)
    D, I = index.search(xq, k) 
    
    pip install faiss
    
    python==3.6
    pandas==0.25.0
    numpy==1.17.1
    faiss==1.5.3 
    
    import pandas as pd
    import numpy as np
    import faiss 
    
    df_1 = pd.DataFrame({'object_id_1': range(10),
                       'feature_0': np.random.uniform(0,1,10),
                       'feature_1': np.random.uniform(0,1,10),
                       'feature_2': np.random.uniform(0,1,10),
                       'feature_3':np.random.uniform(0,1,10)})
    
    df_2 = pd.DataFrame({'object_id_2': range(10,20),
                       'feature_0': np.random.uniform(0,1,10),
                       'feature_1': np.random.uniform(0,1,10),
                       'feature_2': np.random.uniform(0,1,10),
                       'feature_3':np.random.uniform(0,1,10)})
    
    def get_similarities(df_1: pd.DataFrame, 
                         df_2: pd.DataFrame, 
                         meaningful_features:list, 
                         n_neighbors:int = df_2.shape[0])->pd.DataFrame:
        '''
        This function generates features based similarity scores, between to groups of reviews
        
        Parameters
        ----------
        df_1: pandas.DataFrame
            DataFrame with features, and id_s of objects
        df_2: pandas.DataFrame
            DataFrame with features, and id_s of objects which has no id_s same to df_1
        meaningful_features: list
            Features columns to calculate similarity on
        n_neighbors: int
            Number of most similar objects_2 for every object_1. By default - full similarity matrix generated.
            (default = df_2.shape[0]) 
        
        Returns
        ----------
            similarities_of_objects: pandas.DataFrame
                DataFrame, with columns 'object_id_1', 'object_id_2', 'similarity', 
                where we have features similarity, for each object_1-object_2 pair. 
                Similarity - symmetric.  
        '''
        d = len(meaningful_features) #  dimensionality
        
        res = np.empty(shape=[1, 3]) #  res initialization
        
        xb = np.float32(df_1[meaningful_features].values)
        xb = np.ascontiguousarray(xb)
        
        xq = np.float32(df_2[meaningful_features].values)
        xq = np.ascontiguousarray(xq)
    
        index = faiss.IndexFlatL2(d) #  build the index
        index.add(xb)                #  add vectors to the index
        
        D, I = index.search(xq, n_neighbors)     # actual search
        
        for i in range(I.shape[0]): 
            object_id_1_v = [df_1["object_id_1"].iloc[i]]*n_neighbors
            object_id_2_v = df_2["object_id_2"].iloc[I[i]]
            similarities = 1-D[i]/2
            
            neighbors_scores_for_target = np.stack((object_id_1_v, object_id_2_v, similarities), axis=-1)
            res = np.concatenate((res, neighbors_scores_for_target))
            
        res = res[1:] #  remove line we've created during res initialization
        
        resulting_df = pd.DataFrame({'object_id_1': res[:, 0], 
                                     'object_id_2': res[:, 1],
                                     'similarity':  res[:, 2] })
    
        
        return resulting_df
    
    get_similarities(df_1,df_2, ['feature_0', 'feature_1', 'feature_2'])