Numpy:分区指标

时间:2017-01-20 21:11:29

标签: python arrays performance numpy

我试图在Python中表示数字0到n-1的分区

我有一个numpy数组,其中第i个条目表示数字i的分区ID。例如,numpy数组

indicator = array([1, 1, 3, 0, 2, 3, 0, 0])

表示数字3,6和7属于ID为0的分区。数字0和1属于分区1. 4属于分区2.而2和5属于分区3.我们称之为指标表示。

表示分区的另一种方式是列表,其中第i个列表是ID为i的分区。对于上面的数组,这将映射到

explicit = [[3, 6, 7], [0, 1], [4], [2, 5]]

我们称之为显式表示。

我的问题是将指标表示转换为显式表示的最有效方法是什么?天真的方法是迭代指标数组并将元素分配到显式的各自的插槽中数组,但迭代numpy数组是低效的。 是否有更自然的numpy结构?

2 个答案:

答案 0 :(得分:1)

以下是仅使用numpy(无indicator循环,列表推导,itertools等)将explicit转换为for的解决方案 我没有看到你的基于迭代的方法,所以我无法比较它们,但也许你可以告诉我它是否足够快以满足你的需求:)

import numpy as np
indicator = np.array([1, 1, 3, 0, 2, 3, 0, 0])
explicit = [[3, 6, 7], [0, 1], [4], [2, 5]]

def from_ind_to_expl(indicator):
    groups, group_sizes = np.unique(indicator, return_counts=True)
    group_sizes = np.cumsum(group_sizes)
    ordered = np.where(indicator==groups[:, np.newaxis])
    return np.hsplit(ordered[1], group_sizes[:-1])

from_ind_to_expl(indicator)给出了

[array([3, 6, 7]), array([0, 1]), array([4]), array([2, 5])]

我还比较了@Divakar和我的解决方案的时间。在我的机器上@Divakar的解决方案比我的快2-3倍。所以@Divakar绝对得到了我的支持:)

在@Divakar的帖子的最后比较中,我的解决方案没有平均值,因为只有一个循环 - 这有点不公平:P;)

答案 1 :(得分:1)

这是一种使用排序索引然后将它们分组的方法 -

<!DOCTYPE html>
<html >
<head>
  <meta charset="UTF-8">
  <title>Random title</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  
  <link rel="stylesheet" href="css/style.css">
  <link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet"> 

  
</head>

<body>

<section>
  <div class="header-wrapper">
    <h1>Just some random text</h1>
  </div>
</section>


<section id="menu2">
  <div class="navigation">
    <nav>
    <a href="" id="home">Home</a>
    <a href="" id="menu2" style="background-color:honeydew">Menu 2</a>
    <a href="" id="menu3" style="background-color:lightblue">Menu 3</a>
    <a href="" id="menu4" style="background-color:red">Menu 4</a>
    <a href="" id="menu5" style="background-color:yellow">Menu 5</a>
  </nav>
  <img src="http://placehold.it/200x70" alt="Logo" id="logo">
</div>
</section>

<section id="menu3">
  <div class="text-boxes">
    <img src="images/slider-buttons/typography/typography-icon.jpg">
  </div>
</section>

<section id="menu4">
  <div class="picture-boxes">
  <p>parapap</p>
  </div>
</section>


</body>
</html>

运行时测试 -

def indicator_to_part(indicator):
    sidx = indicator.argsort() # indicator.argsort(kind='mergesort') keeps order
    sorted_arr = indicator[sidx]
    split_idx = np.nonzero(sorted_arr[1:] != sorted_arr[:-1])[0]
    return np.split(sidx, split_idx+1)

请注意,输出将是数组列表。如果必须将列表列表作为输出,一种简单的方法是使用In [326]: indicator = np.random.randint(0,100,(10000)) In [327]: %timeit from_ind_to_expl(indicator) #@yogabonito's soln 100 loops, best of 3: 5.59 ms per loop In [328]: %timeit indicator_to_part(indicator) 1000 loops, best of 3: 801 µs per loop In [330]: indicator = np.random.randint(0,1000,(100000)) In [331]: %timeit from_ind_to_expl(indicator) #@yogabonito's soln 1 loops, best of 3: 494 ms per loop In [332]: %timeit indicator_to_part(indicator) 100 loops, best of 3: 11.1 ms per loop 。同样,一个高性能的替代方案将涉及更多的步骤,如此 -

map(list,indicator_to_part(indicator))