如何在Python中将数组简化为唯一值

时间:2013-01-30 02:06:26

标签: php python arrays numpy

由于PHP中的数组深度问题,从Python接收此数组会被删除省略号(“...”)。我想在返回php之前用Python处理数组。

澄清:我需要保持内部集[135,121,81]。这些是R,G,B值,我与多次出现的组合在一起。集合中的值需要维持[1,2,3]序列,而不是[1,2,3,4,5,6,7,8],如下面的一些答案所示。

您如何将此3D numpy.ndarray简化为一系列独特的RGB三元组?

以下是Python如何打印数组:

[[[135 121  81]
  [135 121  81]
  [135 121  81]
  ..., 
  [135 121  81]
  [135 121  81]
  [135 121  81]]

 [[135 121  81]
  [135 121  81]
  [135 121  81]
  ..., 
  [135 121  81]
  [135 121  81]
  [135 121  81]]

 [[ 67  68  29]
  [135 121  81]
  [ 67  68  29]
  ..., 
  [135 121  81]
  [135 121  81]
  [135 121  81]]

 ..., 
 [[200 170  19]
  [200 170  19]
  [200 170  19]
  ..., 
  [ 67  68  29]
  [ 67  68  29]
  [ 67  68  29]]

 [[200 170  19]
  [200 170  19]
  [200 170  19]
  ..., 
  [116 146  15]
  [116 146  15]
  [116 146  15]]

 [[200 170  19]
  [200 170  19]
  [200 170  19]
  ..., 
  [116 146  15]
  [116 146  15]
  [116 146  15]]]

以下是我尝试过的代码:

def uniquify(arr)
    keys = []

    for c in arr:
        if not c in keys:
            keys[c] = 1
        else:
            keys[c] += 1

    return keys

result = uniquify(items)

4 个答案:

答案 0 :(得分:2)

根据您的“数组”的表示,看起来您正在使用numpy.ndarray。如果是这种情况,这就变成了一个非常简单的问题 - 您可以使用.flat属性转换为一维可迭代的简单。要使其独一无二,您只需使用set

即可
set(array.flat)

这会给你一套,但你可以很容易地从中得到一个列表:

list(set(array.flat))

以下是它的工作原理:

>>> array = np.zeros((10,12,42,53))
>>> list(set(array.flat))
[0.0]

作为旁注,还有np.unique,它也会为您提供阵列的独特元素。

>>> array = np.zeros((10,12),dtype=int)
>>> print array
[[0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0]]
>>> np.unique(array)
array([0])
>>> array[0,5] = 1
>>> array[4,10] = 42
>>> np.unique(array)
array([ 0,  1, 42])

我想我终于找到了这个:

from itertools import product

items = set(tuple(a[itr+(slice(None),)]) for itr in product(*[range(x) for x in a.shape[:-1]]))
print items

似乎工作。呼!

这是如何工作的 - 您想要保存为三元组的部分可以访问:

array[X,Y,:]

因此,我们只需要遍历XY的所有组合。这正是itertools.product的好处。我们可以在任意数量的维度中获得有效的XY

[range(x) for x in array.shape[:-1]]

所以我们将其传递给产品:

indices_generator = product(*[range(x) for x in array.shape[:-1]])

现在我们有了一些能够生成第一个索引的东西 - 我们只需要构造一个元组来传递给__getitem__ numpy将其解释为(X,Y,:) - 这很简单,我们已经从indices_generator获取(X,Y) - 我们只需要处理一个emtpy切片:

all_items = ( array[idx+(slice(None),)] for idx in indices_generator )

现在我们可以循环遍历all_items,寻找具有集合的唯一的:

unique_items = set(tuple(item) for item in all_items)

现在把它转回一个列表,或一个numpy数组或任何你想要的东西,以便将它传回PHP。

答案 1 :(得分:1)

查看itertools文档中的食谱。有flattenunique_everseen函数完全符合您的要求。

因此,您可以复制并粘贴它们。或者您只需pip install more-itertools即可导入它们。现在,您可以将3D数组展平为2D,并使用unique_everseen ...

来统一2D数组。

除了一个问题。 2D数组的元素是list s,它们是不可清除的,因此您必须将它们转换为可哈希的东西。但这很容易:

