Python 有没有聪明高效的算法可以在字符串的分割空间上执行计算?

Python 有没有聪明高效的算法可以在字符串的分割空间上执行计算?,python,string,partitioning,Python,String,Partitioning,我正在做一个统计项目,涉及到迭代所有可能的方法来划分字符串集合,并对每个字符串运行一个简单的计算。具体地说,每个可能的子串都有一个与其相关联的概率,我试图得到所有分区中的子串概率乘积的和 例如,如果字符串为“abc”,则可能存在“a”、“b”、“c”、“ab”、“bc”和“abc”的概率。字符串有四种可能的分区:“abc”、“ab | c”、“a | bc”和“a | b | c”。该算法需要找到每个分区的分量概率的乘积,然后将四个结果数相加 目前,我已经编写了一个python迭代器,该迭代器对

我正在做一个统计项目,涉及到迭代所有可能的方法来划分字符串集合,并对每个字符串运行一个简单的计算。具体地说,每个可能的子串都有一个与其相关联的概率,我试图得到所有分区中的子串概率乘积的和

例如,如果字符串为“abc”,则可能存在“a”、“b”、“c”、“ab”、“bc”和“abc”的概率。字符串有四种可能的分区:“abc”、“ab | c”、“a | bc”和“a | b | c”。该算法需要找到每个分区的分量概率的乘积,然后将四个结果数相加

目前,我已经编写了一个python迭代器,该迭代器对分区使用整数的二进制表示(例如上面的例子中的00、01、10、11),并简单地运行整数。不幸的是,对于长度超过20个左右字符的字符串来说,这非常慢

有人能想出一个聪明的方法来执行这个操作,而不只是一次一个地运行每个分区吗?这件事我已经坚持了好几天了

对于一些评论,这里提供了更多信息:
字符串可以是任何形式,例如“foobar(foo2)”——我们的字母表是小写字母数字加上所有三种大括号((“,“[”,“{”)、连字符和空格。

目标是获得给定单个“单词”可能性的字符串的可能性。因此,L(S='abc')=P('abc')+P('ab')P('c')+P('a')P('bc')+P('a')P('b')P('c'))(此处“P('abc')”表示“单词”abc”的可能性,而“L(S='abc')”是观察字符串“abc”的统计可能性).

首先,配置文件以查找瓶颈

如果瓶颈仅仅是大量可能的分区,我建议并行化,可能是通过

如果瓶颈仅仅是计算速度慢,那么尝试使用C语言。这很容易通过via实现

另外,我不确定您是如何存储分区的,但是您可以使用一个字符串和一个a来很好地压缩内存消耗。如果您的瓶颈是交换和/或缓存未命中,这可能是一个巨大的胜利。

解决方案(如果我正确理解这个问题):

复杂度为O(N2),因此它将很容易解决N=20的问题

这是如何工作的:

  • 您将用
    probs['a']*probs['b']
    乘以的所有内容也将用
    probs['ab']
  • 多亏了乘法和加法的作用,你可以把这两个加起来,然后把这一个和乘以它的所有连续性
  • 对于每一个可能的最后一个子串,它通过将其概率乘以之前路径的所有概率之和,将以该子串结尾的所有拆分的总和相加。(请使用其他措辞。我的python比我的英语好。)

较长的字符串将一次又一次地重复使用您的子字符串,因此使用技术缓存值似乎是一件显而易见的尝试。这只是一种时空权衡。最简单的实现是在计算值时使用字典缓存值。对每个字符串计算进行字典查找;如果它不在字典中,请计算并添加它。后续调用将使用预先计算的值。如果字典查找速度比计算速度快,则您很幸运


我意识到您正在使用Python,但是……有一点值得注意,如果您在Perl中这样做,您甚至不必编写任何代码;内置的将为您进行缓存!

您可以通过基于算术的关联属性(和字符串连接)的小规模重构来稍微减少计算量虽然我不确定它是否会改变生活。其核心思想如下:

考虑一个较长的字符串,例如'abcdefghik',10长,用于明确性而不失去一般性。在一个简单的方法中,你将p(a)乘以9尾的多个分区,p(ab)乘以8尾的多个分区,等等;特别是p(a)和p(b)将乘以与p(ab)完全相同的8尾分区(全部)will--3次乘法,其中两次求和。所以把它算出:

(p(ab) + p(a) * p(b)) * (partitions of the 8-tail)
对于这部分,我们减少到2次乘法和1次求和,节省了1次乘积和1次求和。要覆盖所有拆分点正好位于“b”的分区,当涉及拆分点正好位于“c”的分区时

(p(abc) + p(ab) * p(c) + p(a) * (p(b)*p(c)+p(bc)) * (partitions of the 7-tail)

<储蓄>,部分是由于内部重构——当然,我们必须注意双重计数。我认为这种方法可能是广义的——从中间点开始,考虑所有有分裂的分区,分别(递归地)。对于左边和右边的部分,进行乘法和求和;然后添加所有没有拆分的分区,例如,在示例中,左边的部分是'abcde',右边的部分是'fghik',第二部分是关于所有分区的,其中'ef'在一起而不是分开--因此“折叠”将“ef”视为新的“超级字母”X,剩下一个短一点的字符串“abcdXghik”(当然,该映射的子字符串直接到原始字符串的概率,例如,新字符串中的p(cdXg)正好是原始字符串中的p(cdefg).

您应该查看
itertools
模块。它可以为您创建一个非常快速的生成器。给定您的输入字符串,它将为您提供所有可能的排列。根据您的需要,还有一个
组合()“abc”,但无论如何,本模块可能对您有用。

您是说
(p(abc) + p(ab) * p(c) + p(a) * (p(b)*p(c)+p(bc)) * (partitions of the 7-tail)