在 numpy.array 中查找唯一行

Posted

技术标签:

【中文标题】在 numpy.array 中查找唯一行【英文标题】:Find unique rows in numpy.array 【发布时间】:2013-06-02 23:40:16 【问题描述】:

我需要在 numpy.array 中找到唯一的行。

例如:

>>> a # I have
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])
>>> new_a # I want to get to
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 0]])

我知道我可以创建一个集合并在数组上循环,但我正在寻找一个高效的纯numpy 解决方案。我相信有一种方法可以将数据类型设置为 void,然后我可以使用 numpy.unique,但我不知道如何使它工作。

【问题讨论】:

pandas 有一个 dataframe.drop_duplicates() 方法。见***.com/questions/12322779/pandas-unique-dataframe 和pandas.pydata.org/pandas-docs/dev/generated/… 谢谢,但我不能使用 pandas。 Removing duplicates in each row of a numpy array的可能重复 @Andy Hayden,尽管标题如此,但它与这个问题并不重复。 codeape 的链接是重复的。 此功能将在 1.13 原生支持:github.com/numpy/numpy/pull/7742 【参考方案1】:

从 NumPy 1.13 开始,可以简单地选择轴来选择任何 N-dim 数组中的唯一值。要获得唯一的行,可以这样做:

unique_rows = np.unique(original_array, axis=0)

【讨论】:

小心这个功能。 np.unique(list_cor, axis=0) 为您提供删除重复行的数组;它不会将数组过滤为在原始数组中唯一的元素。参见here,例如.. 请注意,如果您想要忽略行中值顺序的唯一行,您可以先对列中的原始数组进行排序:original_array.sort(axis=1)【参考方案2】:

另一种可能的解决方案

np.vstack(tuple(row) for row in a)

【讨论】:

+1 这很清晰,简短且符合 Python 风格。除非速度是一个真正的问题,否则这些类型的解决方案应该优先于这个问题 IMO 的复杂、更高投票的答案。 太棒了!花括号或 set() 函数可以解决问题。 @Greg von Winckel 你能推荐一些不会改变顺序的东西吗? 是的,但不是在单个命令中:x=[]; [x.append(tuple(r)) for r in a if tuple(r) not in x]; a_unique = array(x); 为避免 FutureWarning,请将集合转换为类似列表:np.vstack(list(tuple(row) for row in AIPbiased[i, :, :]))FutureWarning:数组到堆栈必须作为“序列”类型传递,例如列表或元组。自 NumPy 1.16 起,对非序列可迭代对象(如生成器)的支持已弃用,将来会引发错误。【参考方案3】:

使用结构化数组的另一种选择是使用 void 类型的视图,它将整行连接成一个项目:

a = np.array([[1, 1, 1, 0, 0, 0],
              [0, 1, 1, 1, 0, 0],
              [0, 1, 1, 1, 0, 0],
              [1, 1, 1, 0, 0, 0],
              [1, 1, 1, 1, 1, 0]])

b = np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
_, idx = np.unique(b, return_index=True)

unique_a = a[idx]

>>> unique_a
array([[0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

编辑 根据@seberg 的建议添加了np.ascontiguousarray。如果数组不是连续的,这将减慢方法的速度。

编辑 上面可以稍微加快,也许以清晰为代价,通过这样做:

unique_a = np.unique(b).view(a.dtype).reshape(-1, a.shape[1])

另外,至少在我的系统上,它在性能方面与 lexsort 方法相当,甚至更好:

a = np.random.randint(2, size=(10000, 6))

%timeit np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, a.shape[1])
100 loops, best of 3: 3.17 ms per loop

%timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]
100 loops, best of 3: 5.93 ms per loop

a = np.random.randint(2, size=(10000, 100))

%timeit np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, a.shape[1])
10 loops, best of 3: 29.9 ms per loop

%timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]
10 loops, best of 3: 116 ms per loop

【讨论】:

