【问题标题】:Reduce the time complexity while populating data into a matrix python在将数据填充到矩阵 python 时降低时间复杂度
【发布时间】:2021-12-21 20:44:28
【问题描述】:

我有一个 core_df 数据框。每一行都必须与其他行进行比较,结果必须存储在矩阵中。条件是如果开始或结束节点不匹配,或者长度比小于 0.2,则必须填充 0,否则必须填充一些值(比如 100)。 问题是数据框可能很大。它可以产生数百万条记录。 我为节省内存所做的是:

  • 初始化稀疏 dok 矩阵
  • 仅在上部诊断矩阵中填充值(因为它将是下部的镜像)
  • 更改了矩阵的数据类型,使其消耗更少的字节。 欢迎任何其他改进内存分配的建议。

我已经尝试了下面的代码,虽然它正在返回结果,但它在大型数据集上花费了大量时间。有没有办法优化时间复杂度?

import pandas as pd
import scipy
from scipy.sparse import dok_matrix
core_df = pd.DataFrame({'sno':[1,2,3,4],'start':[1,3,5,5],'end':[5,14,17,27],'start_elements':[('A', 'B'),('X','Y'),('B', 'C'),('B', 'C')],'end_elements':[('L', 'M'),('S', 'T'),('N', 'P'),('N', 'P')]})
 
core_df_count=len(core_df)    
Score_matrix = dok_matrix((core_df_count, core_df_count))

for i in range(0, core_df_count):
    start1 = core_df.iloc[i, 1]
    end1 = core_df.iloc[i, 2]
    Start_elements1 = core_df.iloc[i, 3]
    End_elements1 = core_df.iloc[i, 4]

    for j in range(i + 1, core_df_count):
        start2 = core_df.iloc[j, 1]
        end2 = core_df.iloc[j, 2]
        Start_elements2 = core_df.iloc[j, 3]
        End_elements2 = core_df.iloc[j, 4]

        if Start_elements1 != Start_elements2 or End_elements1 != End_elements2:
            Score_matrix[i, j] = 0

        else:
            ratio = (end1 - start1) / (end2 - start2)
            if ratio <0.2:
                Score_matrix[i, j] = 0
            else:
                Score_matrix[i,j]=100
Score_matrix_2D = pd.DataFrame(Score_matrix.todense())
Score_matrix_2D 

【问题讨论】:

    标签: python performance for-loop list-comprehension sparse-matrix


    【解决方案1】:
    1. 首先我根据start_elements & end_elements 对 df 进行分组,然后只搜索这些
    2. 在每个组中,我计算长度并制作密集矩阵来比较长度(比率)。
    3. 我搜索 df 指数比率 >= 0.2
    4. 我没有将 0 分配给稀疏矩阵,只有 100 才是必要的。默认处处为0
    import numpy as np
    import pandas as pd
    from scipy.sparse import dok_matrix
    
    core_df = pd.DataFrame({'sno': [1, 2, 3, 4], 'start': [1, 3, 5, 5], 'end': [5, 14, 17, 27],
                            'start_elements': [('A', 'B'), ('X', 'Y'), ('B', 'C'), ('B', 'C')],
                            'end_elements': [('L', 'M'), ('S', 'T'), ('N', 'P'), ('N', 'P')]})
    
    core_df_count = len(core_df)
    Score_matrix = dok_matrix((core_df_count, core_df_count))
    core_df_values = core_df.values
    
    for (start_elements, end_elements), group_df in core_df.groupby(['start_elements', 'end_elements']):
        lengths = (group_df['end'] - group_df['start']).values
        ratios = np.divide.outer(lengths, lengths)
        # I guess we should not take into account diagonal, so adding this:
        ratios[np.arange(len(ratios)), np.arange(len(ratios))] = 0
        where_is_above_threshold = np.where(ratios >= 0.2)
        row_indices = group_df.index[where_is_above_threshold[0]]
        column_indices = group_df.index[where_is_above_threshold[1]]
        Score_matrix[row_indices, column_indices] = 100
    
    Score_matrix_2D = pd.DataFrame(Score_matrix.todense())
    print(Score_matrix_2D)
    
         0    1      2      3
    0  0.0  0.0    0.0    0.0
    1  0.0  0.0    0.0    0.0
    2  0.0  0.0    0.0  100.0
    3  0.0  0.0  100.0    0.0
    

    【讨论】:

    • 嘿,非常感谢您的好主意。几个问题,1)我必须在最后一个 else 部分(Score_matrix[i,j]=100)执行的实际操作是 Score_matrix[i,j]= np.dot(sample_df[i,:].data, sample_df [j,:].data) 。 sample_df 的编号相同。作为 core_df 的行数。我如何在这段代码中适应它。另外,如何使包括诊断在内的较低训练矩阵为零?
    • @AB6 提出问题然后更改可能需要对答案进行重大更改的部分代码是不合适的。您应该在问题中包含此 np.dot 操作。您可以通过过滤where_is_above_threshold 使下三角矩阵为零(通过在下三角部分写入任何内容)
    • 好的.. 非常感谢您的帮助。
    • ratios = np.divide.outer(lengths, lengths) 当数据量很大时会引发内存问题。尝试对 dok 矩阵做同样的事情,有什么解决方法吗?
    • @AB6 它可以进行内存优化,通过对lengths 的数组进行排序,并为每个长度搜索具有我们想要的比率的其他长度的跨度。但我担心这可能会导致Score_matrix 中的内存问题。
    猜你喜欢
    • 2011-06-15
    • 1970-01-01
    • 2012-07-28
    • 2016-10-07
    • 1970-01-01
    • 2016-03-18
    • 2020-09-15
    • 1970-01-01
    相关资源
    最近更新 更多