更新字典和检查键的最快方法

如何解决更新字典和检查键的最快方法

| 我正在建立一个非常长的字符串(〜1G)的字典,其中key是固定长度的k-mer,value是所有出现的位置。当k大(> 9)时,预构建k-mer词典是没有意义的,因为并非所有值都会出现并且会夸大表格。 目前,我正在执行以下任务:
def hash_string(st,mersize):

    stsize = len(st)
    hash = {}
    r = stsize-mersize+1

    for i in range(0,r):
        mer = st[i:i+mersize]
        if mer in hash:
            hash[mer].append(i)
        else:
            hash[mer] = [i]

    return hash

# test for function hash_st above        
mer3 = hash_string(\"ABCDABBBBBAAACCCCABCdddd\",3) 
最耗时的步骤(我做过cProfile)是查找遇到的键(随着我们在字符串中移动),是新键还是已经存在。最快的方法是什么? (我目前正在测试一种避免该步骤的两遍策略(对于大型序列,这要快得多),在该方法中,我首先通过简单地覆盖双精度字来构建键列表。然后,我不必检查密钥是否存在-我用这些密钥为dict播种,然后在第二遍时在遇到它们时进行附加操作。) 但是,我仍然有兴趣总结一下,在Python中查找字典键的最快方法,因为这是一种常见的模式: 如果存在密钥,则追加新条目,否则,创建密钥并添加一个元素。 什么是此模式的最快实现?     

解决方法

我会用
collections.defaultdict
import collections
...
hash = collections.defaultdict(list)
r = stsize-mersize+1

for i in range(0,r):
    mer = st[i:i+mersize]
    hash[mer].append(i)
尽管从没对它进行过分析,但它与
if ... else
无关。     ,通常,使用的方法将取决于您的数据。我已经构建了一些简单的测试,这些测试使用不同类型的数据来说明时序如何变化。 使用的字符串: 问题中的字符串。 较大的伪随机字符串(假定散列中具有更多不同的mers / key)。 哈希中几乎没有不同的mer / key的字符串。 这是一些测试各种方法的快速代码(我赞成the4ѭ的答案,因为它似乎是最快的)。
import random
from timeit import Timer
from collections import defaultdict

def test_check_first(st,mersize):
    \"\"\" Look for the existance of the mer in the dict.
    \"\"\"
    mer_hash = {}
    r = len(st)-mersize+1

    for i in range(0,r):
        mer = st[i:i+mersize]
        if mer in mer_hash:
            mer_hash[mer].append(i)
        else:
            mer_hash[mer] = [i]

    return mer_hash

def test_throw_exception(st,mersize):
    \"\"\" Catch the KeyError thown if a mer doesn\'t exist in the dict.
    \"\"\"
    mer_hash = {}
    r = len(st)-mersize+1

    for i in range(0,r):
        mer = st[i:i+mersize]
        try:
            mer_hash[mer].append(i)
        except KeyError:
            mer_hash[mer] = [i]

    return mer_hash

def test_defaultdict(st,mersize):
    \"\"\" Use a defaultdict.
    \"\"\"
    mer_hash = defaultdict(list)
    r = len(st)-mersize+1

    for i in range(0,r):
        mer = st[i:i+mersize]
        mer_hash[mer].append(i)

    return mer_hash

def test_dict_setdefault(st,mersize):
    \"\"\" Use dict\'s setdefault method
    \"\"\"
    mer_hash = {}
    r = len(st)-mersize+1

    for i in range(0,r):
        mer = st[i:i+mersize]
        mer_hash.setdefault(mer,[]).append(i)

    return mer_hash

def gen_pseudorandom_string(size):
    \"\"\" Generate a larger,more \"random\" string of data.
    \"\"\"
    # only use four letters
    letters = (\'A\',\'B\',\'C\',\'D\')
    return \'\'.join(random.choice(letters) for i in range(size))

if __name__ == \'__main__\':
    # test functions
    test_strings = (\'ABCDABBBBBAAACCCCABCDDDD\',gen_pseudorandom_string(1000),\'A\'*100 + \'B\'*100 + \'C\'*100 + \'D\'*100)
    mer_size = 3
    passes = 10000

    for string in test_strings:
        display_string = string if len(string) <= 30 else string[:30] + \'...\'
        print \'Testing with string: \"\' + display_string + \'\" and mer size: \' + str(mer_size) + \' and number of passes: \' + str(passes)

        t1 = Timer(\"test_check_first(string,mer_size)\",\"from __main__ import test_check_first,string,mer_size\")
        print \'\\tResults for test_check_first: \',print \"%.2f usec/pass\" % (1000000 * t1.timeit(number=passes)/passes)

        t2 = Timer(\"test_throw_exception(string,\"from __main__ import test_throw_exception,mer_size\")
        print \'\\tResults for test_throw_exception: \',print \"%.2f usec/pass\" % (1000000 * t2.timeit(number=passes)/passes)

        t3 = Timer(\"test_defaultdict(string,\"from __main__ import test_defaultdict,mer_size\")    
        print \'\\tResults for test_defaultdict: \',print \"%.2f usec/pass\" % (1000000 * t3.timeit(number=passes)/passes)

        t4 = Timer(\"test_dict_setdefault(string,\"from __main__ import test_dict_setdefault,mer_size\")    
        print \'\\tResults for test_dict_setdefault: \',print \"%.2f usec/pass\" % (1000000 * t4.timeit(number=passes)/passes)
这是在计算机上运行时得到的结果:
Testing with string: \"ABCDABBBBBAAACCCCABCDDDD\" and mer size: 3 and number of passes: 10000
    Results for test_check_first:  8.70 usec/pass
    Results for test_throw_exception:  22.78 usec/pass
    Results for test_defaultdict:  10.61 usec/pass
    Results for test_dict_setdefault:  8.88 usec/pass
Testing with string: \"BACDDDADAAABADBDADDBBBCAAABBBC...\" and mer size: 3 and number of passes: 10000
    Results for test_check_first:  305.19 usec/pass
    Results for test_throw_exception:  320.62 usec/pass
    Results for test_defaultdict:  254.56 usec/pass
    Results for test_dict_setdefault:  342.55 usec/pass
Testing with string: \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...\" and mer size: 3 and number of passes: 10000
    Results for test_check_first:  114.23 usec/pass
    Results for test_throw_exception:  107.96 usec/pass
    Results for test_defaultdict:  94.11 usec/pass
    Results for test_dict_setdefault:  125.72 usec/pass
    ,字典具有
detdefault
方法,该方法可以执行您想要的操作,但不确定它会快多少。 因此,您的新模式可以是:
hash.setdefault(mer,[]).append(i)
    ,您也可以尝试基于异常的方法:
# Python2-3 compatibility
try: xrange
except NameError: xrange= range

for i in xrange(r):
    mer = st[i:i+mersize]
    try: hash[mer].append(i)
    except KeyError: # not there
        hash[mer]= [i]
请注意,如果在大多数情况下未找到ѭ10this,它将比您的方法慢,但是在大多数情况下却未找到faster10。您知道自己的数据,可以做出选择。 另外,最好不要掩盖诸如ѭ11之类的内建函数。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?