繁体   English   中英

从Pandas Dataframe并行/矢量化组合计算

[英]Parallelize/vectorize computation of combinations from Pandas Dataframe

我有许多腌制的熊猫数据框,每行都有相当数量的行(〜10k)。 数据帧的列之一是浮点数的numpy ndarray(是的,我特别选择将数组数据存储在单个单元格内-我读过这通常不是正确的方法,例如, here ,但是在此如果单个值没有意义,那么只有完整的值列表才具有意义,因此在这种情况下,我认为这很有意义。 我需要计算框架中每对行之间的欧式距离。 我有为此工作的代码,但我希望我可以做一些事情来改善它的性能,因为现在它告诉我较小的数据集将需要一个月以上的时间,但是我敢肯定它会花费我所有的记忆早在那之前。

代码如下:

import pandas as pd
import sys
import getopt
import math
from scipy.spatial import distance
from timeit import default_timer as timer
from datetime import timedelta

id_column_1 = 'id1'
id_column_2 = 'id2'
distance_column = 'distance'
val_column = 'val'

# where n is the size of the set
# and k is the number of elements per combination
def combination_count(n, k):
    if k > n:
        return 0
    else:
        # n! / (k! * (n - k)!)
        return math.factorial(n)/(math.factorial(k) * math.factorial(n - k))

def progress(start, current, total, id1, id2):
    if current == 0:
        print('Processing combination #%d of #%d, (%d, %d)' % (current, total, id1, id2))
    else:
        percent_complete = 100 * float(current)/float(total)
        elapsed_time = timer() - start
        avg_time = elapsed_time / current
        remaining = total - current
        remaining_time = timedelta(seconds=remaining * avg_time)
        print('Processing combination #%d of #%d, (%d, %d). %.2f%% complete, ~%.2f s/combination, ~%s remaining' % (current, total, id1, id2, percent_complete, avg_time, remaining_time))

def check_distances(df):
    indexes = df.index
    total_combinations = combination_count(len(indexes), 2)
    current_combination = 0
    print('There are %d possible inter-message relationships to compute' % total_combinations)
    distances = pd.DataFrame(columns=[id_column_1, id_column_2, distance_column])
    distances.set_index([id_column_1, id_column_2], inplace=True)
    start = timer()
    for id1 in indexes:
        for id2 in indexes:
            # id1 is always < id2
            if id1 >= id2:
                continue
            progress(start, current_combination, total_combinations, id1, id2)
            distances.loc[(id1, id2), distance_column] = distance.euclidean(df.loc[id1, embeddings_column], df.loc[id2, embeddings_column])
            current_combination+=1

(我排除了main()函数,该函数仅提取args并基于它们在腌制的文件中加载)

我最近才真正开始使用Python来完成此任务,因此我很可能会错过一些简单的东西,有没有很好的方法来解决这个问题?

在纯python中,有一些用于并行计算数据帧的选项。
最完整的可能是愚蠢的
一个更简单但更容易的选择是pandaral-lel

因此解决方案最终是并行化,但是我无法使用Panda特定的并行化库弄清楚这一点,因为预期的结果不是对现有单元格内容的转换,而是从另一个数据帧派生的新值。

我抓住了joblib库 ,并执行以下步骤:

首先,我创建了一个函数,给定两个id,该函数可以返回该索引的行(由于单独的工作程序无法在主流程中更改数据框,因此我们不得不转向首先生成所有数据的范式,然后构建数据框):

def get_distance(df, id1, id2):
    return [id1, id2, distance.euclidean(df.loc[id1, embeddings_column], df.loc[id2, embeddings_column])]

并对其应用joblib并行化:

def get_distances(df):
    indexes = df.index
    total_combinations = combination_count(len(indexes), 2)
    current_combination = 0
    print('There are %d possible inter-message relationships to compute' % total_combinations)
    data = Parallel(n_jobs=-1)(delayed(get_distance)(df, min(ids), max(ids)) for ids in combinations(indexes, 2))
    distances = pd.DataFrame(data, columns=[id_column_1, id_column_2, distance_column])
    distances.set_index([id_column_1, id_column_2], inplace=True)
    return distances

在预期的时间内,这可以从数月到数天立即得到改善,但是我怀疑传递整个数据帧会造成大量开销。

将功能修改为仅传递所需的值后,又获得了不到一天(约20小时)的立即改进:

def get_distance(id1, id2, embed1, embed2):
    return [id1, id2, distance.euclidean(embed1, embed2)]

# ...later, in get_distances()...

data = Parallel(n_jobs=-1)(delayed(get_distance)(min(ids), max(ids), df.loc[ids[0], embeddings_column], df.loc[ids[1], embeddings_column]) for ids in combinations(indexes, 2))

最后,基于joblib的文档以及大量数据仍在传输给工作人员这一事实,我交换了到多处理后端,并看到预期的时间进一步减少到1.5小时左右。 (我还添加了tqdm库,因此我可以比joblib提供更好的进度想法)

data = Parallel(n_jobs=-1, backend='multiprocessing')(delayed(get_distance)(min(ids), max(ids), df.loc[ids[0], embeddings_column], df.loc[ids[1], embeddings_column]) for ids in tqdm(combinations(indexes, 2), total=total_combinations))

希望这可以帮助其他人首次涉足Python并行化!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM