栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Python-pandas高性能笛卡尔积(CROSS JOIN)

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python-pandas高性能笛卡尔积(CROSS JOIN)

让我们从建立基准开始。解决此问题的最简单方法是使用临时“键”列:

def cartesian_product_basic(left, right):    return (       left.assign(key=1).merge(right.assign(key=1), on='key').drop('key', 1))cartesian_product_basic(left, right)  col1_x  col2_x col1_y  col2_y0      A       1      X      201      A       1      Y      302      A       1      Z      503      B       2      X      204      B       2      Y      305      B       2      Z      506      C       3      X      207      C       3      Y      308      C       3      Z      50

这是如何为两个Dataframe分配一个具有相同值(例如1)的临时“键”列的。

merge
然后对“键”执行多对多JOIN。

尽管多对多JOIN技巧适用于大小合理的Dataframe,但你会在较大数据上看到相对较低的性能。

更快的实现将需要NumPy。这是一些著名的一维笛卡尔积的NumPy实现。我们可以基于其中一些性能解决方案来获得所需的输出。但是,我最喜欢的是@senderle的第一个实现。

def cartesian_product(*arrays):    la = len(arrays)    dtype = np.result_type(*arrays)    arr = np.empty([len(a) for a in arrays] + [la], dtype=dtype)    for i, a in enumerate(np.ix_(*arrays)):        arr[...,i] = a    return arr.reshape(-1, la)  

通用化:对唯一或非唯一索引数据帧进行CROSS JOIN

免责声明

这些解决方案针对具有非混合标量dtype的Dataframes进行了优化。如果处理混合dtype,请自担风险!

此技巧适用于任何类型的Dataframe。我们使用上述方法计算Dataframes数字索引的笛卡尔积·,使用它来重新索引Dataframes,然后

def cartesian_product_generalized(left, right):    la, lb = len(left), len(right)    idx = cartesian_product(np.ogrid[:la], np.ogrid[:lb])    return pd.Dataframe(        np.column_stack([left.values[idx[:,0]], right.values[idx[:,1]]]))cartesian_product_generalized(left, right)   0  1  2   30  A  1  X  201  A  1  Y  302  A  1  Z  503  B  2  X  204  B  2  Y  305  B  2  Z  506  C  3  X  207  C  3  Y  308  C  3  Z  50np.array_equal(cartesian_product_generalized(left, right),    cartesian_product_basic(left, right))True

而且,沿着类似的路线,

left2 = left.copy()left2.index = ['s1', 's2', 's1']right2 = right.copy()right2.index = ['x', 'y', 'y']left2   col1  col2s1    A     1s2    B     2s1    C     3right2  col1  col2x    X    20y    Y    30y    Z    50np.array_equal(cartesian_product_generalized(left, right),    cartesian_product_basic(left2, right2))True

该解决方案可以推广到多个Dataframe。例如,

def cartesian_product_multi(*dfs):    idx = cartesian_product(*[np.ogrid[:len(df)] for df in dfs])    return pd.Dataframe(        np.column_stack([df.values[idx[:,i]] for i,df in enumerate(dfs)]))cartesian_product_multi(*[left, right, left]).head()   0  1  2   3  4  50  A  1  X  20  A  11  A  1  X  20  B  22  A  1  X  20  C  33  A  1  X  20  D  44  A  1  Y  30  A  1

进一步简化
cartesian_product当只处理两个 Dataframe 时,可能会出现一个不涉及@senderle的简单解决方案。使用np.broadcast_arrays,我们可以达到几乎相同的性能水平。

def cartesian_product_simplified(left, right):    la, lb = len(left), len(right)    ia2, ib2 = np.broadcast_arrays(*np.ogrid[:la,:lb])    return pd.Dataframe(        np.column_stack([left.values[ia2.ravel()], right.values[ib2.ravel()]]))np.array_equal(cartesian_product_simplified(left, right),    cartesian_product_basic(left2, right2))True

性能比较

在具有唯一索引的某些人为设计的Dataframe上对这些解决方案进行基准测试,

请注意,时间可能会根据你的设置,数据和cartesian_product适用的辅助功能选择而有所不同。

性能基准测试代码

这是时间脚本。上面定义了此处调用的所有功能。

from timeit import timeitimport pandas as pdimport matplotlib.pyplot as pltres = pd.Dataframe(       index=['cartesian_product_basic', 'cartesian_product_generalized',    'cartesian_product_multi', 'cartesian_product_simplified'],       columns=[1, 10, 50, 100, 200, 300, 400, 500, 600, 800, 1000, 2000],       dtype=float)for f in res.index:     for c in res.columns:        # print(f,c)        left2 = pd.concat([left] * c, ignore_index=True)        right2 = pd.concat([right] * c, ignore_index=True)        stmt = '{}(left2, right2)'.format(f)        setp = 'from __main__ import left2, right2, {}'.format(f)        res.at[f, c] = timeit(stmt, setp, number=5)ax = res.div(res.min()).T.plot(loglog=True) ax.set_xlabel("N"); ax.set_ylabel("time (relative)");plt.show()


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/430210.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号