从 numpy 结构化数组中删除重复值
Remove duplicate values from numpy structured array
我有一个结构化数组 v
例如
import numpy as np
v = np.zeros((3,3), [('a1', np.int),('a2', np.int), ('a3', np.int),
('a4', np.int), ('a5', np.int), ('a6', np.int)])
通常 v
会大得多,'a1'
,...,'a6'
值由其他例程计算。假设 v
是
>>> print v
[[(2, 0, 0, 0, 0, 1) (1, 0, 3, 2, 1, 2) (3, 1, 3, 0, 3, 1)]
[(1, 2, 1, 1, 0, 3) (3, 0, 3, 2, 3, 1) (1, 3, 1, 1, 3, 3)]
[(0, 2, 3, 3, 1, 1) (0, 1, 1, 1, 3, 0) (0, 3, 3, 3, 1, 0)]]
我需要从每个条目中删除重复项,并(可选地)对每个条目进行排序,以便在对 v
进行操作后,我有另一个数组看起来像
[[(0, 1, 2) (0, 1, 2, 3) (0, 1, 3)]
[(0, 1, 2, 3) (0, 1, 2, 3) (1, 3)]
[(0, 1, 2, 3) (0, 1, 3) (0, 1, 3)]]
我的预感是 numpy.unique
,但我无法实现。有什么想法吗?
像这样的东西怎么样:
v = np.array(
[[(2, 0, 0, 0, 0, 1), (1, 0, 3, 2, 1, 2), (3, 1, 3, 0, 3, 1)],
[(1, 2, 1, 1, 0, 3), (3, 0, 3, 2, 3, 1), (1, 3, 1, 1, 3, 3)],
[(0, 2, 3, 3, 1, 1), (0, 1, 1, 1, 3, 0), (0, 3, 3, 3, 1, 0)]])
def uniqueify(obj):
if isinstance(obj[0], np.ndarray):
return np.array([uniqueify(e) for e in obj])
else:
return np.unique(obj)
v2 = uniqueify(v)
print(v2)
输出:
[[array([0, 1, 2]) array([0, 1, 2, 3]) array([0, 1, 3])]
[array([0, 1, 2, 3]) array([0, 1, 2, 3]) array([1, 3])]
[array([0, 1, 2, 3]) array([0, 1, 3]) array([0, 1, 3])]]
注意:锯齿状数组可能很奇怪。如果您简单地创建 (python) 个数组列表,您的情况就差不多了,例如:
def uniqueify(obj):
if isinstance(obj[0], np.ndarray):
return [uniqueify(e) for e in obj]
else:
return np.unique(obj)
这通常产生相同的东西,但使用 python 列表来包含 numpy 数组:
[[array([0, 1, 2]), array([0, 1, 2, 3]), array([0, 1, 3])], [array([0, 1, 2, 3]), array([0, 1, 2, 3]), array([1, 3])], [array([0, 1, 2, 3]), array([0, 1, 3]), array([0, 1, 3])]]
或手动格式化:
[[array([0, 1, 2]), array([0, 1, 2, 3]), array([0, 1, 3])],
[array([0, 1, 2, 3]), array([0, 1, 2, 3]), array([1, 3])],
[array([0, 1, 2, 3]), array([0, 1, 3]), array([0, 1, 3])]]
set
的这种用法有效:
In [111]: np.array([tuple(set(i)) for i in v.ravel().tolist()]).reshape(3,3)
Out[111]:
array([[(0, 1, 2), (0, 1, 2, 3), (0, 1, 3)],
[(0, 1, 2, 3), (0, 1, 2, 3), (1, 3)],
[(0, 1, 2, 3), (0, 1, 3), (0, 1, 3)]], dtype=object)
我返回了一个二维元组数组(dtype 对象)。我没有保留结构化数组数据类型。我也可以返回集合数组或集合列表。
或者使用 tolist
嵌套的元组列表
In [112]: _.tolist()
Out[112]:
[[(0, 1, 2), (0, 1, 2, 3), (0, 1, 3)],
[(0, 1, 2, 3), (0, 1, 2, 3), (1, 3)],
[(0, 1, 2, 3), (0, 1, 3), (0, 1, 3)]]
我不需要原件tolist
;在 raveled 数组上迭代就足够了
In [115]: [set(i) for i in v.ravel()]
Out[115]:
[{0, 1, 2},
{0, 1, 2, 3},
{0, 1, 3},
{0, 1, 2, 3},
{0, 1, 2, 3},
{1, 3},
{0, 1, 2, 3},
{0, 1, 3},
{0, 1, 3}]
unique
给出同样的东西;我不能做 np.unique(i)
因为它试图处理整个 1 元素结构化数组:
In [117]: [np.unique(i.tolist()) for i in v.ravel()]
Out[117]:
[array([0, 1, 2]),
array([0, 1, 2, 3]),
array([0, 1, 3]),
array([0, 1, 2, 3]),
array([0, 1, 2, 3]),
array([1, 3]),
array([0, 1, 2, 3]),
array([0, 1, 3]),
array([0, 1, 3])]
=======================
这会将其转换为 3 维数组
在[134]中:v1=v.view(np.dtype('(6,)i4'))
In [135]: v1
Out[135]:
array([[[2, 0, 0, 0, 0, 1],
[1, 0, 3, 2, 1, 2],
[3, 1, 3, 0, 3, 1]],
[[1, 2, 1, 1, 0, 3],
[3, 0, 3, 2, 3, 1],
[1, 3, 1, 1, 3, 3]],
[[0, 2, 3, 3, 1, 1],
[0, 1, 1, 1, 3, 0],
[0, 3, 3, 3, 1, 0]]])
不过,我不确定这是否有帮助。将 unique
应用于最后一个维度与结构化形式存在相同的问题。
In [137]: [np.unique(i) for i in v1.reshape(-1,6)]
=====================
我在下面写的是一维结构化数组。这个例子是 2d。当然,它可以被展平并且所有适用。
我的第一个想法是将其转换为列表并将 set
应用于每个元组。这是一个结构化数组,因此 v.tolist()
将是一个元组列表。
我在 link 中的第一个建议是 Dan 发现的:
(重点在于计数;bincount
解决方案在这里无济于事。)。
[set(i) for i in v.tolist()]
您甚至可能不需要翻译它,但我必须对其进行测试。我不知道结构化记录是否可以作为 set
.
的参数
[set(i) for i in v]
不管结果将是一个不同长度的项目列表。它们是集合、列表还是数组并不重要。只有它们不会是结构化数组 - 除非我们付出额外的努力来确定哪些字段是唯一的。
由于字段都是相同的数据类型,因此很容易将其转换为二维数组。
v.view(int, 6) # 6 fields
应该可以解决问题(需要测试)。 (更正,将其转换为纯 int 数组并不像我想象的那么容易)。
np.unique
应该和 set
一样有效;但是我怀疑 set
对于 6 个值(或任何其他合理数量的字段)更快。
我有一个结构化数组 v
例如
import numpy as np
v = np.zeros((3,3), [('a1', np.int),('a2', np.int), ('a3', np.int),
('a4', np.int), ('a5', np.int), ('a6', np.int)])
通常 v
会大得多,'a1'
,...,'a6'
值由其他例程计算。假设 v
是
>>> print v
[[(2, 0, 0, 0, 0, 1) (1, 0, 3, 2, 1, 2) (3, 1, 3, 0, 3, 1)]
[(1, 2, 1, 1, 0, 3) (3, 0, 3, 2, 3, 1) (1, 3, 1, 1, 3, 3)]
[(0, 2, 3, 3, 1, 1) (0, 1, 1, 1, 3, 0) (0, 3, 3, 3, 1, 0)]]
我需要从每个条目中删除重复项,并(可选地)对每个条目进行排序,以便在对 v
进行操作后,我有另一个数组看起来像
[[(0, 1, 2) (0, 1, 2, 3) (0, 1, 3)]
[(0, 1, 2, 3) (0, 1, 2, 3) (1, 3)]
[(0, 1, 2, 3) (0, 1, 3) (0, 1, 3)]]
我的预感是 numpy.unique
,但我无法实现。有什么想法吗?
像这样的东西怎么样:
v = np.array(
[[(2, 0, 0, 0, 0, 1), (1, 0, 3, 2, 1, 2), (3, 1, 3, 0, 3, 1)],
[(1, 2, 1, 1, 0, 3), (3, 0, 3, 2, 3, 1), (1, 3, 1, 1, 3, 3)],
[(0, 2, 3, 3, 1, 1), (0, 1, 1, 1, 3, 0), (0, 3, 3, 3, 1, 0)]])
def uniqueify(obj):
if isinstance(obj[0], np.ndarray):
return np.array([uniqueify(e) for e in obj])
else:
return np.unique(obj)
v2 = uniqueify(v)
print(v2)
输出:
[[array([0, 1, 2]) array([0, 1, 2, 3]) array([0, 1, 3])]
[array([0, 1, 2, 3]) array([0, 1, 2, 3]) array([1, 3])]
[array([0, 1, 2, 3]) array([0, 1, 3]) array([0, 1, 3])]]
注意:锯齿状数组可能很奇怪。如果您简单地创建 (python) 个数组列表,您的情况就差不多了,例如:
def uniqueify(obj):
if isinstance(obj[0], np.ndarray):
return [uniqueify(e) for e in obj]
else:
return np.unique(obj)
这通常产生相同的东西,但使用 python 列表来包含 numpy 数组:
[[array([0, 1, 2]), array([0, 1, 2, 3]), array([0, 1, 3])], [array([0, 1, 2, 3]), array([0, 1, 2, 3]), array([1, 3])], [array([0, 1, 2, 3]), array([0, 1, 3]), array([0, 1, 3])]]
或手动格式化:
[[array([0, 1, 2]), array([0, 1, 2, 3]), array([0, 1, 3])],
[array([0, 1, 2, 3]), array([0, 1, 2, 3]), array([1, 3])],
[array([0, 1, 2, 3]), array([0, 1, 3]), array([0, 1, 3])]]
set
的这种用法有效:
In [111]: np.array([tuple(set(i)) for i in v.ravel().tolist()]).reshape(3,3)
Out[111]:
array([[(0, 1, 2), (0, 1, 2, 3), (0, 1, 3)],
[(0, 1, 2, 3), (0, 1, 2, 3), (1, 3)],
[(0, 1, 2, 3), (0, 1, 3), (0, 1, 3)]], dtype=object)
我返回了一个二维元组数组(dtype 对象)。我没有保留结构化数组数据类型。我也可以返回集合数组或集合列表。
或者使用 tolist
嵌套的元组列表
In [112]: _.tolist()
Out[112]:
[[(0, 1, 2), (0, 1, 2, 3), (0, 1, 3)],
[(0, 1, 2, 3), (0, 1, 2, 3), (1, 3)],
[(0, 1, 2, 3), (0, 1, 3), (0, 1, 3)]]
我不需要原件tolist
;在 raveled 数组上迭代就足够了
In [115]: [set(i) for i in v.ravel()]
Out[115]:
[{0, 1, 2},
{0, 1, 2, 3},
{0, 1, 3},
{0, 1, 2, 3},
{0, 1, 2, 3},
{1, 3},
{0, 1, 2, 3},
{0, 1, 3},
{0, 1, 3}]
unique
给出同样的东西;我不能做 np.unique(i)
因为它试图处理整个 1 元素结构化数组:
In [117]: [np.unique(i.tolist()) for i in v.ravel()]
Out[117]:
[array([0, 1, 2]),
array([0, 1, 2, 3]),
array([0, 1, 3]),
array([0, 1, 2, 3]),
array([0, 1, 2, 3]),
array([1, 3]),
array([0, 1, 2, 3]),
array([0, 1, 3]),
array([0, 1, 3])]
=======================
这会将其转换为 3 维数组
在[134]中:v1=v.view(np.dtype('(6,)i4'))
In [135]: v1
Out[135]:
array([[[2, 0, 0, 0, 0, 1],
[1, 0, 3, 2, 1, 2],
[3, 1, 3, 0, 3, 1]],
[[1, 2, 1, 1, 0, 3],
[3, 0, 3, 2, 3, 1],
[1, 3, 1, 1, 3, 3]],
[[0, 2, 3, 3, 1, 1],
[0, 1, 1, 1, 3, 0],
[0, 3, 3, 3, 1, 0]]])
不过,我不确定这是否有帮助。将 unique
应用于最后一个维度与结构化形式存在相同的问题。
In [137]: [np.unique(i) for i in v1.reshape(-1,6)]
===================== 我在下面写的是一维结构化数组。这个例子是 2d。当然,它可以被展平并且所有适用。
我的第一个想法是将其转换为列表并将 set
应用于每个元组。这是一个结构化数组,因此 v.tolist()
将是一个元组列表。
我在 link 中的第一个建议是 Dan 发现的:
(重点在于计数;bincount
解决方案在这里无济于事。)。
[set(i) for i in v.tolist()]
您甚至可能不需要翻译它,但我必须对其进行测试。我不知道结构化记录是否可以作为 set
.
[set(i) for i in v]
不管结果将是一个不同长度的项目列表。它们是集合、列表还是数组并不重要。只有它们不会是结构化数组 - 除非我们付出额外的努力来确定哪些字段是唯一的。
由于字段都是相同的数据类型,因此很容易将其转换为二维数组。
v.view(int, 6) # 6 fields
应该可以解决问题(需要测试)。 (更正,将其转换为纯 int 数组并不像我想象的那么容易)。
np.unique
应该和 set
一样有效;但是我怀疑 set
对于 6 个值(或任何其他合理数量的字段)更快。