只需运行代码:
a = [frozenset({1,2}),frozenset({3,4}),frozenset({1,2})]
print(set(a)) # out: {frozenset({3, 4}), frozenset({1, 2})}
print(np.unique(a)) # out: [frozenset({1, 2}), frozenset({3, 4}), frozenset({1, 2})]
第一个是正确的,第二个是不正确的。 问题恰好在这里:
a[0]==a[-1] # out: True
但是从np.unique设置有3个元素,而不是2个。
我曾经利用np.unique处理ex的重复项(使用return_index = True等)。您可以建议我为这些目的改用np.unique吗?
答案 0 :(得分:3)
numpy.unique
的操作方式是先排序,然后折叠相同元素的运行。根据文档字符串:
返回数组中排序的唯一元素。
“已排序”部分表示它正在使用一种排序折叠相邻技术(类似于* NIX sort | uniq
管道完成的工作)。
问题在于,尽管frozenset
确实定义了__lt__
(<
的重载,大多数Python排序算法都将其用作其基本构建块),但它没有将其用于目的像数字和序列这样的总排序中使用它。测试“是……的适当子集”(不包括直接相等)是超负荷的。因此frozenset({1,2}) < frozenset({3,4})
是False
, 也是frozenset({3,4}) > frozenset({1,2})
。
由于预期的排序不变性被破坏,类似set
的对象的排序序列会产生特定于实现且几乎无用的结果。在这种情况下,基于排序的统一策略通常会失败;一个可能的结果是,它将发现已经按顺序或反向排序的序列(因为每个元素都“小于”前一个元素和后一个元素);如果确定顺序正确,则没有任何变化;如果顺序相反,则交换元素顺序(但在这种情况下,它与保留顺序没有区别)。然后,它删除相邻的重复项(由于后排序,因此所有重复项都应分组在一起),没有发现(重复项不相邻),然后返回原始数据。
对于frozenset
,您可能希望使用基于哈希的唯一化,例如通过set
或(为了保留Python 3.7+上的原始外观顺序),dict.fromkeys
;后者就是:
a = [frozenset({1,2}),frozenset({3,4}),frozenset({1,2})]
uniqa = list(dict.fromkeys(a)) # Works on CPython/PyPy 3.6 as implementation detail, and on 3.7+ everywhere
也可以使用基于排序的唯一化,但是numpy.unique
似乎不支持key
函数,因此使用Python内置工具更容易:
from itertools import groupby # With no key argument, can be used much like uniq command line tool
a = [frozenset({1,2}),frozenset({3,4}),frozenset({1,2})]
uniqa = [k for k, _ in groupby(sorted(a, key=sorted))]
第二行有点密集,所以我将其分解:
sorted(a, key=sorted)
-根据list
返回一个新的a
,其中每个元素都是根据元素的已排序list
形式排序的(因此<
比较实际上确实与like一样)groupby(...)
返回键/组-迭代器对的迭代器。没有key
的{{1}}参数,这仅表示每个键都是唯一值,并且group-iterator产生的值是所看到的次数。groupby
因为我们不在乎每个重复值出现了多少次,所以我们忽略了group-iterator(分配给[k for k, _ in ...]
的意思是按照惯例“忽略”),并拥有列表理解仅产生键(唯一值)