看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
本案例有两个表,两个表的形状相同,通过这两个表计算一个新表。这两个表分别提供了新表的计算方法,其中涉及将计算规则展开填充到新表中。
两个表分别是:
import pandas as pd
import io
data1 = '''
A B C D E
2020-01-02 1.0 3.2 4.2 NaN 2.0
2020-01-03 NaN 2.1 NaN 3.4 NaN
2020-01-06 NaN NaN NaN NaN NaN
2020-01-07 NaN NaN NaN NaN 1.0
2020-01-08 1.0 NaN NaN NaN NaN
'''
df1 = pd.read_csv(io.StringIO(data1), sep=r'\s+')
df1
# ...
data2 = '''
a b c d e
2020-01-02 10.0 5.0 3.0 NaN 6.0
2020-01-03 NaN 6.0 NaN 7.0 NaN
2020-01-06 NaN NaN NaN NaN NaN
2020-01-07 NaN NaN NaN NaN 14.0
2020-01-08 2.0 NaN NaN NaN NaN
'''
df2 = pd.read_csv(io.StringIO(data2), sep='\s+')
df2
# ...
df1 意味对应的数字需要向后占用几天(单次为1,小数放在最后)。
如在 df1 中(2020-01-02,B)是3.2天,那么对应的(2020-01-02,b)中的5 需要在 T(2020-01-02)、T+1(2020-01-03) 、T+2 (2020-01-06)都是5,0.2留给T+3(2020-01-07)。
结合 df1、 df2 两张表,按照图中的计算逻辑,最后得到A、B、C、D、E每项的当日余额,并求和得到当天的汇总。最终的结果是:
'''
A B C D E total
2020-01-02 10.0 10.0 6.0 6.0 32.0
2020-01-03 22.0 6.0 14.0 6.0 48.0
2020-01-06 22.0 6.0 14.0 42.0
2020-01-07 1.6 6.0 14.0 14.0 35.6
2020-01-08 2.0 0.6 2.8 5.4
'''
计算逻辑也可以看看图示:
由于两个 DataFrame 的形状相同,但最终数据是以 df1 的表头为准的,所以我们将 df2 的表头设置为 df1 的,然后将两个数据拼接,再按行标签分组,将同位置的两个元素组成一个元组,这个过程与 pandas 标记用户购买复购和流失行为 案例是同样的思路。
接下来,我们写一个函数来按列处理这些数据,这个函数传入的是一个 Series,就是每个列,返回的也是一个相同长度、充当最终结果的 Series。接下来我们说说这个函数如何产生这个结果。
首先定义一个初始化的 Series,这个 Series 的所有值为 0.0,标签与传入的每个 Series 相同,这样方便我们返回时与原数据对齐,后续的操作就是给这个 Series 赋值,按逻辑在指定的位置上修改为需要的值。
迭代传入的 Series,分别使用每个数据标签、元组中的两个值,然后根据元组的数据类型(有无小数、是否缺失值)来构造填充的数据序列,最后将这个序列赋值给对应的初始化 Series 的位置中。
根据思路,我们的代码如下:
import numpy as np
def func(ser: pd.Series) -> pd.Series:
# 设置一个初始的 Series 用于数据修改填充
res = pd.Series(.0, index=ser.index)
for idx, (a, b) in ser.items():
# 展开的计算后的数字序列并写入 res
# 为一个数字并有小数
if a > 0 and a%1 > 0:
unit = [1]*(i:=int(a)) + [round(a-i, 1)]
nums = [i*b for i in unit]
res.loc[idx:][:len(nums)] += nums
# 没有小数的
if a > 0:
unit = [1]*(i:=int(a))
nums = [i*b for i in unit]
res.loc[idx:][:len(nums)] += nums
return res
(
pd.concat([df1,
df2.set_axis(df1.columns, axis=1)])
.groupby(level=0).agg(tuple)
.apply(func)
.assign(total=lambda x: x.sum(1))
.replace({0: ''})
)
'''
A B C D E total
2020-01-02 10.0 10.0 6.0 6.0 32.0
2020-01-03 22.0 6.0 14.0 6.0 48.0
2020-01-06 22.0 6.0 14.0 42.0
2020-01-07 1.6 6.0 14.0 14.0 35.6
2020-01-08 2.0 0.6 2.8 5.4
'''
这样就完成了这个需求。
(完)
更新时间:Aug. 18, 2024, 4:18 p.m. 标签:pandas python 填充