Python 如何加速groupby.filter()操作?
我有以下带有groupby函数的代码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() 我有点困惑,为什么结果与过滤器()不同。我将非常感谢您对此的反馈。谢谢。我的经验法则是,任何采用自定义
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)