我具有以下函数,该函数使我可以在两个数据帧(data
和ref
)的行之间进行一些比较,并在匹配时返回两行的索引。>
def get_gene(row):
m = np.equal(row[0], ref.iloc[:,0].values) & np.greater_equal(row[2], ref.iloc[:,2].values) & np.less_equal(row[3], ref.iloc[:,3].values)
return ref.index[m] if m.any() else None
作为一个耗时的过程(data
中1.6M行25分钟,ref
中20K行25分钟),我试图通过并行化计算来加快速度。由于pandas本机不支持多处理,因此我使用了在SO上找到的这段代码,并且可以通过我的函数get_gene
正常工作。
def _apply_df(args):
df, func, kwargs = args
return df.apply(func, **kwargs)
def apply_by_multiprocessing(df, func, **kwargs):
workers = kwargs.pop('workers')
pool = multiprocessing.Pool(processes=workers)
result = pool.map(_apply_df, [(d, func, kwargs) for d in np.array_split(df, workers)])
pool.close()
df = pd.concat(list(result))
return df
这使我节省了9分钟的计算时间。但是,如果我理解正确,那么这段代码会将我的数据帧data
分解为4部分,并将每个数据帧发送到CPU的每个内核。因此,每个内核最终都要在40万行(来自data
分成4个)和20K行(ref
)之间进行比较。
我实际上想要做的是根据一个列中的值拆分两个数据框,以便我只计算同一“组”的数据框之间的比较:
data.get_group(['a'])
与ref.get_group(['a'])
data.get_group(['b'])
与ref.get_group(['b'])
data.get_group(['c'])
与ref.get_group(['c'])
等...
这将减少计算量。 data
中的每一行只能与ref
中的〜3K行进行匹配,而不能与所有2万行进行匹配。
因此,我试图修改上面的代码,但是我无法使其正常工作。
def apply_get_gene(df, func, **kwargs):
reference = pd.read_csv('genomic_positions.csv', index_col=0)
reference = reference.groupby(['Chr'])
df = df.groupby(['Chr'])
chromosome = df.groups.keys()
workers = multiprocessing.cpu_count()
pool = multiprocessing.Pool(processes=workers)
args_list = [(df.get_group(chrom), func, kwargs, reference.get_group(chrom)) for chrom in chromosome]
results = pool.map(_apply_df, args_list)
pool.close()
pool.join()
return pd.concat(results)
def _apply_df(args):
df, func, kwarg1, kwarg2 = args
return df.apply(func, **kwargs)
def get_gene(row, ref):
m = np.equal(row[0], ref.iloc[:,0].values) & np.greater_equal(row[2], ref.iloc[:,2].values) & np.less_equal(row[3], ref.iloc[:,3].values)
return ref.index[m] if m.any() else None
我很确定这与通过不同函数传递*args
和**kwargs
的方式有关(因为在这种情况下,我必须考虑要传递的我的已分解ref
数据帧和已分解的data
数据帧..)。
我认为问题出在函数_apply_df
之内。我以为我了解它的真正作用,但是df, func, kwargs = args
行仍然困扰着我,我认为我没有正确修改它。.
感谢所有建议!
答案 0 :(得分:0)
看看starmap()
:
starmap(func,iterable [,chunksize]) 与map()相似,只是可迭代的元素应该是作为参数解压缩的可迭代。
因此[[1,2,3,(3,4)]的可迭代结果为[func(1,2),func(3,4)]。
似乎正是您所需要的。
答案 1 :(得分:0)
我为可能偶然发现此帖子的读者发布了我想出的答案:
如@Michele Tonutti所述,我只需要使用starmap()
并在此处和此处进行一些调整。折衷方案是,它仅将我的自定义函数get_gene
与设置axis=1
一起使用,但是如果需要,可能有一种使它更灵活的方法。
def Detect_gene(data):
reference = pd.read_csv('genomic_positions.csv', index_col=0)
ref = reference.groupby(['Chr'])
df = data.groupby(['Chr'])
chromosome = df.groups.keys()
workers = multiprocessing.cpu_count()
pool = multiprocessing.Pool(processes=workers)
args = [(df.get_group(chrom), ref.get_group(chrom))
for chrom in chromosome]
results = pool.starmap(apply_get_gene, args)
pool.close()
pool.join()
return pd.concat(results)
def apply_get_gene(df, a):
return df.apply(get_gene, axis=1, ref=a)
def get_gene(row, ref):
m = np.equal(row[0], ref.iloc[:,0].values) & np.greater_equal(row[2], ref.iloc[:,2].values) & np.less_equal(row[3], ref.iloc[:,3].values)
return ref.index[m] if m.any() else None
现在,从以前的代码版本开始,大约需要5分钟而不是9分钟,而无需多处理则大约需要25分钟。