非常感谢。这是我一直在寻找的答案,你能解释一下这一步发生了什么吗:b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1]))) @Akavall 它正在使用np.void 数据类型创建数据视图,其大小为整行中的字节数。如果您有一个 np.uint8s 数组并将其查看为 np.uint16s,这与您得到的两个相似,它将每两列合并为一个列,但更灵活。 @Jaime,您能否添加一个np.ascontiguousarray 或类似的名称以确保总体安全(我知道它的限制比必要的要多,但是...)。行必须连续,视图才能按预期工作。 @ConstantineEvans 这是最近添加的:在 numpy 1.6 中,尝试在 np.void 的数组上运行 np.unique 返回与未针对该类型实现合并排序相关的错误。不过它在 1.7 中运行良好。 值得注意的是,如果此方法用于浮点数,则-0. 不会与+0. 进行比较,而逐个元素的比较将具有@987654336 @(由 ieee 浮点标准指定)。见***.com/questions/26782038/…【参考方案4】:

如果您想避免转换为一系列元组或其他类似数据结构的内存开销,您可以利用 numpy 的结构化数组。

诀窍是将原始数组视为结构化数组,其中每个项目对应于原始数组的一行。这不会复制,而且效率很高。

举个简单的例子:

import numpy as np

data = np.array([[1, 1, 1, 0, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [1, 1, 1, 0, 0, 0],
                 [1, 1, 1, 1, 1, 0]])

ncols = data.shape[1]
dtype = data.dtype.descr * ncols
struct = data.view(dtype)

uniq = np.unique(struct)
uniq = uniq.view(data.dtype).reshape(-1, ncols)
print uniq

要了解发生了什么,请查看中间结果。

一旦我们将事物视为结构化数组,数组中的每个元素就是原始数组中的一行。 (基本上,它是一个类似于元组列表的数据结构。)

In [71]: struct
Out[71]:
array([[(1, 1, 1, 0, 0, 0)],
       [(0, 1, 1, 1, 0, 0)],
       [(0, 1, 1, 1, 0, 0)],
       [(1, 1, 1, 0, 0, 0)],
       [(1, 1, 1, 1, 1, 0)]],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

In [72]: struct[0]
Out[72]:
array([(1, 1, 1, 0, 0, 0)],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

一旦我们运行numpy.unique,我们就会得到一个结构化数组:

In [73]: np.unique(struct)
Out[73]:
array([(0, 1, 1, 1, 0, 0), (1, 1, 1, 0, 0, 0), (1, 1, 1, 1, 1, 0)],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

然后我们需要将其视为“正常”数组(_ 将上次计算的结果存储在 ipython 中,这就是您看到 _.view... 的原因):

In [74]: _.view(data.dtype)
Out[74]: array([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0])

然后重新整形为二维数组(-1 是一个占位符,告诉 numpy 计算正确的行数,给出列数):

In [75]: _.reshape(-1, ncols)
Out[75]:
array([[0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

显然,如果你想更简洁,你可以写成:

import numpy as np

def unique_rows(data):
    uniq = np.unique(data.view(data.dtype.descr * data.shape[1]))
    return uniq.view(data.dtype).reshape(-1, data.shape[1])

data = np.array([[1, 1, 1, 0, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [1, 1, 1, 0, 0, 0],
                 [1, 1, 1, 1, 1, 0]])
print unique_rows(data)

结果:

[[0 1 1 1 0 0]
 [1 1 1 0 0 0]
 [1 1 1 1 1 0]]

【讨论】:

这实际上看起来很慢,几乎和使用元组一样慢。显然,像这样对结构化数组进行排序很慢。 @cge - 尝试使用更大的数组。是的,对 numpy 数组进行排序比对列表进行排序要慢。不过,在大多数使用 ndarray 的情况下,速度并不是主要考虑因素。这是内存使用情况。与此解决方案相比,元组列表将使用 大量 更多内存。即使您有足够的内存和相当大的数组,将其转换为元组列表的开销也大于速度优势。 @cge - 啊,我没注意到你在使用lexsort。我以为您指的是使用元组列表。是的,lexsort 在这种情况下可能是更好的选择。我忘记了它,并跳到了一个过于复杂的解决方案。【参考方案5】:

np.unique 当我在np.random.random(100).reshape(10,10) 上运行它时会返回所有唯一的单个元素,但您需要唯一的行,所以首先需要将它们放入元组中:

array = #your numpy array of lists
new_array = [tuple(row) for row in array]
uniques = np.unique(new_array)

这是我看到您更改类型以执行您想要的操作的唯一方法,并且我不确定更改为元组的列表迭代是否适合您的“不循环”

【讨论】:

+1 这很清晰、简短且符合 Python 风格。除非速度是一个真正的问题,否则这些类型的解决方案应该优先于这个问题 IMO 的复杂、更高投票的答案。 我更喜欢这个而不是接受的解决方案。速度对我来说不是问题,因为每次调用我可能只有 &lt; 100 行。这准确地描述了如何在行上执行唯一性。 这实际上不适用于我的数据,uniques 包含独特的元素。可能我误解了array 的预期形状 - 你能在这里更准确吗? @ryan-saxe 我喜欢这是pythonic,但这不是一个好的解决方案,因为返回到uniques 的行已排序(因此与array 中的行不同)。 B = np.array([[1,2],[2,1]]); A = np.unique([tuple(row) for row in B]); print(A) = array([[1, 2],[1, 2]])【参考方案6】:

np.unique 的工作原理是对扁平数组进行排序,然后查看每个项目是否等于前一个。这可以手动完成而无需展平:

ind = np.lexsort(a.T)
a[ind[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]]

此方法不使用元组,应该比这里给出的其他方法更快、更简单。

注意:之前的版本在 a[ 之后没有 ind,这意味着使用了错误的索引。此外,Joe Kington 提出了一个很好的观点,即这确实制作了各种中间副本。以下方法通过制作排序副本然后使用它的视图来减少:

b = a[np.lexsort(a.T)]
b[np.concatenate(([True], np.any(b[1:] != b[:-1],axis=1)))]

这样更快,使用更少的内存。

此外,如果您想在 ndarray 中找到唯一行无论数组中有多少维,以下方法都可以:

b = a[lexsort(a.reshape((a.shape[0],-1)).T)];
b[np.concatenate(([True], np.any(b[1:]!=b[:-1],axis=tuple(range(1,a.ndim)))))]

如果您想沿任意维度数组的任意轴进行排序/唯一化,那么剩下的一个有趣的问题会更加困难。

编辑:

为了演示速度差异,我在 ipython 中对答案中描述的三种不同方法进行了一些测试。与 your 完全一样,并没有太大的区别,虽然这个版本要快一些:

In [87]: %timeit unique(a.view(dtype)).view('<i8')
10000 loops, best of 3: 48.4 us per loop

In [88]: %timeit ind = np.lexsort(a.T); a[np.concatenate(([True], np.any(a[ind[1:]]!= a[ind[:-1]], axis=1)))]
10000 loops, best of 3: 37.6 us per loop

In [89]: %timeit b = [tuple(row) for row in a]; np.unique(b)
10000 loops, best of 3: 41.6 us per loop

然而,有了更大的 a,这个版本最终会快得多:

In [96]: a = np.random.randint(0,2,size=(10000,6))

In [97]: %timeit unique(a.view(dtype)).view('<i8')
10 loops, best of 3: 24.4 ms per loop

In [98]: %timeit b = [tuple(row) for row in a]; np.unique(b)
10 loops, best of 3: 28.2 ms per loop

In [99]: %timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!= a[ind[:-1]],axis=1)))]
100 loops, best of 3: 3.25 ms per loop

【讨论】:

非常好!不过,附带说明一下,它确实制作了几个中间副本。 (例如,a[ind[1:]] 是副本等)另一方面,您的解决方案通常比我的解决方案快 2-3 倍,直到您的内存用完。 好点。事实证明,我尝试仅使用索引取出中间副本使我的方法使用更多内存并且最终比仅制作数组的排序副本更慢,因为 a_sorted[1:] 不是 a_sorted 的副本. 您的时间安排中dtype 是什么?我想你弄错了。在我的系统上,按照我的回答中所述调用np.unique 比使用np.lexsort 的两种风格中的任何一种都要快一些。如果查找唯一值的数组的形状为(10000, 100),则速度大约快 5 倍。即使您决定重新实现 np.unique 所做的以减少一些(次要)执行时间,将每一行折叠成一个对象比在列比较时调用 np.any 运行速度更快,尤其是对于更高的列数。 @cge:你的意思可能是“np.any”,而不是标准的“any”,它不接受关键字参数。 @Jaime - 我相信 dtype 只是 a.dtype,即正在查看的数据的数据类型,正如 Joe Kington 在他的回答中所做的那样。如果有很多列,另一种(不完美!)使用lexsort 保持快速的方法是只对几列进行排序。这是特定于数据的,因为需要知道哪些列提供了足够的方差来完美排序。例如。 a.shape = (60000, 500) - 按前 3 列排序:ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0]))。节省的时间相当可观,但再次声明:它可能无法涵盖所有​​情况 - 这取决于数据。【参考方案7】:

我比较了建议的速度替代方案,发现令人惊讶的是,void 视图 unique 解决方案甚至比带有 axis 参数的 numpy 的原生 unique 还要快一点。如果你正在寻找速度,你会想要

numpy.unique(
    a.view(numpy.dtype((numpy.void, a.dtype.itemsize*a.shape[1])))
).view(a.dtype).reshape(-1, a.shape[1])

我在npx.unique_rows 中实现了最快的变体。

这个也有a bug report on GitHub。


重现情节的代码:

import numpy
import perfplot


def unique_void_view(a):
    return (
        numpy.unique(a.view(numpy.dtype((numpy.void, a.dtype.itemsize * a.shape[1]))))
        .view(a.dtype)
        .reshape(-1, a.shape[1])
    )


def lexsort(a):
    ind = numpy.lexsort(a.T)
    return a[
        ind[numpy.concatenate(([True], numpy.any(a[ind[1:]] != a[ind[:-1]], axis=1)))]
    ]


def vstack(a):
    return numpy.vstack([tuple(row) for row in a])


def unique_axis(a):
    return numpy.unique(a, axis=0)


perfplot.show(
    setup=lambda n: numpy.random.randint(2, size=(n, 20)),
    kernels=[unique_void_view, lexsort, vstack, unique_axis],
    n_range=[2 ** k for k in range(15)],
    xlabel="len(a)",
    equality_check=None,
)

【讨论】:

非常好的答案,一个小问题:vstack_dict,从不使用字典,花括号是一个集合理解,因此它的行为几乎与vstatck_set 相同。由于 fro 图表缺少 vstack_dict 性能线,看起来它只是被 vstack_set 性能图表覆盖,因为它们非常相似! 感谢您的回复。我改进了情节以仅包含一个 vstack 变体。【参考方案8】:

这是@Greg pythonic 答案的另一个变体

np.vstack(set(map(tuple, a)))

【讨论】:

【参考方案9】:

我不喜欢这些答案中的任何一个,因为没有一个在线性代数或向量空间意义上处理浮点数组,其中两行“相等”意味着“在某个 ? 内”。具有容差阈值的一个答案https://***.com/a/26867764/500207 将阈值设为元素级和十进制 精度,这适用于某些情况,但在数学上不如真正的矢量距离一般.

这是我的版本:

from scipy.spatial.distance import squareform, pdist

def uniqueRows(arr, thresh=0.0, metric='euclidean'):
    "Returns subset of rows that are unique, in terms of Euclidean distance"
    distances = squareform(pdist(arr, metric=metric))
    idxset = tuple(np.nonzero(v)[0]) for v in distances <= thresh
    return arr[[x[0] for x in idxset]]

# With this, unique columns are super-easy:
def uniqueColumns(arr, *args, **kwargs):
    return uniqueRows(arr.T, *args, **kwargs)

上面的公共域函数使用scipy.spatial.distance.pdist 来查找每对行之间的欧几里得(可定制)距离。然后它将每个距离与threshold 进行比较,以查找彼此在thresh 内的行,并从每个thresh-cluster 返回一行。

正如所暗示的,metric 的距离不必是欧几里得——pdist 可以计算各种距离,包括cityblock(曼哈顿标准)和cosine(向量之间的角度)。

如果thresh=0(默认),那么行必须是位精确的才能被认为是“唯一的”。 thresh 的其他良好值使用缩放的机器精度,即 thresh=np.spacing(1)*1e3

【讨论】:

最佳答案。谢谢。这是迄今为止写的最(数学)概括的答案。它将矩阵视为 N 维空间中的一组数据点或样本,并找到相同或相似点的集合(相似性由欧几里得距离或任何其他方法定义)。这些点可以是重叠的数据点或非常接近的邻域。最后,相同或相似点的集合被属于同一集合的任何点(在上述答案中由第一个点)替换。这有助于减少点云的冗余。 @Sanchit 啊哈,这是一个很好的观点,而不是选择“第一个”点(实际上它可能是有效的随机的,因为它取决于 Python 如何将这些点存储在 set 中)作为代表对于每个thresh 大小的邻域,该函数可以允许用户指定如何选择该点,例如,使用“中值”或最接近质心的点等。 当然。毫无疑问。我刚刚提到了第一点,因为这是你的程序正在做的事情,完全没问题。 只是一个更正-我在上面错误地说,由于set 的无序性质,将为每个thresh-cluster 选择的行将是随机的。当然这是我的脑残,set 存储了在thresh-neighborhood 中的索引元组,所以这个findRows 确实实际上返回,对于每个thresh-簇,它的第一行。【参考方案10】:

为什么不使用 pandas 的drop_duplicates

>>> timeit pd.DataFrame(image.reshape(-1,3)).drop_duplicates().values
1 loops, best of 3: 3.08 s per loop

>>> timeit np.vstack(tuple(r) for r in image.reshape(-1,3))
1 loops, best of 3: 51 s per loop

【讨论】:

我真的很喜欢这个答案。当然,它不直接使用 numpy,但对我来说它是最容易理解的,同时速度很快。【参考方案11】:

numpy_indexed 包(免责声明:我是它的作者)将 Jaime 发布的解决方案封装在一个经过测试的漂亮界面中,以及更多功能:

import numpy_indexed as npi
new_a = npi.unique(a)  # unique elements over axis=0 (rows) by default

【讨论】:

【参考方案12】:

np.unique 给定一个元组列表:

>>> np.unique([(1, 1), (2, 2), (3, 3), (4, 4), (2, 2)])
Out[9]: 
array([[1, 1],
       [2, 2],
       [3, 3],
       [4, 4]])

使用列表列表会引发TypeError: unhashable type: 'list'

【讨论】:

似乎不适用于我的。每个元组是两个字符串而不是两个浮点数 不起作用,它返回一个元素列表而不是元组【参考方案13】:

根据本页中的答案,我编写了一个函数,该函数复制了 MATLAB 的 unique(input,'rows') 函数的功能,并具有接受检查唯一性的容差的附加功能。它还返回诸如c = data[ia,:]data = c[ic,:] 的索引。如果您发现任何差异或错误,请报告。

def unique_rows(data, prec=5):
    import numpy as np
    d_r = np.fix(data * 10 ** prec) / 10 ** prec + 0.0
    b = np.ascontiguousarray(d_r).view(np.dtype((np.void, d_r.dtype.itemsize * d_r.shape[1])))
    _, ia = np.unique(b, return_index=True)
    _, ic = np.unique(b, return_inverse=True)
    return np.unique(b).view(d_r.dtype).reshape(-1, d_r.shape[1]), ia, ic

【讨论】:

【参考方案14】:

除了@Jaime 出色的答案,另一种折叠行的方法是使用a.strides[0](假设a 是C 连续的),它等于a.dtype.itemsize*a.shape[0]。此外,void(n)dtype((void,n)) 的快捷方式。我们终于到了这个最短的版本:

a[unique(a.view(void(a.strides[0])),1)[1]]

对于

[[0 1 1 1 0 0]
 [1 1 1 0 0 0]
 [1 1 1 1 1 0]]

【讨论】:

【参考方案15】:

对于像 3D 或更高的多维嵌套数组这样的一般用途,试试这个:

import numpy as np

def unique_nested_arrays(ar):
    origin_shape = ar.shape
    origin_dtype = ar.dtype
    ar = ar.reshape(origin_shape[0], np.prod(origin_shape[1:]))
    ar = np.ascontiguousarray(ar)
    unique_ar = np.unique(ar.view([('', origin_dtype)]*np.prod(origin_shape[1:])))
    return unique_ar.view(origin_dtype).reshape((unique_ar.shape[0], ) + origin_shape[1:])

满足您的 2D 数据集:

a = np.array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])
unique_nested_arrays(a)

