使用 pandas 对数据进行移动计算

使用 pandas 对数据进行移动计算插图亿华云

假设有 10 天的销售额数据,我们想每三天求一次总和,比如第五天的总和就是第三天 第四天 第五天的销售额之和,这个时候该怎么做呢?

Series 对象有一个 rolling 方法,专门用来做移动计算,我们来看一下。

import pandas as pd

amount = pd.Series(

[100, 90, 110, 150, 110, 130, 80, 90, 100, 150])

print(amount.rolling(3).sum())

"""

0 NaN # NaN NaN 100

1 NaN # NaN 100 90

2 300.0 # 100 90 110

3 350.0 # 90 110 150

4 370.0 # 110 150 110

5 390.0 # 150 110 130

6 320.0 # 110 130 80

7 300.0 # 130 80 90

8 270.0 # 80 90 100

9 340.0 # 90 100 150

dtype: float64

"""

结果和我们想要的是一样的,amount.rolling(3) 相当于创建了一个长度为 3 的窗口,窗口从上到下依次滑动,我们画一张图:

使用 pandas 对数据进行移动计算插图1亿华云

amount.rolling(3) 就做了类似于图中的事情,然后在其基础上调用 sum,会将每个窗口里面的元素加起来,就得到上面代码输出的结果。另外窗口的大小可以任意,这里我们以 3 为例。

除了sum,还可以求平均值、求方差等等,可以进行很多的操作,有兴趣可以自己尝试一下。当然我们也可以自定义函数:

import pandas as pd

import numpy as np

amount = pd.Series(

[100, 90, 110, 150, 110, 130, 80, 90, 100, 150])

print(

# 调用 agg 方法,传递一个函数

# 参数 x 就是每个窗口里面的元素组成的 Series 对象

amount.rolling(3).agg(lambda x: np.sum(x) * 2)

)

"""

0 NaN # (NaN NaN 100) * 2

1 NaN # (NaN 100 90) * 2

2 600.0 # (100 90 110) * 2

3 700.0 # (90 110 150) * 2

4 740.0 # (110 150 110) * 2

5 780.0 # (150 110 130) * 2

6 640.0 # (110 130 80) * 2

7 600.0 # (130 80 90) * 2

8 540.0 # (80 90 100) * 2

9 680.0 # (90 100 150) * 2

dtype: float64

"""

agg 里面的函数的逻辑可以任意,但返回的必须是一个数值。

此外我们注意到,开始的两个元素为 NaN,这是因为 rolling(3) 表示从当前位置往上筛选,总共筛选 3 个元素,图上已经画的很清晰了。但如果我们希望元素不够的时候有多少算多少,该怎么办呢?比如:第一个窗口里面的元素之和就是第一个元素,第二个窗口里面的元素之和是第一个元素加上第二个元素。

import pandas as pd

amount = pd.Series(

[100, 90, 110, 150, 110, 130, 80, 90, 100, 150])

print(

# min_periods 表示窗口的最小观测值

amount.rolling(3, min_periods=1).sum()

)

"""

0 100.0

1 190.0

2 300.0

3 350.0

4 370.0

5 390.0

6 320.0

7 300.0

8 270.0

9 340.0

dtype: float64

"""

添加一个 min_periods 参数即可实现,这个参数表示窗口的最小观测值,即:窗口里面元素的最小数量,默认它和窗口的长度相等。我们窗口长度为 3,但指定了 min_periods 为 1,表示元素不够也没关系,只要有一个就行。

因此元素不够的话,有几个就算几个。如果我们指定 min_periods 为 2 的话,那么会是什么结果呢?显然第一个是 NaN,第二个还是 190.0,因为窗口里面的元素个数至少为 2。

import pandas as pd

amount = pd.Series(

[100, 90, 110, 150, 110, 130, 80, 90, 100, 150])

print(

# 窗口的最小观测值为 2

amount.rolling(3, min_periods=2).sum()

)

"""

0 NaN

1 190.0

2 300.0

3 350.0

4 370.0

5 390.0

6 320.0

7 300.0

8 270.0

9 340.0

dtype: float64

"""

THE END
Copyright © 2024 亿华云