为啥我的Python这么慢 - 项查找 (二)
上一篇为啥我的Python这么慢, 字符串的加和和join被陈群主分享到biopython-生信
QQ群时,乐平指出字典的写法存在问题,并给了一篇知乎的链接https://zhuanlan.zhihu.com/p/28738634指导如何高效字典操作。
根据那篇文章改了两处写法,如下 (存储于readFaJoin2.py文件中):
from collections import defaultdict
aDict = defaultdict(list)
for line in open("GRCh38.fa"):
if line[0] == '>':
key = line[1:-1]
else:
aDict[key].append(line.strip())
#----------------------------------------
for key, value in aDict.iteritems():
aDict[key] = ''.join(value)
比之前提速接近2s
。一个是使用了defaultdict
初始化字典,另外一个是用iteritems
遍历字典,节省近一半的内存。
time python readFaJoin2.py
real 0m49.114s
user 0m38.442s
sys 0m10.565s
defaultdict
用在这效果不太明显,之前处理全基因组每个位点数据的频繁存取时,defaultdict
在程序无论速度还是写法上都有很大提升。
字典本身还有更多高效用法,可以去参考知乎的那篇文章。这儿介绍的是妙用字典的哈希属性快速查找项。
在生信操作中,常常会在一个大矩阵中匹配已小部分基因或位点,提取关注的基因或位点的信息。最开始的写法是:
targetL = ['a', 'n', 'c', 'd']
if item in targetL:
other_operations
后来,随着数据量变大,发现这个速度并不快,于是换了下面的方式
targetL = ['a', 'n', 'c', 'd']
targetD = dict.fromkeys(targetL, 0)
if item in targetD:
other_operations
又可以愉快的查询了。
为什么呢?
这是因为:在Pyhton
中列表的查询时间复杂度是O(n)
(n
是列表长度);字典的查询负责度是O(1)
(与字典长度无关)。
字典的查询复杂度为什么是O(1)
呢? Python中实现了一个hash
函数,把字典的key
转换为哈希
值,组成连续地址的数字哈希表
。字典的每次查询转换为了从数组特定位置取出一个元素,所以时间复杂度为O(1)
。
后来发现python
中set
也是用hash table
存储,所以上面的程序,可以更简化而不影响速度。
targetS = set(['a', 'n', 'c', 'd'])
if item in targetS:
other_operations
那么速度到底差多大,有没有直观一些的展示呢? 这是StackOverflow的一个简化例子, 百万倍速度差异。
ct@ehbio:~$ python -mtimeit -s 'd=range(10**7)' '5*10**6 in d'
10 loops, best of 3: 182 msec
per loop
ct@ehbio:~$ python -mtimeit -s 'd=dict.fromkeys(range(10**7))' '5*10**6 in d'
10000000 loops, best of 3: 0.16 usec
per loop
ct@ehbio:~$ python -mtimeit -s 'd=set(range(10**7))' '5*10**6 in d'
10000000 loops, best of 3: 0.164 usec
per loop
Ref:
- 速度测试例子 https://stackoverflow.com/questions/513882/python-list-vs-dict-for-look-up-table
- python各数据结构时间复杂度 https://wiki.python.org/moin/TimeComplexity
。
- dedecms自增标签[field:global.autoindex/]的运用
- dedecms调用副栏目文章怎么操作
- 12个非常有用的JavaScript技巧
- 使用JPA中@Query 注解实现update 操作
- 配合dedecms内容模型实现后台输入栏目id前端输出文章列表
- SpringBoot之前端文件管理
- Spring Boot 设置静态资源访问
- IDEA更换主题
- 用正则表达式给字符串属性值都加上双引号
- Spring Boot修改启动端口
- Packet for query is too large (12238 > 1024). You can change this value
- win10下端口被占用解决办法
- 微信小程序开发教程第九章:微信小程序拍照收纳开发以及删除名片等
- centos 安装sbt
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【redis6.0.6】redis源码慢慢学,慢慢看 -- 第三天:MakeFile
- 继续学习Shell脚本(详细)
- 将linux终端的输出信息保存到log中
- UNIX网络编程卷1(第三版)一个简单的时间获取服务器的程序
- Python数据分析实战(3)Python实现数据可视化
- xresloader转表工具链增加了一些新功能(map,oneof支持,输出矩阵,基于模板引擎的加载代码生成等)
- 数据结构之树
- UNIX网络编程卷1(第三版)套接字编程简介
- UNIX网络编程卷1(第三版)readn,writen和readline函数
- UNIX网络编程卷1(第三版)基本TCP套接字编程
- Ubuntu下linux映射共享盘到window下方法
- 数据同步写入磁盘:sync
- 惯用的关机命令:shutdown
- 重启、关机:reboot,halt,poweroff
- 使用Docker构建ZooKeeper镜像