给予:

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

还有 3D 数组,例如:

b = np.array([[[1, 1, 1], [0, 1, 1]],
              [[0, 1, 1], [1, 1, 1]],
              [[1, 1, 1], [0, 1, 1]],
              [[1, 1, 1], [1, 1, 1]]])
unique_nested_arrays(b)

给予:

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

【讨论】:

像 Jaime 那样使用 unique return_index 应该会使最后的 return 行更简单。只需在右轴上索引原始ar【参考方案16】:

这些答案都不适合我。我假设我的唯一行包含字符串而不是数字。然而,来自另一个线程的这个答案确实有效:

来源:https://***.com/a/38461043/5402386

您可以使用 .count() 和 .index() 列表的方法

coor = np.array([[10, 10], [12, 9], [10, 5], [12, 9]])
coor_tuple = [tuple(x) for x in coor]
unique_coor = sorted(set(coor_tuple), key=lambda x: coor_tuple.index(x))
unique_count = [coor_tuple.count(x) for x in unique_coor]
unique_index = [coor_tuple.index(x) for x in unique_coor]

【讨论】:

【参考方案17】:

我们实际上可以将mxn numeric numpy 数组转换为mx 1 numpy 字符串数组,请尝试使用以下函数,它提供countinverse_idx 等,就像numpy .unique:

