我有一个Python数据集,其中有OrderNumbers、IsOurs、产品是否是我们的以及产品的成本金额。我们希望对每个订单进行分类,无论它是否仅包含我们的产品,是否包含产品的混合或仅包含其他产品的产品。我们可以按如下方式生成数据集:
# Number of orders and products
num_orders = 1000
max_products_per_order = 10
# Generate random OrderNumbers
order_numbers = np.repeat(np.arange(1, num_orders + 1), np.random.randint(1, max_products_per_order + 1, num_orders))
# Generate IsOurs column with random True/False values
is_ours = np.random.choice([True, False], size=len(order_numbers))
# Generate unique ProductID
product_ids = np.arange(1, len(order_numbers) + 1)
# Generate random amounts for each product
np.random.seed(42) # Set seed for reproducibility
amounts = np.round(np.random.uniform(10, 500, size=len(order_numbers)), 2)
# Create the DataFrame
df = pd.DataFrame({
'OrderNumber': order_numbers,
'ProductID': product_ids,
'IsOurs': is_ours,
'Amount': amounts
})
现在,为了计算它,我们可以执行以下操作:
第一个解决方案
df['OnlyOurs'] = df.groupby(['OrderNumber'])['IsOurs'].transform('all')
df['Mixed'] = df.groupby(['OrderNumber'])['IsOurs'].transform('any')
df['Mixed'] = df.Mixed & (df.OnlyOurs == False)
df['OnlyOther'] = (df.Mixed == False) & (df.OnlyOurs == False)
df['MixClass'] = "Mix"
df.loc[df['OnlyOther'], 'MixClass'] = "Other"
df.loc[df['OnlyOurs'], 'MixClass'] = "Ours"
df.groupby('MixClass')['Amount'].sum()
在我的电脑上,运行时间约为 40 毫秒,相当快。
如果我们写得优雅一点的话就是:
第二种解决方案
df['MixClass'] = df.groupby('OrderNumber')['IsOurs'].transform(
lambda x: 'Ours' if x.all() else 'Other' if not x.any() else 'Mix')
这运行速度明显慢了。我想知道我是否遗漏了一些关于如何提高单衬管性能的信息。我知道这是因为在第一个解决方案中我使用矢量化函数,在第二个解决方案中我没有定义自己的函数。然而,我想知道是否存在更优雅的方法,而不需要那么多“样板”代码。
提前谢谢您。
np.select
:
g = df.groupby('OrderNumber')['IsOurs']
condlist = [g.transform(f) for f in ['all', 'any']]
choicelist = ['Ours', 'Mix']
df['MixClass'] = np.select(condlist, choicelist, default='Other')
时间:
%timeit first_solution(df.copy())
%timeit second_solution(df.copy())
%timeit np_select(df.copy())
2.08 ms ± 590 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
84.7 ms ± 22.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
913 µs ± 31.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
平等
df_second.equals(df_np_select)
# True