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

使嵌套循环运行得更快,例如通过Python中的矢量化

使嵌套循环运行得更快,例如通过Python中的矢量化,python,performance,vectorization,Python,Performance,Vectorization,我有一个2*N整数数组ids表示间隔,其中N大约是一百万。看起来像这样 0 2 1 ... 3 4 3 ... 数组中的整数可以是0,1,M-1,其中M避开for循环,仅为一个样本 将numpy导入为np 作为pd进口熊猫 df=pd.DataFrame({ “A”:np.random.randint(0,100100000), “B”:np.random.randint(0,100100000) }) df.groupby(“B”)[“A”].agg(列表) 您可以尝试下面的选项,在该选

我有一个2*N整数数组
ids
表示间隔,其中N大约是一百万。看起来像这样

 0 2 1 ...
 3 4 3 ...

数组中的整数可以是0,1,M-1,其中M避开for循环,仅为一个样本

将numpy导入为np
作为pd进口熊猫
df=pd.DataFrame({
“A”:np.random.randint(0,100100000),
“B”:np.random.randint(0,100100000)
})
df.groupby(“B”)[“A”].agg(列表)

您可以尝试下面的选项,在该选项中,您的外部循环隐藏在numpy的C语言实现的
沿轴应用()。不确定性能优势,只有适当规模的测试才能说明(特别是在将列表转换为numpy数组时会涉及一些初始开销):

输出:

{0:array('I',[0]),1:array('I',[0,2]),2:array('I',[0,1,2]), 3:数组('I',[1])}

编辑:

我觉得在这里使用字典可能不是个好主意。我怀疑在这个特定的上下文中,字典索引实际上可能比
numpy
数组索引慢。使用以下行创建并初始化
inv
作为Python数组的
numpy
数组。代码的其余部分可以保持原样:

inv_len = np.max(ids_arr)
inv = np.empty(shape=(inv_len,), dtype=array.array)
for i in range(inv_len):
    inv[i] = array.array('I')

注意:这假设您的应用程序没有在
inv
上执行
dict
-特定的操作,例如
inv.items()
inv.keys()
。但是,如果是这种情况,您可能需要额外的步骤将numpy数组转换为
dict

,因为
N
的顺序很大,我想出了一个看似实用的方法;如果有任何缺陷,请告诉我

  • 对于第i个
    间隔
    [x,y]
    ,将其存储为
    [x,y,i]
    。根据阵列的开始和结束时间对阵列进行排序。这应该需要O(NlogN)时间
  • 创建频率阵列
    freq[2*N+1]
    。对于每个间隔,使用的概念更新频率。在O(N)中生成频率
  • 根据您的数据确定阈值。根据该值,可以将元素指定为稀疏或频繁。对于稀疏元素,不执行任何操作。仅对于频繁元素,存储它们发生的间隔
  • 在查找过程中,如果存在频繁元素,则可以直接访问预先计算的列表。如果元素是稀疏元素,则可以在O(logN)时间内搜索间隔,因为在步骤1中对间隔进行了排序,并附加了索引

  • 这对我来说似乎是一个实用的方法,其余的取决于你的使用。如每个查询所需的摊销时间复杂度等。

    如果有一个列表,其中每个间隔为(0,2*N-1),并且有N个这样的间隔,那么复杂度将为O(N^2)。如何进一步降低复杂性?这似乎是最糟糕的情况。不知道如何解决这个O(N*2)问题。考虑到N大约是一百万,O(N*2)确实是一个大问题。为什么需要这个逆映射呢?这应该决定我们是否可以在这个问题上解决一些问题case@AbhinavMathur我需要把这个逆映射作为一种查找表。计算映射处于预处理步骤中,但不应太慢。这回答了你的问题吗?@AbhinavMathur。反向查找将允许我以后的应用程序快速知道哪些间隔将包含特定点。通过“直觉”部分的例子,我需要知道哪一个区间覆盖了一个点,比如说2。这可以称为区间点问题:给定一组区间和一个点,知道哪些区间包含该点。我本可以使用范围树或分段树来实现这一点,但我希望建立一个查找表,以便以后能够非常快速地进行查找。谢谢你的提问。这是OP需要的吗?谢谢。这将如何替换我问题中的嵌套循环?首先,将原始数据转换为数据=[[0,0],[0,1],[0,2],…]之类的对列表;然后使df=pd.DataFrame(数据,列=[“A”,“B”])df.groupby(“B”)[“A”])agg(列表)谢谢。这种方法很优雅,但似乎存在内存问题。我有大约一百万个条目,每个条目都有一个范围[a,b],其中b-a大约是3000。通过你的方法,我得到了3*10^9个条目。在上面的示例中,我尝试了使用“10**9”,其中使用了100000,但由于内存不足(在16G笔记本电脑上),代码在运行几分钟后被删除。我们可以像你建议的那样使用h5py吗?谢谢!将列表转换为numpy数组的初始开销没有问题,因为它是作为numpy数组提供的。@zell-不客气。我刚刚在回答中添加了一个编辑,建议将
    inv
    作为Python数组的
    numpy
    数组,而不是作为Python数组的字典。谢谢!早些时候,我使用的是列表的numpy数组,但是有些人应该避免使用列表的numpy数组。看见你认为python数组的numpy数组有意义吗?尽管列表的numpy数组不符合链接要求?@zell-很高兴有了一些改进。你是坚持使用字典,还是用numpy数组替换它?还有一点需要注意:当您比较解决方案以选择更好的解决方案时,我希望您在备选解决方案中使用完全相同的数据——不仅是在
    id
    的大小方面,而且在其内容方面)。这是因为最终构造的
    inv
    的大小取决于
    ids
    的内容和长度,出于同样的原因,您可能还想通过改变
    ids
    的内容来重复测试,然后才能真正确定您的最终选择
    0 -> 0, 1, 2
    1 -> 2, 3
    2 -> 1, 2 
    
    0 -> 0
    1 -> 0, 2
    2 -> 0, 1, 2
    3 -> 1
    
      for i in range(ids.shape[1]):
        for j in range(ids[0][i], ids[1][i]):
            inv[j].append(i)
    
      for i in range(M):  inv[i]=array.array('I')
    
    import numpy as np
    import array
    
    ids = [[0,2,1],[3,4,3]]
    ids_arr = np.array(ids)   # Convert to numpy array. Expensive operation?
    
    range_index = 0   # Initialize. To be bumped up by each invocation of my_func()
    
    inv = {}
    for i in range(np.max(ids_arr)):
        inv[i] = array.array('I')
    
    def my_func(my_slice):
        global range_index
        for i in range(my_slice[0], my_slice[1]):
            inv[i].append(range_index)
        range_index += 1
    
    np.apply_along_axis (my_func,0,ids_arr)
    print (inv)
    
    inv_len = np.max(ids_arr)
    inv = np.empty(shape=(inv_len,), dtype=array.array)
    for i in range(inv_len):
        inv[i] = array.array('I')