在 Python 中将分区设置为 k 个组(包括 NULL 集)

Posted

技术标签:

【中文标题】在 Python 中将分区设置为 k 个组(包括 NULL 集)【英文标题】:Set partitions into k groups (including the NULL set) in Python 【发布时间】:2016-07-03 13:41:51 【问题描述】:

有一些类似的帖子 I have a list of numbers, how to generate all unique k-partitions?

但我想知道是否有一些新的高效库来解决这个问题(itertoolssagemath?)

我有一个数字列表,如何生成所有唯一的有序 ​​k 分区? 例如,如果我有 [1,2,3,4,5] 和 k=3

[[1,2],[3],[4,5]]就是这样一个分区 但是[[4,5],[3],[1,2]]也是这样一个分区

例如,我还想将 NULL 集合作为可能的集合包含在 k 个子集中

[[2,3],[],[1,4,5]]

顺序很重要

[[1,2],[3],[4,5]]

[[4,5],[3],[1,2]]

但是 [[2,1],[3],[5,4]] 被认为与 [[1,2],[3],[4,5]] 相同,如果您关注我...

据我所知,Sagemath 的OrderedSetPartitions(5,3) 不会提供我的问题的答案,因为它不包括 NULL 集

编辑:这是一个(根本没有优化)尝试使用 SAGEMATH 天真地解决这个问题

def OrderedSetPartitions_0(A,k):

    cols=i for i in range(k)
    # returns the list of k-OrderedSetPartitions of A, allowing for the empty set
    s=Subsets(cols).list()
    res=[]
    count=0
    P=[OrderedSetPartitions(A,i) for i in range(k+1)]

    for sub in s:
           print("sub=")
           print(sub)

           tmp=[  for i in range(k)]
           c=sub.cardinality()
           for part in P[c]:
               print("part=")
               print(part)
               for i in range(c):
                   tmp[sub[i]]=part[i]

               print("tmp=")
               print(tmp)

               res=res.append([tmp])
               # res = res.append(tmp) # tried this too
               print("res=")
               print(res)
               count=count+1
    return(res)
    # print(count)

A=range(3)
k=2
A
P=[OrderedSetPartitions(A,i) for i in range(k+1)]
# note that P[2].list is a list of list !
P[2].list()
[[0, 1, 2],
 [0, 2, 1],
 [1, 2, 0],
 [0, 1, 2],
 [1, 0, 2],
 [2, 0, 1]]
myset=OrderedSetPartitions_0(A,k)

我收到此错误消息,我承认我根本没有收到它,因为它在编码时看起来不错, 但不知何故 res 似乎是“无”而不是 []

sub=