import numpy as np

def uniqueRow(a):
    #This function turn m x n numpy array into m x 1 numpy array storing 
    #string, and so the np.unique can be used

    #Input: an m x n numpy array (a)
    #Output unique m' x n numpy array (unique), inverse_indx, and counts 

    s = np.chararray((a.shape[0],1))
    s[:] = '-'

    b = (a).astype(np.str)

    s2 = np.expand_dims(b[:,0],axis=1) + s + np.expand_dims(b[:,1],axis=1)

    n = a.shape[1] - 2    

    for i in range(0,n):
         s2 = s2 + s + np.expand_dims(b[:,i+2],axis=1)

    s3, idx, inv_, c = np.unique(s2,return_index = True,  return_inverse = True, return_counts = True)

    return a[idx], inv_, c

例子:

A = np.array([[ 3.17   9.502  3.291],
  [ 9.984  2.773  6.852],
  [ 1.172  8.885  4.258],
  [ 9.73   7.518  3.227],
  [ 8.113  9.563  9.117],
  [ 9.984  2.773  6.852],
  [ 9.73   7.518  3.227]])

B, inv_, c = uniqueRow(A)

Results:

B:
[[ 1.172  8.885  4.258]
[ 3.17   9.502  3.291]
[ 8.113  9.563  9.117]
[ 9.73   7.518  3.227]
[ 9.984  2.773  6.852]]

