在Python中优化数据框子集操作

时间:2019-12-16 14:54:35

标签: python pandas optimization bioinformatics

总结问题

我正在尝试优化我编写的某些代码。按照当前的形式,它可以按预期工作,但是由于需要大量的循环,因此脚本需要很长时间才能运行。

我正在寻找一种加速下述代码的方法。

详细说明问题

在这个称为master的数据框中,有3,936,192行。位置列代表基因组窗口。在该数据帧中存在76次。这样master[master['Position'] == 300]返回一个76行的数据帧,并且对于Position的每个唯一外观都类似。我对数据帧的这些子集中的每个子集执行一些操作。

可以找到数据here

我当前的代码采用以下形式:

import pandas as pd

master = pd.read_csv(data_location)

windows = sorted(set(master['Position']))

window_factor = []

               # loop through all the windows, look at the cohort of samples, ignore anything not CNV == 2
               # if that means ignore all, then drop the window entirely
               # else record the 1/2 mean of that windows normalised coverage across all samples. 

for window in windows:
    current_window = master[master['Position'] == window]

    t = current_window[current_window['CNV'] == 2]

    if t.shape[0] == 0:
        window_factor.append('drop')

    else:
        window_factor.append(
            np.mean(current_window[current_window['CNV'] == 2]['Normalised_coverage'])/2)

但是,这需要花费非常长的时间才能运行,尽管我知道必须有一个方法,但是我想不出一种方法来加快它的运行速度。

4 个答案:

答案 0 :(得分:2)

您的df并不大,并且在您的代码中几乎没有问题:

  • 如果您使用np.mean并且一个值为np.nan,则它将返回np.nan
  • 计算出平均值后可以除以2。
  • 在我看来,groupby的完美案例
  • 在其他结果为float时返回字符串,您可以考虑使用 改为np.nan
import pandas as pd

df = pd.read_csv("master.csv")

def fun(x):
    t = x[x["CNV"]==2]
    return t["Normalised_coverage"].mean()/2

# returns np.nan when len(t)==0
out = df.groupby('Position').apply(fun)
CPU times: user 34.7 s, sys: 72.5 ms, total: 34.8 s
Wall time: 34.7 s

groupby之前甚至更快地进行过滤

%%time
out = df[df["CNV"]==2].groupby("Position")["Normalised_coverage"].mean()/2

CPU times: user 82.5 ms, sys: 8.03 ms, total: 90.5 ms
Wall time: 87.8 ms

更新:在最后一种情况下,如果您确实需要跟踪df["CNV"]!=2所在的组,则可以使用以下代码:

import numpy as np
bad = df[df["CNV"]!=2]["Position"].unique()
bad = list(set(bad)-set(out.index))

out = out.reset_index(name="value")

out1 = pd.DataFrame({"Position":bad,
                     "value":[np.nan]*len(bad)})

out = pd.concat([out,out1],
                ignore_index=True)\
        .sort_values("Position")\
        .reset_index(drop=True)

160ms添加到您的计算中。

答案 1 :(得分:1)

您可以做几件事:

  • 考虑使用np.array而不是使用window_factor的python列表,因为 你知道数组的长度。
  • t已经current_window[current_window['CNV'] == 2]在计算np.mean时使用t

您还可以使用探查器来查看是否存在昂贵的操作,或者只是考虑使用C ++并重新实现代码(这非常简单)。

答案 2 :(得分:1)

我认为.groupby()函数正是您所需要的:

fac = []
for name,group in master.groupby('Position'):
    if all(group['CNV'] != 2):
        fac.append('drop')
    else:
        fac.append(np.mean(group[group['CNV'] == 2]['Normalised_coverage'])/2)


我下载了您的数据master.csv,生成的数据完全相同,笔记本电脑上的运行时间从6分钟减少到30秒。 希望对您有所帮助。

答案 3 :(得分:0)

使用groupby和query是我的解决方案。

{{1}}