如何在列名不同时将一个Pandas透视表(DataFrame)除以另一个?
我想要实现的目标
我正在使用pandas计算一些透视表,希望将其中一个除以另一个。
以下是一个虚构数据示例,我有某类商品的销售数据,想要计算总销售额(美元)、销售数量、单价等指标。
另一个场景是计算加权平均值,最后一步需要除以权重。
数据带有多重索引(multi-indices),因为这是按不同分类切片分析的结果(例如,在伦敦和纽约分别售出了多少高质量和低质量的小部件)。
最小可复现示例
在以下示例中,我创建了维度为7×8的DataFrame piv_all_sales:
- 7行:2个地区 × 3种产品 + 1行总计
- 8列:2个指标(总销售额gross sales、净销售额net sales) ×(3种品质(low、medium、high) + 1列总计)
piv_all_sales的样式如下:
piv_count统计销售商品的数量,维度为7×4:
我想要将前者除以后者,但DataFrame.div()方法无法生效——推测是因为两个DataFrame的列名不同。
另一个复杂点在于piv_all_sales有8列,而piv_count只有4列
import numpy as np import pandas as pd rng = np.random.default_rng(seed=42) df=pd.DataFrame() df['region'] = np.repeat(['USA','Canada'],12) df['product'] = np.tile(['apples','strawberries','bananas'],8) df['quality'] = np.repeat(['high','medium','low'],8) df['net sales'] = rng.integers(low=0, high=100, size=24) df['gross sales'] = rng.integers(low=50, high=150, size=24) df['# items sold'] = rng.integers(low=1, high=20, size=24) piv_net_sales = pd.pivot_table(data=df, values=['net sales'], index=['region','product'], columns=['quality'], aggfunc='sum', margins=True) piv_all_sales = pd.pivot_table(data=df, values=['net sales','gross sales'], index=['region','product'], columns=['quality'], aggfunc='sum', margins=True) piv_count = pd.pivot_table(data=df, values=['# items sold'], index=['region','product'], columns=['quality'], aggfunc='sum', margins=True)
我已尝试的方法
我不知道如何将7×8的DataFrame除以7×4的DataFrame。
因此我先尝试将7×4的DataFrame(仅包含净销售额的piv_net_sales)除以7×4的piv_count,但两种方式都无效:
out1 = piv_net_sales / piv_count out2 = piv_net_sales.div(piv_count)
推测是因为pandas会查找同名列,但未找到?
两种方式都生成了全为NaN的7×8 DataFrame。
部分低效解决方案
唯一可行的方法是将每个DataFrame转换为numpy数组,再进行除法运算。这样就无需考虑列名不同的问题,但存在以下缺点:
- 方法非常繁琐且不优雅,因为我需要将DataFrame转换为numpy数组,之后还要重新创建带有正确索引的DataFrame
- 我仍不知道如何将7×8的DataFrame除以7×4的DataFrame;或许可以将7×8的数组拆分为两个7×4的数组,分别计算后再合并?
该方法可行,但不够优雅且效率低下out3 = piv_net_sales.to_numpy() / piv_count.to_numpy()
类似问题
我找到了一些类似问题,例如:
How to divide two Pandas Pivoted Tables
但我无法将这些答案适配到我的场景中。
内容的提问来源于stack exchange,提问作者Pythonista anonymous