inv_:
[3 4 1 0 2 4 0]

c:
[2 1 1 1 2]

【讨论】:

【参考方案18】:

让我们将整个 numpy 矩阵作为一个列表,然后从该列表中删除重复项,最后将我们唯一的列表返回到一个 numpy 矩阵中:

matrix_as_list=data.tolist() 
matrix_as_list:
[[1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 0, 0], [0, 1, 1, 1, 0, 0], [1, 1, 1, 0, 0, 0], [1, 1, 1, 1, 1, 0]]

uniq_list=list()
uniq_list.append(matrix_as_list[0])

[uniq_list.append(item) for item in matrix_as_list if item not in uniq_list]

unique_matrix=np.array(uniq_list)
unique_matrix:
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 0]])

【讨论】:

【参考方案19】:

最直接的解决方案是通过将行设为字符串来使它们成为单个项目。然后可以使用 numpy 将每一行作为一个整体进行比较,以确定其唯一性。这个解决方案是通用的,你只需要为其他组合重塑和转置你的数组。这是针对所提供问题的解决方案。

import numpy as np

original = np.array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

uniques, index = np.unique([str(i) for i in original], return_index=True)
cleaned = original[index]
print(cleaned)    

将给予:

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

通过邮件发送我的诺贝尔奖

【讨论】:

非常低效且容易出错,例如具有不同的打印选项。其他选项显然更可取。【参考方案20】:
import numpy as np
original = np.array([[1, 1, 1, 0, 0, 0],
                     [0, 1, 1, 1, 0, 0],
                     [0, 1, 1, 1, 0, 0],
                     [1, 1, 1, 0, 0, 0],
                     [1, 1, 1, 1, 1, 0]])
# create a view that the subarray as tuple and return unique indeies.
_, unique_index = np.unique(original.view(original.dtype.descr * original.shape[1]),
                            return_index=True)
# get unique set
print(original[unique_index])

【讨论】:

以上是关于在 numpy.array 中查找唯一行的主要内容,如果未能解决你的问题,请参考以下文章

在 NumPy 数组中查找等于零的元素的索引

在 Pandas 数据框中查找唯一值,无论行或列位置如何

规范化表:在一系列行中查找唯一列 (Oracle 10.x)

numpy初识

用于基于三个参数查找唯一行的 SQL 查询 - 类似于“在已排序的分组集中获取第一行”

查找具有唯一列的数组中每一行的最小值