所有(2 ^ m-2)/ 2种可能的分区列表方式

时间:2016-04-08 18:25:29

标签: python arrays list

每个样本都是一系列要素(整数)。我需要通过确定最佳功能,以及该功能的最佳分割值,将我的样本分成两个独立的组。通过" best",我的意思是分裂,它给出了预分割集与左侧和右侧熵值的加权平均值之间的最大熵差。我需要尝试所有(2 ^ m-2)/ 2种可能的方法将这些项分成两个非空列表(其中m是不同值的数量(具有相同值的所有样本作为一个组一起移动) )

以下内容非常缓慢,因此我需要更合理/更快速的方法。

sorted_by_feature是(feature_value,0_or_1)元组的列表。

same_vals = {}
            for ele in sorted_by_feature:
                if ele[0] not in same_vals:
                    same_vals[ele[0]] = [ele]
                else:
                    same_vals[ele[0]].append(ele)



            l = same_vals.keys()
            orderings = list(itertools.permutations(l))
            for ordering in orderings:

                list_tups = []
                for dic_key in ordering:
                    list_tups += same_vals[dic_key]

                left_1 = 0 
                left_0 = 0 
                right_1 = num_one
                right_0 = num_zero


                for index, tup in enumerate(list_tups):
                       #0's or #1's on the left +/- 1
                       calculate entropy on left/ right, calculate entropy drop, etc.

琐碎的细节(继续上面的代码):

                if index == len(sorted_by_feature) -1:
                        break
                    if tup[1] == 1:
                        left_1 += 1
                        right_1 -= 1

                    if tup[1] == 0:
                        left_0 += 1
                        right_0 -= 1


                    #only calculate entropy if values to left and right of split are different


                    if list_tups[index][0] != list_tups[index+1][0]:

2 个答案:

答案 0 :(得分:3)

TL;博士

你要求奇迹。没有任何编程语言可以帮助您摆脱困境。使用比你考虑做的更好的方法!

您的解决方案具有指数时间复杂度

让我们假设一个完美的算法:一个可以在恒定的O(1)时间内给你一个新分区的算法。换句话说,无论是什么输入,都可以在保证的恒定时间内生成新的分区。

实际上,我们更进一步,假设您的算法受CPU限制,并且在理想条件下运行。 Under ideal circumstances,高端CPU每秒可处理超过1000亿条指令。由于该算法需要O(1)时间,我们会说,哦,每个新分区都是在千分之一秒内生成的。到现在为止还挺好?

现在你希望它表现良好。你说你希望它能够处理大小 m 的输入。您知道这意味着您需要对算法进行大约pow(2,m)次迭代 - 这是您需要生成的分区数量,并且因为生成每个算法需要有限的时间O(1),所以时间只是pow(2,m)次O(1)。让我们快速浏览一下这里的数字:

  • m = 20表示您的时间为pow(2,20) * 10 ^ -11秒= 0.00001秒。不错。

  • m = 40表示您的时间为pow(2,40) 10 -11秒= 1万亿/ 100亿= 10 秒。也不错,但请注意 m = 40是多少。在庞大的全景数字中,40是 nothing 。请记住,我们假设理想的条件。

  • m = 100表示​​10 ^ 41 !发生了什么?

您是算法理论的受害者。简而言之,一个具有指数时间复杂度的解决方案 - 任何需要2 ^ m时间才能完成的解决方案 - 不能通过更好的编程来加速。生成或生成pow(2,m)输出总是将占用相同的时间比例。

进一步注意,1000亿条指令/秒是高端桌面计算机的理想 - 你的CPU也必须担心你正在运行的程序以外的进程,在这种情况下内核中断和上下文切换会影响处理时间(特别是当您运行几千个系统进程时,您无疑是这样)。您的CPU还必须从磁盘读取和写入,这是I / O绑定并且比您想象的要长很多。 Python之类的解释语言也会影响处理时间,因为每一行都被动态转换为字节码,迫使其他资源专门用于此。您现在可以对代码进行基准测试,我几乎可以保证您的数字将高于我上面提供的简单计算。更糟糕的是:存储 2 ^ 40个排列需要1000 GB的内存。你还有那么多吗? :)

使用生成器等切换到较低级别的语言都是毫无意义的事情:它们不是主要的瓶颈,这只是你的庞大且不合理的时间复杂度 brute force approach生成所有分区。

您可以做什么

  • 使用更好的算法。生成pow(2,m)分区并调查所有分区是不切实际的抱负。相反,您需要考虑dynamic programming approach。您希望考虑仅通过缩小的最佳解决方案空间,而不是遍历可能分区的整个空间。这就是动态编程为您所做的。它在一个类似于这个问题的工作中的一个例子:unique integer partitioning。 动态编程问题方法最适用于可以表示为线性化有向无环图的问题(谷歌,如果不确定我的意思是什么!)。

  • 如果采用动态方法,请考虑投资parallel processing with a GPU。您的计算机已经拥有GPU - 它是您的系统用于渲染图形的内容 - 而GPU的构建能够并行执行大量计算。并行计算是指不同的工作人员可以同时对同一计算执行不同部分的计算 - 最终结果可以在最后结合在一起。如果你能找到一种方法将其分解为一系列并行计算 - 我认为有充分的理由建议你可以 - there are good tools for GPU interfacing in Python

其他提示

  • 明确最佳的含义。如果您可以提供有关 best 意味着什么的更多信息,那么Stack Overflow上的人员可能会为您提供更多帮助并编写这样的算法。

  • 使用裸机编译语言可能有助于减少解决方案在普通情况下所需的实时数量,但这种情况的差异将是微不足道的。当您必须有效地执行通过数组搜索等操作时,编译语言非常有用,因为每次迭代都没有指令编译开销。在生成新分区时,它们并不是那么有用,因为这不是删除动态字节码生成障碍实际上会影响的东西。

答案 1 :(得分:0)

我可以看到一些小改进:

  1. 使用if not in代替if ele[0] not in same_vals: same_vals[ele[0]] = [ele] else: same_vals[ele[0]].append(ele) # Should be changed to try: same_vals[ele[0]].append(ele) # Most of the time this will work catch KeyError: same_vals[ele[0]] = [ele] 以避免重复查找密钥

    orderings = list(itertools.permutations(l))
    for ordering in orderings:
    # Should be changed to 
    for ordering in itertools.permutations(l):
    
  2. 如果您不需要,请不要将生成器显式转换为列表。我不会立即看到你需要将你的演员阵容放到一个列表中,这会减慢事情的发展速度

    {{1}}
  3. 但是,正如我所说,这些只是微小的改进。如果您确实需要更快,请考虑使用其他语言。