首页 > 解决方案 > 如何提高 np.where 的性能(在 line_profiler 中占用 98% 的时间)

问题描述

我正在使用 np.where 搜索从大型数据帧中的文件读取的值,这需要 98% 的时间。代码运行大约需要 19 小时。

因此,此代码扫描包含 2 列约 50 万条记录的数据框,第一列包含数字,第二列包含文本。现在的工作流程是我逐行读取另一个文件,然后在数据框中搜索“alleleID”,并在匹配后从数据框中提取一些数据。我正在使用 np.where 代码执行此操作。

res = np.where(df['alleleID'] == alist[0])

这条线在 line_profiler 中大约占 98%。那么,我该如何改进呢?

经过研究,我在索引后尝试了 df.loc 但我发现的问题是,每次我搜索从文件中读取的一个等位基因 ID 并且它位于变量 (alist[0]) 中时,我无法将此变量传递给使用搜索

res = df.loc(alist[0])

因为 df.loc 总是期望一个值而不是一个变量。

将不胜感激任何帮助,以提高该程序的性能。谢谢你。完整代码如下:

with open('C:/Data/DATA/ClinVar/temp.dat', 'r') as varFile:
    count = 0
    dat1 = []
    dat2 = []
    dat3 = []
    dat4 = []
    dat5 = []
    dat6 = []
    dat7 = []
    dat8 = []
    dat9 = []
    dat10 = []
    dat11 = []
    dat12 = []
    dat13 = []
    dat14 = []
    dat15 = []
    dat16 = []
    dat17 = []
    dat18 = []
    dat19 = []
    dat20 = []
    dat21 = []
    dat22 = []
    dat23 = []
    dat24 = []
    dat25 = []
    dat26 = []
    dat27 = []
    dat28 = []
    dat29 = []
    dat30 = []
    dat31 = []
    dat32 = []
    dat33 = []
    dat34 = []
    dat35 = []
    dat36 = []
    dat37 = []
    dat38 = []
    dat39 = []
    dat40 = []
    for line in varFile:
        alist = line.split('\t')
        count += 1
        print(alist[0], "-", count)
        if(alist[1] == 'single nucleotide variant'):
            hgvs = '-'
            aaChange = ''
            otherID = '-'
            otherID1 = '-'
            uniProt = ''
            uniProt_var = ''
            omim_list = ''
            if alist[2] and not alist[2].isspace():
                hgvs = alist[2].split(' ')
                i = 0
                for i in range(0,len(hgvs)):
                    if(hgvs[i][0] == "("):
                        aaChange = hgvs[i]
            else:
                hgvs = '-'
            otherID = alist[28].split(',')
            j = 0
            omim = ''
            uniprot = ''
            hgmd = ''
            hbvar_list = ''
            uni_list = ''
            hgmd_list = ''
            flag1 = 0
            flag2 = 0
            flag3 = 0
            flag4 = 0
            flag5 = 0
            indices1 = [i for i, elem in enumerate(otherID) if 'OMIM' in elem]
            for b in range(0, len(indices1)):
                omim = otherID[indices1[b]].split(':')
                flag2 += 1
                if(flag2 == 2):
                    omim_list = omim_list+','+omim[1]
                    #print("OMIM_list",omim_list)
                else:
                    omim_list = omim[1]
            indices2 = [i for i, elem in enumerate(otherID) if 'HGMD' in elem]
            for b in range(0, len(indices2)):
                hgmd = otherID[indices2[b]].split(':')
                flag3 += 1
                if(flag3 == 2):
                    hgmd_list = hgmd_list+','+hgmd[1]
                else:
                    hgmd_list = hgmd[1]
            indices3 = [i for i, elem in enumerate(otherID) if 'HBVAR' in elem]
            for b in range(0, len(indices3)):
                hbvar = otherID[indices3[b]].split(':')
                flag4 += 1
                if(flag4 == 2):
                    hbvar_list = hbvar_list+','+hbvar[1]
                else:
                    hbvar_list = hbvar[1]
            indices4 = [i for i, elem in enumerate(otherID) if 'UniProtKB' in elem]
            for b in range(0, len(indices4)):
                otherID1 = otherID[indices4[b]].split(':')
                flag5 += 1
                if(flag5 == 2):
                    uni_list = uni_list+','+otherID1[1]
                else:
                    uni_list = otherID1[1]
            AF_ESP = ''
            AF_EXAC = ''
            AF_TGP = ''
            res = np.where(df['alleleID'] == alist[0])
            if res[0].size != 0:
                res1 = df['info'][res[0][0]].split(';')
                indices5 = [i for i, elem in enumerate(res1) if 'AF_ESP' in elem]
                for b in range(0, len(indices5)):
                    res2 = res1[indices5[b]].split('=')
                    AF_ESP = res2[1]
                indices6 = [i for i, elem in enumerate(res1) if 'AF_EXAC' in elem]
                for b in range(0, len(indices6)):
                    res2 = res1[indices6[b]].split('=')
                    AF_EXAC = res2[1]
                indices7 = [i for i, elem in enumerate(res1) if 'AF_TGP' in elem]
                for b in range(0, len(indices7)):
                    res2 = res1[indices7[b]].split('=')
                    AF_TGP = res2[1]
            alist[30] = alist[30].rstrip('\n')

            dat1.append(alist[0])
            dat2.append(alist[1])
            dat3.append(alist[2])
            dat4.append(hgvs[0])
            dat5.append(aaChange)
            dat6.append(omim_list)
            dat7.append(uni_list)
            dat8.append(hgmd_list)
            dat9.append(hbvar_list)
            dat10.append(alist[3])
            dat11.append(alist[4])
            dat12.append(alist[5])
            dat13.append(alist[6])
            dat14.append(alist[7])
            dat15.append(alist[8])
            dat16.append(alist[9])
            dat17.append(alist[10])
            dat18.append(alist[11])
            dat19.append(alist[12])
            dat20.append(alist[13])
            dat21.append(alist[14])
            dat22.append(alist[15])
            dat23.append(alist[16])
            dat24.append(alist[17])
            dat25.append(alist[18])
            dat26.append(alist[19])
            dat27.append(alist[20])
            dat28.append(alist[21])
            dat29.append(alist[22])
            dat30.append(alist[23])
            dat31.append(alist[24])
            dat32.append(alist[25])
            dat33.append(alist[26])
            dat34.append(alist[27])
            dat35.append(alist[28])
            dat36.append(alist[29])
            dat37.append(alist[30])
            dat38.append(AF_ESP)
            dat39.append(AF_EXAC)
            dat40.append(AF_TGP)

