您拥有的数据由数学阶跃函数描述,staircase 已为此目的构建在 pandas 和 numpy 之上。
设置
df = pd.DataFrame(
{
"start":[1,8,3,3],
"end":[12,15,7,8],
"user":["A", "A", "B", "B"],
"product":["X_1", "X_1", "X_1", "X_2"],
"usage_rate":[10,20,3,70]
}
)
解决方案
我们将为每个用户和产品创建一个阶梯函数。阶梯函数由staircase.Stairs 类表示。这个类是 staircase 就像 Series 是 pandas。为此,我们根据这些变量对数据帧进行分组,并将子数据帧传递给Stairs constructor。
import staircase as sc
stepfunctions = df.groupby(["user", "product"]).apply(sc.Stairs, "start", "end", "usage_rate")
我们的stepfunctions 变量如下所示。它是一个系列,具有多索引,值为Stairs 对象。
user product
A X_1 <staircase.Stairs, id=2516839332104>
B X_1 <staircase.Stairs, id=2516834889160>
X_2 <staircase.Stairs, id=2516835627464>
dtype: object
您可以使用staircase 中的步进函数做很多事情,包括绘图。
stepfunctions["A", "X_1"].plot(style="hlines")
您想要做的是create bins and integrate(找到下面的区域)这些步进函数。对于阶跃函数sf,这意味着以下计算
sf.slice([0,4,8,12,16]).integral()
我们可以使用pandas.Series.apply 对我们所有的步进函数执行此操作。
binned = stepfunctions.apply(lambda sf: sf.slice([0,4,8,12,16]).integral())
binned 变量将是一个数据框,与stepfunctions 具有相同的索引,每个 bin 间隔有一列
[0, 4) [4, 8) [8, 12) [12, 16)
user product
A X_1 30.0 40.0 120.0 60.0
B X_1 3.0 9.0 0.0 0.0
X_2 70.0 280.0 0.0 0.0
要在tidy format 中获取此数据,可以使用以下方法
tidy_result = binned.melt(ignore_index=False).rename({"variable":"bin"}).reset_index()
tidy_result 数据框将如下所示:
user product bin value
0 A X_1 [0, 4) 30.0
1 B X_1 [0, 4) 3.0
2 B X_2 [0, 4) 70.0
3 A X_1 [4, 8) 40.0
4 B X_1 [4, 8) 9.0
5 B X_2 [4, 8) 280.0
6 A X_1 [8, 12) 120.0
7 B X_1 [8, 12) 0.0
8 B X_2 [8, 12) 0.0
9 A X_1 [12, 16) 60.0
10 B X_1 [12, 16) 0.0
11 B X_2 [12, 16) 0.0
这对于您的目的可能已经足够了。如果您想以您提交的确切格式获取它,那么这应该很容易:
- 使用
tidy_result.pivot(index=["user", "bin"], columns="product") 将产品列转换为每个产品的列。用 0 填充 A 和 X_2 的 NA 值。
- 使用
tidy_result["start"] = pd.IntervalIndex(tidy_result["bin"]).left等
回顾一下,解决方案(导入后)归结为以下三行
stepfunctions = df.groupby(["user", "product"]).apply(sc.Stairs, "start", "end", "usage_rate")
binned = stepfunctions.apply(lambda sf: sf.slice([0,4,8,12,16]).integral())
tidy_result = binned.melt(ignore_index=False).rename({"variable":"bin"}).reset_index()