def uniquify(arr3d):
    return unique_everseen(flatten(arr3d), tuple)

就是这样。

如果你在粘贴它们时查看这些函数的实现,它们就非常简单了。这里唯一真正的技巧是使用set来保存到目前为止看到的值:sets只保存每个唯一元素的一个副本(并且可以非常快速地确定元素是否已经存在于集合中)。

事实上,如果你不需要保留订单,那就更简单了:

def uniquify(arr3d):
    return set(tuple(x) for x in flatten(arr3d))

作为测试,我复制了你的字符串并将其转换为实际的Python列表显示,然后执行了此操作:

inarray = [[[135, 121, 81],
            [135, 121, 81],
            [135, 121, 81],
            [135, 121, 81],
            [135, 121, 81],
            [135, 121, 81]],
           [[135, 121, 81],
            [135, 121, 81],
            [135, 121, 81],
            [135, 121, 81],
            [135, 121, 81],
            [135, 121, 81]],
           [[67, 68, 29],
            [135, 121, 81],
            [67, 68, 29],
            [135, 121, 81],
            [135, 121, 81],
            [135, 121, 81]],
           [[200, 170, 19],
            [200, 170, 19],
            [200, 170, 19],
            [67, 68, 29],
            [67, 68, 29],
            [67, 68, 29]],
           [[200, 170, 19],
            [200, 170, 19],
            [200, 170, 19],
            [116, 146, 15],
            [116, 146, 15],
            [116, 146, 15]],
           [[200, 170, 19],
            [200, 170, 19],
            [200, 170, 19],
            [116, 146, 15],
            [116, 146, 15],
            [116, 146, 15]]]
for val in uniquify(inarray):
    print(val)

输出结果为:

[135, 121, 81]
[67, 68, 29]
[200, 170, 19]
[116, 146, 15]

这就是你想要的吗?

如果您想将其作为list的{​​{1}},那就是:

list

如果您使用的是简单的array2d = list(uniquify(array3d)) 而不是set,那么这些将是unique_everseen而不是tuple,因此如果您需要list } list s:

list

答案 2 :(得分:0)

itertools是你的朋友:

>>> import itertools
>>> array = [1,1,1,2,2,2,3,3,3,4,5,6,6,6]
>>> [x[0] for x in itertools.groupby(array)]
[1, 2, 3, 4, 5, 6]

例如:

array = [[[135,121,81],
          [135,121,81],
          [135,121,81],
          [135,121,81],
          [135,121,81],
          [135,121,81]],
         [[135,121,81],
          [135,121,81],
          [135,121,81],
          [135,121,81],
          [135,121,81],
          [135,121,81]],
         [[67,68,29],
          [135,121,81],
          [67,68,29],
          [135,121,81],
          [135,121,81],
          [135,121,81]]]

import itertools

new_array = list()
for inner in array:
    new_inner = [x[0] for x in itertools.groupby(inner)]
    new_array.append(new_inner)

产地:

[ [ [135, 121, 81] ], 
  [ [135, 121, 81] ],
  [ [67, 68, 29],
    [135, 121, 81],
    [67, 68, 29],
    [135, 121, 81] ] ]

不完全独特,但您可以将inner排序为唯一。

答案 3 :(得分:0)

假设python list看起来像[[[1,2,3], [4,5,6]], [[7,8,9]]](即list list integers mylist = [[[1,2,3], [4,5,6]], [[7,8,9]]] items = set() for sublist in mylist: for subsublist in sublist: for item in subsublist: items.add(item)

list

如果您特别需要items = list(items),则可以将其投射为:set

list是一种类似于set的数据类型,但不包含重复项。 mylist = [[[1,2,3], [4,5,6]], [[7,8,9]]] items = [] for sublist in mylist: for subsublist in sublist: for item in subsublist: if not item in items: items.add(item) 数据类型的副作用是不保留插入顺序 - 如果这对您很重要,则需要以下内容:

mylist = [[[1,2,3], [4,5,6]], [[7,8,9], [1,2,3]]]
items = []
for sublist in mylist:
    for item in sublist:
        if not item in items:
            items.append(item)
# items = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

编辑:根据你的编辑,你可能想要这个:

{{1}}