优化 Python 中的数据帧子集操作



总结问题

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

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

详细说明问题

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

数据可以在这里找到

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

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)

但是,这需要很长时间才能运行,我想不出加快速度的方法,尽管我知道一定有一个。

你的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

我认为.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)

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

您可以执行以下几项操作:

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

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

使用 groupby 和查询是我采用的解决方案。

import pandas as pd
import numpy as np
master = pd.read_csv("/home/sean/Desktop/master.csv", index_col=0)
windows = sorted(set(master['Position']))
g = master.groupby("Position")
master.query("Position == 24386700").shape
g = master.query("CNV == 2").groupby("Position")
p = g.Normalised_coverage.mean() / 2

最新更新