0

由于 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

4 回答 4

3

根据您的“数组”的表示,看起来您正在使用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,:]

所以,我们只需要遍历 和 的所有X组合Y。这正是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,:)——这很容易,我们已经(X,Y)从 indices_generator 获取——我们只需要添加一个 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。

于 2013-01-30T02:15:15.063 回答
1

查看itertools文档中的食谱。有一些功能可以完全满足您的需求flattenunique_everseen

因此,您可以复制和粘贴它们。或者你也可以pip install more-itertools只导入它们。unique_everseen现在,您可以将 3D 阵列展平为 2D,并使用……使 2D 阵列唯一化。

除了一个问题。二维数组的元素是lists,它们不可散列,因此您必须将它们转换为可散列的元素。但这很容易:

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

而已。

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

事实上,如果您不需要保留顺序,它甚至更简单:

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]

那是你想要的吗?

如果你想要它作为s 的一个listlist那就是:

array2d = list(uniquify(array3d))

如果您使用简单的set而不是 s unique_everseen,这些将是tuples 而不是lists,因此如果您需要 a listof lists:

array2d = [list(val) for val in uniquify(array3d)]
于 2013-01-30T02:21:21.597 回答
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以获得唯一的。

于 2013-01-30T02:10:36.257 回答
0

假设pythonlist看起来像[[[1,2,3], [4,5,6]], [[7,8,9]]](即a listof listsintegers

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)

如果您随后特别需要 a list,则可以将其转换为:items = list(items)

Aset是类似于 a 的数据类型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]]
于 2013-01-30T02:14:59.297 回答