sub=
0
part=
[0, 1, 2]
tmp=
[0, 1, 2, ]
res=
None
sub=
1
part=
[0, 1, 2]
tmp=
[, 0, 1, 2]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "_sage_input_21.py", line 10, in <module>
    exec compile(u'open("___code___.py","w").write("#

-- 编码:utf-8 --\n" + 支持.preparse_worksheet_cell(base64.b64decode("bXlzZXQ9T3JkZXJlZFNldFBhcnRpdGlvbnNfMChBLGsp"),globals())+"\ n"); execfile(os.path.abspath("代码.py")) 文件“”,第 1 行,在

  File "/private/var/folders/gm/z065gk616xg6g0xgn4c7_bvc0000gn/T/tmpryfYOj/___code___.py", line 2, in <module>
    exec compile(u'myset=OrderedSetPartitions_0(A,k)
  File "", line 1, in <module>

  File "/private/var/folders/gm/z065gk616xg6g0xgn4c7_bvc0000gn/T/tmpSH_9LF/___code___.py", line 27, in OrderedSetPartitions_0
    res=res.append([tmp])
AttributeError: 'NoneType' object has no attribute 'append'

问题在于将列表聚合到 res 中。如果我对所有涉及 res 的行加粗,我可以正确枚举输出

编辑: 谢谢你的回答

其实我把res=res.append(tmp)改成了res.append(tmp) 我做print(tmp)时枚举正确

[0, 1, 2, , ] [, 0, 1, 2, ] [, , 0, 1, 2] [0, 1, 2, ] [0, 2, 1, ] [1, 2, 0, ] [0, 1, 2, ] [1, 0, 2, ] [2, 0, 1, ] [0, 1, , 2] [0, 2, , 1] [1, 2, , 0] [0, , 1, 2] [1, , 0, 2] [2, , 0, 1] [, 0, 1, 2] [, 0, 2, 1] [, 1, 2, 0] [, 0, 1, 2] [, 1, 0, 2] [, 2, 0, 1] [0, 1, 2] [0, 2, 1] [1, 0, 2] [2, 0, 1] [1, 2, 0] [2, 1, 0]

但奇怪的是 res 是错误的,肯定有一些副作用

[[0, 1, 2, , ],
 [, 0, 1, 2, ],
 [, , 0, 1, 2],
 [2, 0, 1, ],
 [2, 0, 1, ],
 [2, 0, 1, ],
 [2, 0, 1, ],
 [2, 0, 1, ],
 [2, 0, 1, ],
 [2, , 0, 1],
 [2, , 0, 1],
 [2, , 0, 1],
 [2, , 0, 1],
 [2, , 0, 1],
 [2, , 0, 1],
 [, 2, 0, 1],
 [, 2, 0, 1],
 [, 2, 0, 1],
 [, 2, 0, 1],
 [, 2, 0, 1],
 [, 2, 0, 1],
 [2, 1, 0],
 [2, 1, 0],
 [2, 1, 0],
 [2, 1, 0],
 [2, 1, 0],
 [2, 1, 0]]

前 3 行是正确的,然后它开始与我使用 print(tmp) 得到的不同。这对我来说很奇怪,因为print(tmp)res.append(tmp) 之间没有指令!!!!!

【问题讨论】:

您看到的错误是由res=res.append([tmp])引起的。列表方法append 修改列表,它不返回值。所以res 被分配给 None 作为结果。只需放弃该分配(尽管我认为您那里的代码可能存在其他问题。) 还有两件事:追加时需要create a fresh copy of tmp,因为后续修改会影响已经追加的内容。使用res.append(tmp[:])。另外,is not empty set,它是一个空字典。对空集使用set()Set() 非常感谢,这确实是我“bug”的原因…… 【参考方案1】:

这是 Sagemath 中的一个解决方案,使用 NumPy 数组和 itertools。这个想法与您的代码中的想法相同:创建 OrderedSetPartitions 并用空集加强它们。为了在没有太多循环的情况下做到这一点,使用了 NumPy 数组:关键部分是 partitions[:, s] = P,其中 2D 数组 partitions 的某些列,最初填充的是空集,被来自 OrderedSetPartitions 的非空集替换。

import numpy as np
from itertools import combinations
A = Set([1, 2, 3, 4, 5])        # Sage set, not Python set
k = 3                           # number of elements in partition
all_partitions = np.array(OrderedSetPartitions(A, k).list())
for i in range(k-1, 0, -1):
    P = np.array(OrderedSetPartitions(A, i).list()) if i > 1 else [[A]]
    for s in combinations(range(k), i):
        partitions = np.empty((len(P), k), dtype=object)
        partitions[:, :] = [[Set()]]
        partitions[:, s] = P
        all_partitions = np.vstack((all_partitions, partitions))
print all_partitions

输出是一个双 NumPy 数组。如果需要 Python 列表,您可以返回 all_partitions.tolist()

技术

Sage 集(使用 Set([1,2,3]) 创建)和 Python 集(使用 set([1,2,3])1,2,3,4,5 创建)是不同类的对象。在 Sagemath 中,Sage 集的输出看起来更好:它们显示为 1,2,3 而 Python 集显示为 set([1,2,3])。出于这个原因,Sage 集在 Sagemath 中是首选。此外,OrderedSetPartitions 返回 Sage 集。

但是要让 NumPy 与 Sage 集一起玩需要更多的努力:特别是,我无法让 np.full 接受空的 Sage 集 Set() 作为填充对象。这就是使用np.empty然后填写的原因。

类似的问题是导致 i == 1 被区别对待的情况:NumPy 尝试将 [[Set([1,2,3,4,5])]] 转换为数字的三维数组,而不是包含一个 Sage 集对象的二维数组。

【讨论】:

感谢您的回答。我进行了编辑。如果您也可以提供帮助,我想知道我的错误的原因。谢谢

以上是关于在 Python 中将分区设置为 k 个组(包括 NULL 集)的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中将 .mdb 文件转换为 .csv 时包括列名

有没有办法在python中将列表中的所有值单独声明为列表[关闭]

无法在 ubuntu 中将默认 python 版本设置为 python3

Python 聚类算法

在python中将长数字格式化为字符串

如何在 Python/Pandas 中将变量设置为“今天”日期