在没有spark集群的条件下,pandas处理上亿行数据的过程探索

        nlp萌新,最近在尝试一个AIDD的项目,期间遇到了一个有趣的问题,当把从zinc,enamine,ChemBL,CDDI等库中收集到的数据合并到一起后,是一个60多G的txt文件,是的,您没看错,60多G的txt,几亿行。果真如文献上所说,可探索的化学空间可达到10^80……

这种东西,最好的处理方式应该是分布式,用spark集群来处理,pyspark里就有很多pandas指令。碍于手头没有可用的资源,只能用最原始的方法,尝试最大程度的简化时间。

首先在数据读入上,就出现了问题,开始的操作很生猛,六十几G的数据,直接读,结果……

 等了很久很久以后,它崩溃了

真是难为pandas了,都是我不好…… 

        接下来,只好走上了类似分期还贷的方法,把数据切成了500M每个的小文件,然后逐个处理。

        切割数据命令行如下:

# 豪横吧,五千万行一个文件(ps:这要是钱该多好啊)
 split -l 50000000 *.txt

        就是这样,一个大文件切割成了几十个小文件。

        我的文件只含一个smiles编码,接下来,需要RDKit及Moses包来解析,以获得weight,logP,SA,QED等其他的分子信息。

import os
import pandas as pd
#显示所有列(参数设置为None代表显示所有行,也可以自行设置数字)
pd.set_option('display.max_columns',None)
#显示所有行
pd.set_option('display.max_rows',None)
#设置数据的显示长度,默认为50
pd.set_option('max_colwidth',200)
#禁止自动换行(设置为Flase不自动换行,True反之)
pd.set_option('expand_frame_repr', False)
from rdkit import rdBase, Chem
from rdkit.Chem import PandasTools, Descriptors, rdMolDescriptors, MolFromSmiles
from moses.metrics import QED, SA, logP, weight,mol_passes_filters
import time

# 解析smiles参数
inputdir = r'./data/dataset'
data = pd.DataFrame(columns = ['smiles','weight','logP','mol_passes_filters','get_n_rings'
                               ,'SA','QED'])
data_all = pd.DataFrame(columns = ['smiles','weight','logP','mol_passes_filters','get_n_rings'
                               ,'SA','QED'])
for parents,dirnames,filenames in os.walk(inputdir):
    for filename in filenames:
        df = pd.read_csv(os.path.join(parents,filename))
        df.columns = ['smiles']
        start = time.time()
        data['weight'] = df['smiles'].apply(lambda x: weight(Chem.MolFromSmiles(x)))
        data['logP'] = df['smiles'].apply(lambda x: logP(Chem.MolFromSmiles(x)))
        data['SA'] = df['smiles'].apply(lambda x: SA(Chem.MolFromSmiles(x)))
        data['QED'] = df['smiles'].apply(lambda x:QED(Chem.MolFromSmiles(x)))
        data['mol_passes_filters'] = df['smiles'].apply(lambda x:mol_passes_filters(x))
        end = time.time()
        print(end-start)
        zinc_all = zinc_all.append(data,ignore_index=True)
data_all.to_csv('data_all.csv')

9388.264369010925
8503.865498304367
………………
………………
………………
………………

平均解析一个文件9000s左右,等它解析完,柯南小学都毕业了…………

并行

上傻瓜式多线程函数——pandarallel,先来两个小简介:

最简单 pandas 多进程 方法 pandarallel - 知乎虽然 Python 有自己专门实现多进程多线程的包,可是用于 pandas 中却不是很好用,其实 pandas 有自己实现多进程的包,超级好用。 一、初次见面pandarallel 包 GitHub - nalepae/pandarallel at v1.5.2二、安装方…https://zhuanlan.zhihu.com/p/416002028GitHub - nalepae/pandarallel: A simple and efficient tool to parallelize Pandas operations on all available CPUshttps://github.com/nalepae/pandarallel先开个四线程耍耍,代码非常简单,上代码:

import os
import pandas as pd
#显示所有列(参数设置为None代表显示所有行,也可以自行设置数字)
pd.set_option('display.max_columns',None)
#显示所有行
pd.set_option('display.max_rows',None)
#设置数据的显示长度,默认为50
pd.set_option('max_colwidth',200)
#禁止自动换行(设置为Flase不自动换行,True反之)
pd.set_option('expand_frame_repr', False)
from rdkit import rdBase, Chem
from rdkit.Chem import PandasTools, Descriptors, rdMolDescriptors, MolFromSmiles
from moses.metrics import QED, SA, logP, weight,mol_passes_filters
from pandarallel import pandarallel
pandarallel.initialize(nb_workers=4)
import time


inputdir = r'./data/dataset'
data = pd.DataFrame(columns = ['smiles','weight','logP','mol_passes_filters','get_n_rings'
                               ,'SA','QED'])
dataset = pd.DataFrame(columns = ['smiles','weight','logP','mol_passes_filters','get_n_rings'
                               ,'SA','QED'])
for parents,dirnames,filenames in os.walk(inputdir):
    for filename in filenames:
        df = pd.read_csv(os.path.join(parents,filename))
        df.columns = ['smiles']
        start = time.time()
        data['weight'] = df['smiles'].parallel_apply(lambda x: weight(Chem.MolFromSmiles(x)))
        data['logP'] = df['smiles'].parallel_apply(lambda x: logP(Chem.MolFromSmiles(x)))
        data['SA'] = df['smiles'].parallel_apply(lambda x: SA(Chem.MolFromSmiles(x)))
        data['QED'] = df['smiles'].parallel_apply(lambda x:QED(Chem.MolFromSmiles(x)))
        data['mol_passes_filters'] = df['smiles'].parallel_apply(lambda x:mol_passes_filters(x))
        end = time.time()
        print(end-start)
        dataset = dataset.append(data,ignore_index=True)

2621.7469606399536
……………………
……………………
……………………
……………………

时间节约了四分之一,我要去开十线程,二十线程去了,回见

ps:关于多线程的使用,开太少达不到最佳优化,开太多也有可能过优化,上两个博客

已经处理完,整个耗时一天左右。发现了这个教程,是真的好用使用Python Pandas处理亿级数据 - Python - 开发语言与工具 - 深度开源

干货 | Python后台开发的高并发场景优化解决方案_Python大本营的博客-CSDN博客嘉宾 | 黄思涵来源 | AI科技大本营在线公开课互联网发展到今天,规模变得越来越大,也对所有的后端服务提出了更高的要求。在平时的工作中,我们或多或少都遇到过服务器压力过...https://blog.csdn.net/weixin_42232219/article/details/95131433?spm=1001.2101.3001.6650.11&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-11.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~Rate-11.pc_relevant_default&utm_relevant_index=16飞哥讲代码9:提升性能,线程数合适就行 - 蘭陵N梓記蘭陵N梓記 | 博客 | 软件 | 架构 | Java | Golanghttp://lanlingzi.cn/post/technical/2020/0718_code/

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值