【问题标题】:Pandas - Get last non Nan value plus count number of non Nan in column on a rolling basisPandas - 滚动获取最后一个非 Nan 值加上列中非 Nan 的计数
【发布时间】:2021-09-12 18:56:47
【问题描述】:

我有一个具有以下结构的表:日期和触发器。将有数百行数据。这里只是一个示例:

id Date Trigger
1 15/05/2021 Nan
2 16/05/2021 1
3 17/05/2021 1
4 18/05/2021 Nan
5 19/05/2021 Nan
6 20/05/2021 1
7 21/05/2021 Nan
8 22/05/2021 Nan

.......

我需要解决一些问题。

问题一:

我需要添加一列,我们将其命名为 DST(触发后的天数),我想在其中计算每一行,多少天前(天是连续的,所以我们可以使用行索引作为简单的减法)是最后一个触发器(不是 Nan 值)。

结果应该是这样的:

id Date Trigger DST
1 15/05/2021 Nan Nan
2 16/05/2021 1 Nan
3 17/05/2021 1 1
4 18/05/2021 Nan 1
5 19/05/2021 Nan 2
6 20/05/2021 1 3
7 21/05/2021 Nan 1
8 22/05/2021 Nan 2

所以对于 DST 列中的每一行,我们在 Trigger 列中向上查找并找到最后一个非 Nan 值。

问题 2:

我需要在新列 (DC) 中计算触发事件连续发生的天数。

结果应该是这样的:

id Date Trigger DST DC
1 15/05/2021 Nan Nan 0
2 16/05/2021 1 Nan 1
3 17/05/2021 1 1 2
4 18/05/2021 Nan 1 0
5 19/05/2021 Nan 2 0
6 20/05/2021 1 3 1
7 21/05/2021 Nan 1 0
8 22/05/2021 Nan 2 0

零也可以是 Nan(我不介意)。搜索与问题1的区别在于,这里我们从当前行开始计数(在问题1中,我们从上面的行向上搜索)

问题 3:

添加另一列,我计算过去 3 天中触发器为 1 的天数:

结果应该是这样的:

id Date Trigger DST DC 3D
1 15/05/2021 Nan Nan 0 0
2 16/05/2021 1 Nan 1 1
3 17/05/2021 1 1 2 2
4 18/05/2021 Nan 1 0 2
5 19/05/2021 Nan 2 0 1
6 20/05/2021 1 3 1 1
7 21/05/2021 Nan 1 0 1
8 22/05/2021 Nan 2 0 1

所以我们向上查看 3 行(包括当前行)并计算触发列上有多少个 1(对于前 3 个值,我们只考虑它们上方的可用行数)。

希望这是有道理的。

有没有什么方法可以简单地计算出来,而不需要逐行迭代?

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    为了计算 DST 和 DC,我们希望在 GroupBy 组上使用 cumsumcumcount,因此计数会重置。为此,我们首先定义每天使用触发器重新启动的组:

    >>> dstgroups = df['Trigger'].notna().cumsum()
    >>> dstgroups
    0    0
    1    1
    2    2
    3    2
    4    2
    5    3
    6    3
    7    3
    Name: Trigger, dtype: int64
    >>> df['Trigger'].groupby(dstgroups).cumcount()
    0    0
    1    0
    2    0
    3    1
    4    2
    5    0
    6    1
    7    2
    dtype: int64
    

    现在这大致就是您想要的,除了一些奇怪的语义,特别是:

    • NaN 直到第一次触发后的第二天
    • 用触发器计算一天会增加延迟

    但是我们可以很容易地调整它,分别通过masking 和cummax(),以及通过移动和添加1

    >>> df['Trigger'].groupby(dstgroups).cumcount()\
    ...     .where(df['Trigger'].fillna(0).cummax().astype(bool))\
    ...     .shift().add(1)
    0    NaN
    1    NaN
    2    1.0
    3    1.0
    4    2.0
    5    3.0
    6    1.0
    7    2.0
    dtype: float64
    

    DC 相同,但每天都会重置,无需触发且没有意外调整,我们也使用cumsum 而不是cumcount

    >>> dcgroups = df['Trigger'].isna().cumsum()
    >>> df['Trigger'].fillna(0).groupby(dcgroups).cumsum()
    0    0.0
    1    1.0
    2    2.0
    3    0.0
    4    0.0
    5    1.0
    6    0.0
    7    0.0
    Name: Trigger, dtype: float64
    

    计算 3D 要简单得多,我们可以使用滚动窗口:

    >>> df['Trigger'].eq(1).rolling(3, center=False, min_periods=1).sum()
    0    0.0
    1    1.0
    2    2.0
    3    2.0
    4    1.0
    5    1.0
    6    1.0
    7    1.0
    Name: Trigger, dtype: float64
    

    【讨论】:

    • 谢谢!它做得很好。干得好!
    猜你喜欢
    • 2017-08-25
    • 2013-06-18
    • 2014-10-11
    • 2017-08-14
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多