numpy.unique frozensets 有问题
numpy.unique has the problem with frozensets
只需运行代码:
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 什么?
numpy.unique
通过排序操作,然后折叠相同元素的运行。根据文档字符串:
Returns the sorted unique elements of an array.
"sorted" 部分暗示它使用排序折叠相邻技术(类似于 *NIX sort | uniq
管道所完成的)。
问题在于,虽然 frozenset
确实定义了 __lt__
([=16= 的重载],大多数 Python 排序算法将其用作其基本构建块),但它是不要将它用于总排序的目的,例如数字和序列使用它。测试 "is a proper subset of" 超载(不包括直接相等)。所以 frozenset({1,2}) < frozenset({3,4})
是 False
, 所以 frozenset({3,4}) > frozenset({1,2})
.
由于预期的排序不变量被破坏,对 set
类对象的排序序列会产生特定于实现且基本上无用的结果。在这些情况下,基于排序的唯一化策略通常会失败;一个可能的结果是它会发现要排序的序列已经按顺序或倒序排序(因为每个元素都是 "less than" 前后元素);如果它确定它是有序的,则没有任何变化,如果它是相反的顺序,它会交换元素顺序(但在这种情况下,这与保留顺序没有区别)。然后它删除相邻的重复项(因为 post-sort,所有重复项应该分组在一起),找到 none(重复项不相邻),并 returns 原始数据。
对于 frozenset
s,您可能希望使用基于散列的唯一化,例如通过 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)
- Returns 基于 a
的新 list
其中每个元素根据元素的排序 list
形式排序(因此<
比较实际上确实把喜欢和喜欢)
groupby(...)
returns key/group-iterator 对的迭代器。 groupby
没有 key
参数,这仅意味着每个键都是一个唯一值,并且组迭代器会生成该值的次数与所看到的次数一样多。
[k for k, _ in ...]
因为我们不关心每个重复值出现了多少次,所以我们忽略了组迭代器(按照惯例分配给 _
意味着 "ignored"),并让列表理解只产生键(唯一值)
只需运行代码:
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 什么?
numpy.unique
通过排序操作,然后折叠相同元素的运行。根据文档字符串:
Returns the sorted unique elements of an array.
"sorted" 部分暗示它使用排序折叠相邻技术(类似于 *NIX sort | uniq
管道所完成的)。
问题在于,虽然 frozenset
确实定义了 __lt__
([=16= 的重载],大多数 Python 排序算法将其用作其基本构建块),但它是不要将它用于总排序的目的,例如数字和序列使用它。测试 "is a proper subset of" 超载(不包括直接相等)。所以 frozenset({1,2}) < frozenset({3,4})
是 False
, 所以 frozenset({3,4}) > frozenset({1,2})
.
由于预期的排序不变量被破坏,对 set
类对象的排序序列会产生特定于实现且基本上无用的结果。在这些情况下,基于排序的唯一化策略通常会失败;一个可能的结果是它会发现要排序的序列已经按顺序或倒序排序(因为每个元素都是 "less than" 前后元素);如果它确定它是有序的,则没有任何变化,如果它是相反的顺序,它会交换元素顺序(但在这种情况下,这与保留顺序没有区别)。然后它删除相邻的重复项(因为 post-sort,所有重复项应该分组在一起),找到 none(重复项不相邻),并 returns 原始数据。
对于 frozenset
s,您可能希望使用基于散列的唯一化,例如通过 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)
- Returns 基于a
的新list
其中每个元素根据元素的排序list
形式排序(因此<
比较实际上确实把喜欢和喜欢)groupby(...)
returns key/group-iterator 对的迭代器。groupby
没有key
参数,这仅意味着每个键都是一个唯一值,并且组迭代器会生成该值的次数与所看到的次数一样多。[k for k, _ in ...]
因为我们不关心每个重复值出现了多少次,所以我们忽略了组迭代器(按照惯例分配给_
意味着 "ignored"),并让列表理解只产生键(唯一值)