Python 如何加速groupby.filter()操作?

Python 如何加速groupby.filter()操作?,python,pandas,pandas-groupby,Python,Pandas,Pandas Groupby,我有以下带有groupby函数的代码 order_diff = order.groupby("CD_QTY").filter( lambda x: x["BOX_ID"].nunique() > 1 ) 但是过滤功能非常慢 我想使用变换或映射功能。但变换和映射函数的结果与过滤函数的结果不同 我尝试过transform()和map() 我有点困惑,为什么结果与过滤器()不同。我将非常感谢您对此的反馈。谢谢。我的经验法则是,任何采用自定义

我有以下带有groupby函数的代码

 order_diff = order.groupby("CD_QTY").filter(
     lambda x: x["BOX_ID"].nunique() > 1
)

但是过滤功能非常慢

我想使用变换或映射功能。但变换和映射函数的结果与过滤函数的结果不同

我尝试过transform()和map()


我有点困惑,为什么结果与过滤器()不同。我将非常感谢您对此的反馈。谢谢。

我的经验法则是,任何采用自定义lambda的pandas函数都会由于循环而显著减慢,因此性能受到GIL的限制

如果您关心速度,请尽可能使用矢量化函数:

# Some mock data
n = 10_000

np.random.seed(42)
cd_qty = np.random.randint(1, n, n)
box_id = np.random.randint(1, 5, n)

order = pd.DataFrame({
    'CD_QTY': cd_qty,
    'BOX_ID': box_id
})

# The original solution. 1.59s
order_diff_1 = order.groupby("CD_QTY").filter(
     lambda x: x["BOX_ID"].nunique() > 1
)

# Vectorized. 8.5 ms -> 187x faster
count = order.groupby(['CD_QTY'])['BOX_ID'].nunique()
cond = order['CD_QTY'].isin(count[count > 1].index)
order_diff_2 = order.loc[cond]

# Check if they produce the same outputs
all(order_diff_1 == order_diff_2) # --> True

测试和您的两个解决方案都比公认的答案更快,以下是赢家:



这有助于您共享数据帧的示例吗?我尝试了完全相同的方法,但filter()的数据形状与map()和transform()的不同。您仍然可以通过仅在相关列上计算
nunique()
来提高速度(大约25%)(而不是在所有列上进行此操作,然后再进行子集设置):
count=order.groupby(['CD\u QTY'])['BOX\u ID'].nunique()
(5.44ms)。@PierreD我忽略了这一事实,因为模拟数据只有2columns@PierreD谢谢。我想知道transform('nunique')。gt(1)是否有效?@prb07-它是有效的,并且比上面的解决方案更快。
#using map()
order[order["CD_QTY"].map(order.groupby("CD_QTY")["BOX_ID"].nunique()).gt(1)]

# Some mock data
n = 10_000

np.random.seed(42)
cd_qty = np.random.randint(1, n, n)
box_id = np.random.randint(1, 5, n)

order = pd.DataFrame({
    'CD_QTY': cd_qty,
    'BOX_ID': box_id
})

# The original solution. 1.59s
order_diff_1 = order.groupby("CD_QTY").filter(
     lambda x: x["BOX_ID"].nunique() > 1
)

# Vectorized. 8.5 ms -> 187x faster
count = order.groupby(['CD_QTY'])['BOX_ID'].nunique()
cond = order['CD_QTY'].isin(count[count > 1].index)
order_diff_2 = order.loc[cond]

# Check if they produce the same outputs
all(order_diff_1 == order_diff_2) # --> True
# Some mock data
n = 10_000

np.random.seed(42)
cd_qty = np.random.randint(1, n, n)
box_id = np.random.randint(1, 5, n)

order = pd.DataFrame({
    'CD_QTY': cd_qty,
    'BOX_ID': box_id
})

count = order.groupby(['CD_QTY'])['BOX_ID'].nunique()
cond = order['CD_QTY'].isin(count[count > 1].index)
order_diff_2 = order.loc[cond]

order_diff = order[order.groupby("CD_QTY")["BOX_ID"].transform('nunique').gt(1)]
order_diff_3 =order[order["CD_QTY"].map(order.groupby("CD_QTY")["BOX_ID"].nunique()).gt(1)]

print (all(order_diff == order_diff_2))
True
print (all(order_diff == order_diff_3))
True
In [201]: %%timeit
     ...: count = order.groupby(['CD_QTY'])['BOX_ID'].nunique()
     ...: cond = order['CD_QTY'].isin(count[count > 1].index)
     ...: order_diff_2 = order.loc[cond]
     ...: 
4.8 ms ± 56.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [202]: %%timeit
     ...: order[order.groupby("CD_QTY")["BOX_ID"].transform('nunique').gt(1)]
     ...: 
4.02 ms ± 50.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [203]: %%timeit
     ...: order[order["CD_QTY"].map(order.groupby("CD_QTY")["BOX_ID"].nunique()).gt(1)]
     ...: 
4.31 ms ± 40.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)