如何使用矢量化基于最小行值拆分数组

时间:2016-11-20 06:41:43

标签: python numpy

我试图弄清楚如何采用以下for循环,根据行中最低值的索引拆分数组并使用向量化。我看过这个link并且一直在尝试使用numpy.where函数,但目前还不成功。

例如,如果一个数组有 n 列,那么 col [0] 具有最低值的所有行都放在一个数组中,所有行都在哪里< em> col [1] 被放入另一个等等。

这是使用for循环的代码。

import numpy

a = numpy.array([[ 0.  1.  3.]
                 [ 0.  1.  3.]
                 [ 0.  1.  3.]
                 [ 1.  0.  2.]
                 [ 1.  0.  2.]
                 [ 1.  0.  2.]
                 [ 3.  1.  0.]
                 [ 3.  1.  0.]
                 [ 3.  1.  0.]])

result_0 = []
result_1 = []
result_2 = []
for value in a:
    if value[0] <= value[1] and value[0] <= value[2]:
        result_0.append(value)
    elif value[1] <= value[0] and value[1] <= value[2]:
        result_1.append(value)
    else:
        result_2.append(value)

print(result_0)
>>[array([ 0.  1.  3.]), array([ 0.  1.  3.]), array([ 0.  1.  3.])]
print(result_1)
>>[array([ 1.  0.  2.]), array([ 1.  0.  2.]), array([ 1.  0.  2.])]
print(result_2)
>>[array([ 3.  1.  0.]), array([ 3.  1.  0.]), array([ 3.  1.  0.])]

3 个答案:

答案 0 :(得分:1)

首先,使用argsort查看每行中最低值的位置:

>>> a.argsort(axis=1)

array([[0, 1, 2],
       [0, 1, 2],
       [0, 1, 2],
       [1, 0, 2],
       [1, 0, 2],
       [1, 0, 2],
       [2, 1, 0],
       [2, 1, 0],
       [2, 1, 0]])

请注意,只要行有0,就是该行中的最小列。

现在您可以构建结果:

>>> sortidx = a.argsort(axis=1)
>>> [a[sortidx[:,i] == 0] for i in range(a.shape[1])]

[array([[ 0.,  1.,  3.],
        [ 0.,  1.,  3.],
        [ 0.,  1.,  3.]]),
 array([[ 1.,  0.,  2.],
        [ 1.,  0.,  2.],
        [ 1.,  0.,  2.]]),
 array([[ 3.,  1.,  0.],
        [ 3.,  1.,  0.],
        [ 3.,  1.,  0.]])]

因此,只需在列上使用一个循环即可完成,如果行数远远大于列数,则会产生巨大的加速。

答案 1 :(得分:0)

这不是最好的解决方案,因为它依赖于简单的python循环,并且在你开始处理大型数据集时效率不高但它应该让你开始。

重点是创建一个&#34;桶的数组&#34;它根据最长元素的深度存储数据。然后枚举values中的每个元素,选择最小的元素并保存其偏移量,随后将其附加到每个a的正确结果&#34; bucket&#34;。最后,我们在最后一个循环中打印出来。

使用循环解决方案

import numpy
import pprint

# random data set
a = numpy.array([[0,  1,  3],
                 [0,  1,  3],
                 [0,  1,  3],
                 [1,  0,  2],
                 [1,  0,  2],
                 [1,  0,  2],
                 [3,  1,  0],
                 [3,  1,  0],
                 [3,  1,  0]])

# create a list of results as big as the depth of elements in an entry
results = list()
for l in range(max(len(i) for i in a)):
    results.append(list())
# don't do the following because all the references to the lists will be the same and you get dups:
# results = [[]]*max(len(i) for i in a)

for value in a:
    res_offset, _val = min(enumerate(value), key=lambda x: x[1])  # get the offset and min value
    results[res_offset].append(value)  # store the original Array obj in the correct "bucket"

# print for visualization
for c, r in enumerate(results):
    print("result_%s: %s" % (c, r))

输出:

  

result_0:[array([0,1,3]),array([0,1,3]),array([0,1,3])]
  result_1:[array([1,0,2]),array([1,0,2]),array([1,0,2])]

  result_2:[array([3,1,0]),array([3,1,0]),array([3,1,0])]

答案 2 :(得分:0)

我找到了一种更简单的方法。我希望我正确地解释OP。

我的感觉是OP想要根据一些条件创建一个较大阵列的片段。

请注意,上面创建数组的代码似乎不起作用 - 至少在python 3.5中。我按如下方式生成了数组。

 a = np.array([0., 1., 3., 0., 1., 3., 0., 1., 3., 1., 0., 2., 1., 0., 2.,1., 0., 2.,3., 1., 0.,3., 1., 0.,3., 1., 0.]).reshape([9,3])

接下来,我将原始数组切成较小的数组。 Numpy已经内置了帮助。

 result_0 = a[np.logical_and(a[:,0] <= a[:,1],a[:,0] <= a[:,2])]
 result_1 = a[np.logical_and(a[:,1] <= a[:,0],a[:,1] <= a[:,2])]
 result_2 = a[np.logical_and(a[:,2] <= a[:,0],a[:,2] <= a[:,1])]

这将生成符合给定条件的新numpy数组。

请注意,如果用户想要将这些单独的行转换为列表或数组,他/她只需输入以下代码即可获得结果。

 result_0 = [np.array(x) for x in result_0.tolist()]
 result_0 = [np.array(x) for x in result_1.tolist()]
 result_0 = [np.array(x) for x in result_2.tolist()]

这应该产生OP中要求的结果。