# Creating DF from lists
df1 = []
df1 = pd.DataFrame(list(zip(dat1,dat2,dat3,dat4,dat5,dat6,dat7,dat8,dat9,dat10,dat11,dat12,dat13,dat14,dat15,dat16,dat17,dat18,dat19,dat20,dat21,dat22,dat23,dat24,dat25,dat26,dat27,dat28,dat29,dat30,dat31,dat32,dat33,dat34,dat35,dat36,dat37,dat38,dat39,dat40)), columns = ['alleleID','Type','Name','HGVSName','ProteinChange','OMIM','UniProt','HGMD','HBVAR','GeneID','GeneSymbol','HGNC_ID','ClinicalSignificance','ClinSigSimple','LastEvaluated',"RS# (dbSNP)",'nsv/esv (dbVar)','RCVaccession','PhenotypeIDS','PhenotypeList','Origin','OriginSimple','Assembly','ChromosomeAccession','Chromosome','Start','Stop','ReferenceAllele','AlternateAllele','Cytogenetic','ReviewStatus','NumberSubmitters','Guidelines','TestedInGTR','OtherIDs','SubmitterCategories','VariationID','AF_ESP','AF_EXAC','AF_TGP'])

标签: pythonpandasdataframesearch

解决方案


好吧,我终于能够加速这个程序,只需用 df.loc 替换 np.where 就可以将它从 19 小时缩短到 5 小时左右。这是替换的代码:

df.loc[df['alleleID'].isin([a1[0]]), 'info'].values

有许多方法可以实现 df.loc 搜索/过滤,但有趣或令人惊讶的是,在互联网上,所有这些方法都给出了作为字符串传递的值的示例(例如:像 '9879' 或 'hosting')。像这样的东西,我必须在 df 中搜索 15072。

df.loc[df['alleleID'] == '15072']

现在,这工作正常,但我的问题是我正在从另一个文件中读取值,所以我在变量中有值,所以我尝试如下:

var = 15072
df.loc[df['alleleID'] == var]

现在,这个不起作用并由于某种原因给出错误。

因此,我进行了更多探索并做了一些修改,并使用了一个只有一个值的列表。如下:

list_a = []
list_a = ['15072']
df.loc[df['alleleID'].isin([list_a[0]]), 'info'].values

这终于奏效了,从 19 小时到 5 小时有了很大的改善。


推荐阅读