总结问题
我正在尝试优化我编写的某些代码。按照当前的形式,它可以按预期工作,但是由于需要大量的循环,因此脚本需要很长时间才能运行。
我正在寻找一种加速下述代码的方法。
详细说明问题
在这个称为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)
但是,这需要花费非常长的时间才能运行,尽管我知道必须有一个方法,但是我想不出一种方法来加快它的运行速度。
答案 0 :(得分:2)
您的df
并不大,并且在您的代码中几乎没有问题:
np.mean
并且一个值为np.nan
,则它将返回np.nan
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)
您可以做几件事:
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}}