- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我试图实现 Burrows-Wheeler在python中转换。 (这是网课的作业之一,但希望自己做了一些功课,才有资格求助)。
该算法的工作原理如下。取一个以特殊字符(在我的例子中是 $)结尾的字符串,并从这个字符串创建所有循环字符串。按字母顺序对所有这些字符串进行排序,特殊字符总是小于任何其他字符。在此之后获取每个字符串的最后一个元素。
这给了我一个单行:
''.join([i[-1] for i in sorted([text[i:] + text[0:i] for i in xrange(len(text))])]
60 000 chars - 16 secs
40 000 chars - 07 secs
25 000 chars - 02 secs
最佳答案
用长字符串制作所有这些字符串切片需要很长时间。它至少是 O(N^2)(因为您创建了 N 个长度为 N 的字符串,并且每个字符串都必须从原始数据中复制到内存中),这会破坏整体性能并使排序变得无关紧要。更不用说内存要求了!
下一个想法不是对字符串进行实际切片,而是对用于创建循环字符串的 i
值进行排序,按照结果字符串的比较顺序 - 无需实际创建它。事实证明这有点棘手。 (在这里删除/编辑了一些错误的内容;请参阅@TimPeters 的回答。)
我在这里采用的方法是绕过标准库 - 这使得很难(尽管并非不可能)“按需”比较这些字符串 - 并进行我自己的排序。这里算法的自然选择是 基数排序 ,因为无论如何我们都需要一次考虑一个字符的字符串。
让我们先设置一下。我正在为 3.2 版编写代码,所以请品尝一下。 (特别是在 3.3 及更高版本中,我们可以利用 yield from
。)我正在使用以下导入:
from random import choice
from timeit import timeit
from functools import partial
def radix_sort(values, key, step=0):
if len(values) < 2:
for value in values:
yield value
return
bins = {}
for value in values:
bins.setdefault(key(value, step), []).append(value)
for k in sorted(bins.keys()):
for r in radix_sort(bins[k], key, step + 1):
yield r
key(value, n)
为我们提供
n
的第
value
个“基数”。所以对于简单的情况,比如直接比较字符串,这可能是一个简单的
lambda v, n: return v[n]
。但是,这里的想法是根据当时字符串中的数据(循环考虑)将索引与字符串进行比较。所以让我们定义一个键:
def bw_key(text, value, step):
return text[(value + step) % len(text)]
n
制作的虚拟字符串,它的最后一个字符位于索引
n - 1
处,因为我们如何环绕 - 稍等片刻就会向您确认这在
n == 0
时仍然有效;)。 [然而,当我们向前换行时,我们仍然需要保持字符串索引在边界内 - 因此在 key 函数中进行模运算。]
text
中,在转换
value
进行比较时会引用该函数。这就是
functools.partial
的用武之地——你也可以把
lambda
弄得一团糟,但这可以说更干净,而且我发现它通常也更快。
def burroughs_wheeler_custom(text):
return ''.join(text[i - 1] for i in radix_sort(range(len(text)), partial(bw_key, text)))
# Notice I've dropped the square brackets; this means I'm passing a generator
# expression to `join` instead of a list comprehension. In general, this is
# a little slower, but uses less memory. And the underlying code uses lazy
# evaluation heavily, so :)
def burroughs_wheeler_standard(text):
return ''.join([i[-1] for i in sorted([text[i:] + text[:i] for i in range(len(text))])])
def test(n):
data = ''.join(choice('abcdefghijklmnopqrstuvwxyz') for i in range(n)) + '$'
custom = partial(burroughs_wheeler_custom, data)
standard = partial(burroughs_wheeler_standard, data)
assert custom() == standard()
trials = 1000000 // n
custom_time = timeit(custom, number=trials)
standard_time = timeit(standard, number=trials)
print("custom: {} standard: {}".format(custom_time, standard_time))
trials
的数量所做的数学运算,与
test
字符串的长度成反比。这应该将用于测试的总时间保持在一个合理的狭窄范围内 - 对吗? ;)(当然是错误的,因为我们确定
standard
算法至少是 O(N^2)。)
>>> imp.reload(burroughs_wheeler)
<module 'burroughs_wheeler' from 'burroughs_wheeler.py'>
>>> burroughs_wheeler.test(100)
custom: 4.7095093091438684 standard: 0.9819262643716229
>>> burroughs_wheeler.test(1000)
custom: 5.532266880287807 standard: 2.1733253807396977
>>> burroughs_wheeler.test(10000)
custom: 5.954826800612864 standard: 42.50686064849015
关于python - python中Burrows-Wheeler的性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21297887/
您好,我在优化 burrows wheeler transform 时遇到一些困难.我正在尝试转换文本文件,但是转换像圣经这样的大型文本文件需要很长时间。 关于如何进行的任何想法? public Bu
如果我们将此 aaabccba 视为我们的输入字符串,则 baaacacb 将是对输入应用 Burrows-Wheeler 变换后的输出字符串。观察输出,您会看到两个聚集的 c 是分开的。很明显,输入
似乎许多实现 BWT 的压缩器将其与算术编码或霍夫曼编码结合使用。 (请随意提名更多,特别是如果他们更好的话。) 我的第一个问题是:为什么字典编码器(例如 LZW 或 LZSS)与 BWT 一起使用是
我已经成功地为我正在编写的 compression testbed 实现了 BWT 阶段(使用常规字符串排序)。我可以应用 BWT,然后逆 BWT 变换,输出与输入匹配。现在我想使用后缀数组加速创建
我正在用 Python 编写 Burrows-Wheeler 变换及其逆变换。它对于小弦工作得很好,但是当我测试更大的弦时它就崩溃了。在某些时候,字符串似乎会循环。我确信这一定与解码器的最终循环有关,
使用BWT后,编码数据中我们需要哪一组数据?我们是否需要对后缀数组进行编码(或导出)? 输入: 计算器 BWT 输出: wtavrcfkle$soo 后缀数组: 13, 2, 3, 7, 9, 4,
我在 Burrows Wheeler 转型中遇到了一些问题。这是一个大学项目,但这只是其中很小的一部分。整个项目由 3 种不同的算法组成,用于数据压缩。 我只是想弄清楚在 Burrows Wheele
我目前在 BWT 工作是为了好玩。 :-) 我学习了 BWT,我认为 BWT 在理论上并不复杂。但是,直到现在我还不知道如何在实际实现中实际对旋转的字符串进行排序。 我是否应该首先将所有旋转的字符串保
我正在尝试实现 block 排序。在 Burrows Wheeler Transform 论文中,Block Sorting 需要在原始字符串 S 后追加 k 个 EOF 字符,其中 EOF 没有出现
我需要在线性时间内执行著名的 Burrows-Wheeler 变换。我找到了一个带有后缀排序和 EOF 字符的解决方案,但是附加 EOF 会改变转换。例如:考虑字符串 bcababa 和两个旋转 s1
我首先想问一下 NHibernate.Burrow 是否适用于 NHibernate 3.0 (Linq)。我想使用这个框架将复杂的 session 处理委托(delegate)给它,然后专注于我正在
我的 ASP.Net MVC 应用程序出现以下运行时错误: NHibernate.MappingException: No persister for: MyProject.Model.MyDomai
我是一名优秀的程序员,十分优秀!