- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个包含一列值的文件,我想用它来与包含两个共同构成一个范围的值的字典进行比较。
例如:文件A:
Chr1 200 ....
Chr3 300
文件 B:
Chr1 200 300 ...
Chr2 300 350 ...
现在我为文件 B 创建了一个值字典:
for Line in FileB:
LineB = Line.strip('\n').split('\t')
Ranges[Chr].append(LineB)
为了比较:
for Line in MethylationFile:
Line = Line.strip("\n")
Info = Line.split("\t")
Chr = Info[0]
Location = int(Info[1])
Annotation = ""
for i, r in enumerate(Ranges[Chr]):
n = i + 1
while (n < len(Ranges[Chr])):
if (int(Ranges[Chr][i][1]) <= Location <= int(Ranges[Chr][i][2])):
Annotation = '\t'.join(Ranges[Chr][i][4:])
n +=1
OutFile.write(Line + '\t' + Annotation + '\n')
如果我离开 while 循环,程序似乎不会运行(或者可能运行得太慢而无法获得结果),因为我在每个字典中有超过 7,000 个值。如果我将 while 循环更改为 if 循环,程序会运行但速度非常慢。
我正在寻找一种让这个程序更快更高效的方法
最佳答案
当您想通过精确匹配查找键时,字典非常有用。特别是,查找键的哈希值必须与存储键的哈希值相同。
如果您的范围是一致的,您可以通过编写一个散列函数来伪造这一点,该散列函数为一个范围以及该范围内的每个值返回相同的值。但如果不是,则此哈希函数将必须跟踪所有已知范围,这会将您带回到您开始时遇到的相同问题。
在那种情况下,这里正确的数据结构可能是某种排序集合。如果您只需要建立集合,然后多次使用它而不修改它,只需对列表进行排序
并使用 bisect
模块会为你做。如果您需要在创建后修改集合,您将需要围绕二叉树或某种 B 树变体构建的东西,例如 blist
或 bintrees
.
这将减少查找范围从 N/2 到 log2(N) 的时间。因此,如果您有 10000 个范围,而不是 5000 次比较,您将进行 14 次。
当我们这样做时,将范围开始值和结束值转换为整数一次而不是每次都这样做会有所帮助。此外,如果您想使用标准库 bisect
,不幸的是您无法将 key
传递给大多数函数,因此让我们也将范围重新组织为可比较的顺序。所以:
for Line in FileB:
LineB = Line.strip('\n').split('\t')
Ranges[Chr].append(int(LineB[1]), int(LineB[2]), [LineB[0])
for r in Ranges:
r.sort()
现在,代替这个循环:
for i, r in enumerate(Ranges[Chr]):
# ...
这样做:
i = bisect.bisect(Ranges[Chr], (Location, Location, None))
if i:
r = Ranges[Chr][i-1]
if r[0] <= Location < r[1]:
# do whatever you wanted with r
else:
# there is no range that includes Location
else:
# Location is before all ranges
你必须仔细考虑 bisect
,我有可能在第一次尝试时就弄错了,所以......阅读文档了解它的作用,并用你的数据进行实验(打印出 bisect
函数的结果),然后再相信它。
如果您的范围可以重叠,并且您希望能够找到包含一个值的所有范围,而不仅仅是一个值,那么您将需要更多的东西来保持效率。无法对重叠范围进行完全排序,因此 bisect
不会切断它。
如果您期望每次平均查找超过 log N 个匹配项,您可以使用两个排序列表和 bisect
来实现。
但除此之外,您需要更复杂的数据结构和更复杂的代码。例如,如果您可以节省 N^2 空间,则可以通过为第一个列表中的每个范围创建一个第二个列表(按末尾排序)并将所有具有匹配开头的值的值保持在 log N。
在这一点上,我认为它已经变得非常复杂,以至于您想寻找一个库来为您做这件事。
但是,您可能需要考虑不同的解决方案。
如果您使用 numpy
或者数据库而不是纯 Python,这不能将算法复杂度从 N 降低到 log N……但它可以将恒定开销降低 10 倍左右,这可能已经足够好了。事实上,如果您在中小型列表上进行大量搜索,它甚至可能更好。
此外,它看起来更简单,一旦你习惯了数组操作或 SQL,它甚至可能更具可读性。所以:
RangeArrays = [np.array(a[:2] for a in value) for value in Ranges]
... 或者,如果 Ranges
是将字符串映射到值的字典,而不是列表:
RangeArrays = {key: np.array(a[:2] for a in value) for key, value in Ranges.items()}
然后,代替这个:
for i, r in enumerate(Ranges[Chr]):
# ...
做:
comparisons = Location < RangeArrays[Chr]
matches = comparisons[:,0] < comparisons[:,1]
indices = matches.nonzero()[0]
for index in indices:
r = Ranges[indices[0]]
# Do stuff with r
(您当然可以让事情变得更简洁,但值得这样做并打印出所有中间步骤以查看其工作原理。)
或者,使用数据库:
cur = db.execute('''SELECT Start, Stop, Chr FROM Ranges
WHERE Start <= ? AND Stop > ?''', (Location, Location))
for (Start, Stop, Chr) in cur:
# do stuff
关于Python 加速在范围字典中搜索值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16530224/
我正在处理一组标记为 160 个组的 173k 点。我想通过合并最接近的(到 9 或 10 个组)来减少组/集群的数量。我搜索过 sklearn 或类似的库,但没有成功。 我猜它只是通过 knn 聚类
我有一个扁平数字列表,这些数字逻辑上以 3 为一组,其中每个三元组是 (number, __ignored, flag[0 or 1]),例如: [7,56,1, 8,0,0, 2,0,0, 6,1,
我正在使用 pipenv 来管理我的包。我想编写一个 python 脚本来调用另一个使用不同虚拟环境(VE)的 python 脚本。 如何运行使用 VE1 的 python 脚本 1 并调用另一个 p
假设我有一个文件 script.py 位于 path = "foo/bar/script.py"。我正在寻找一种在 Python 中通过函数 execute_script() 从我的主要 Python
这听起来像是谜语或笑话,但实际上我还没有找到这个问题的答案。 问题到底是什么? 我想运行 2 个脚本。在第一个脚本中,我调用另一个脚本,但我希望它们继续并行,而不是在两个单独的线程中。主要是我不希望第
我有一个带有 python 2.5.5 的软件。我想发送一个命令,该命令将在 python 2.7.5 中启动一个脚本,然后继续执行该脚本。 我试过用 #!python2.7.5 和http://re
我在 python 命令行(使用 python 2.7)中,并尝试运行 Python 脚本。我的操作系统是 Windows 7。我已将我的目录设置为包含我所有脚本的文件夹,使用: os.chdir("
剧透:部分解决(见最后)。 以下是使用 Python 嵌入的代码示例: #include int main(int argc, char** argv) { Py_SetPythonHome
假设我有以下列表,对应于及时的股票价格: prices = [1, 3, 7, 10, 9, 8, 5, 3, 6, 8, 12, 9, 6, 10, 13, 8, 4, 11] 我想确定以下总体上最
所以我试图在选择某个单选按钮时更改此框架的背景。 我的框架位于一个类中,并且单选按钮的功能位于该类之外。 (这样我就可以在所有其他框架上调用它们。) 问题是每当我选择单选按钮时都会出现以下错误: co
我正在尝试将字符串与 python 中的正则表达式进行比较,如下所示, #!/usr/bin/env python3 import re str1 = "Expecting property name
考虑以下原型(prototype) Boost.Python 模块,该模块从单独的 C++ 头文件中引入类“D”。 /* file: a/b.cpp */ BOOST_PYTHON_MODULE(c)
如何编写一个程序来“识别函数调用的行号?” python 检查模块提供了定位行号的选项,但是, def di(): return inspect.currentframe().f_back.f_l
我已经使用 macports 安装了 Python 2.7,并且由于我的 $PATH 变量,这就是我输入 $ python 时得到的变量。然而,virtualenv 默认使用 Python 2.6,除
我只想问如何加快 python 上的 re.search 速度。 我有一个很长的字符串行,长度为 176861(即带有一些符号的字母数字字符),我使用此函数测试了该行以进行研究: def getExe
list1= [u'%app%%General%%Council%', u'%people%', u'%people%%Regional%%Council%%Mandate%', u'%ppp%%Ge
这个问题在这里已经有了答案: Is it Pythonic to use list comprehensions for just side effects? (7 个答案) 关闭 4 个月前。 告
我想用 Python 将两个列表组合成一个列表,方法如下: a = [1,1,1,2,2,2,3,3,3,3] b= ["Sun", "is", "bright", "June","and" ,"Ju
我正在运行带有最新 Boost 发行版 (1.55.0) 的 Mac OS X 10.8.4 (Darwin 12.4.0)。我正在按照说明 here构建包含在我的发行版中的教程 Boost-Pyth
学习 Python,我正在尝试制作一个没有任何第 3 方库的网络抓取工具,这样过程对我来说并没有简化,而且我知道我在做什么。我浏览了一些在线资源,但所有这些都让我对某些事情感到困惑。 html 看起来
我是一名优秀的程序员,十分优秀!