【问题标题】:Subtract value in row based on condition in pandas根据熊猫中的条件减去行中的值
【发布时间】:2020-07-31 01:30:56
【问题描述】:

我需要根据故障计数的进展减去日期。 下面是具有两个输入列DateFault_Count 的表。我需要的输出列是Option1Option2。最后两列显示日期差异计算。基本上,当 Fault_Count 更改时,我需要计算从 Fault_Count 更改到故障计数初始开始的天数。例如,1/4/2020 上的 Fault_Count 更改为 2,我需要获取从 Fault_Count0 开始并更改为 2 的天数(即1/4/2020 - 1/1/2020 = 3)。

Date    Fault_Count Option1 Option2    Option1calc          Option2calc
1/1/2020       0       0        0       
1/2/2020       0       0        0       
1/3/2020       0       0        0       
1/4/2020       2       3        3   1/4/2020-1/1/2020    1/4/2020-1/1/2020
1/5/2020       2       0        0       
1/6/2020       2       0        0       
1/7/2020       4       3        3   1/7/2020-1/4/2020    1/7/2020-1/4/2020
1/8/2020       4       0        0       
1/9/2020       5       2        2   1/9/2020-1/7/2020    1/9/2020-1/7/2020
1/10/2020      5       0        0       
1/11/2020      0       2       -2   1/11/2020-1/9/2020   (1/11/2020-1/9/2020)*-1 as the fault resets
1/12/2020      1       1        1   1/12/2020-1/11/2020  1/12/2020-1/11/2020

下面是代码。

import pandas as pd

d = {'Date': ['1/1/2020', '1/2/2020', '1/3/2020', '1/4/2020', '1/5/2020', '1/6/2020', '1/7/2020', '1/8/2020', '1/9/2020', '1/10/2020', '1/11/2020', '1/12/2020'], 'Fault_Count' : [0, 0, 0, 2, 2, 2, 4, 4, 5, 5, 0, 1]}
df = pd.DataFrame(d)
df['Date'] = pd.to_datetime(df['Date'])
df['Fault_count_diff'] = df.Fault_Count.diff().fillna(0)
df['Cumlative_Sum'] = df.Fault_count_diff.cumsum()

我认为我可以使用累积和和分组来获取组并获得组的第一个值的差异。这是我所能得到的,我还注意到使用累积总和并没有给我有序的组,因为一些Fault_Count 被重置。

    Date        Fault_Count   Fault_count_diff    Cumlative_Sum
0   2020-01-01       0               0.0                0.0
1   2020-01-02       0               0.0                0.0
2   2020-01-03       0               0.0                0.0
3   2020-01-04       2               2.0                2.0
4   2020-01-05       2               0.0                2.0
5   2020-01-06       2               0.0                2.0
6   2020-01-07       4               2.0                4.0
7   2020-01-08       4               0.0                4.0
8   2020-01-09       5               1.0                5.0
9   2020-01-10       5               0.0                5.0
10  2020-01-11       0              -5.0                0.0
11  2020-01-12       1               1.0                1.0

期望的输出:

         Date  Fault_Count  Option1  Option2
0  2020-01-01            0      0.0      0.0
1  2020-01-02            0      0.0      0.0
2  2020-01-03            0      0.0      0.0
3  2020-01-04            2      3.0      3.0
4  2020-01-05            2      0.0      0.0
5  2020-01-06            2      0.0      0.0
6  2020-01-07            4      3.0      3.0
7  2020-01-08            4      0.0      0.0
8  2020-01-09            5      2.0      2.0
9  2020-01-10            5      0.0      0.0
10 2020-01-11            0      2.0     -2.0
11 2020-01-12            1      1.0      1.0

感谢您的帮助。

【问题讨论】:

    标签: python pandas dataframe pandas-groupby cumsum


    【解决方案1】:

    用途:

    m1 = df['Fault_Count'].ne(df['Fault_Count'].shift(fill_value=0))
    m2 = df['Fault_Count'].eq(0) & df['Fault_Count'].shift(fill_value=0).ne(0)
    
    s = df['Date'].groupby(m1.cumsum()).transform('first')
    
    df['Option1'] = df['Date'].sub(s.shift()).dt.days.where(m1, 0)
    df['Option2'] = df['Option1'].where(~m2, df['Option1'].mul(-1))
    

    详情:

    使用Series.ne + Series.shift 创建布尔掩码m1 表示Fault_count 变化时的边界条件,同样使用Series.eq + Series.shiftSeries.ne 创建布尔掩码m2代表Fault_count重置的条件:

              m1           m2
    0         False        False
    1         False        False
    2         False        False
    3          True        False
    4         False        False
    5         False        False
    6          True        False
    7         False        False
    8          True        False
    9         False        False
    10         True         True # --> Fault count reset
    11         True        False
    

    对使用m1.cumsum 获得的连续故障计数使用Series.groupby,并使用groupby.first 转换Date 列:

    print(s)
    0    2020-01-01
    1    2020-01-01
    2    2020-01-01
    3    2020-01-04
    4    2020-01-04
    5    2020-01-04
    6    2020-01-07
    7    2020-01-07
    8    2020-01-09
    9    2020-01-09
    10   2020-01-11
    11   2020-01-12
    Name: Date, dtype: datetime64[ns]
    

    使用Series.sub 减去Date 以使用Series.shift 移位并使用Series.where 根据掩码m2 填充0,并将其分配给Option1。类似地,我们根据掩码m2Option1获得Option2

    print(df)
             Date  Fault_Count  Option1  Option2
    0  2020-01-01            0      0.0      0.0
    1  2020-01-02            0      0.0      0.0
    2  2020-01-03            0      0.0      0.0
    3  2020-01-04            2      3.0      3.0
    4  2020-01-05            2      0.0      0.0
    5  2020-01-06            2      0.0      0.0
    6  2020-01-07            4      3.0      3.0
    7  2020-01-08            4      0.0      0.0
    8  2020-01-09            5      2.0      2.0
    9  2020-01-10            5      0.0      0.0
    10 2020-01-11            0      2.0     -2.0
    11 2020-01-12            1      1.0      1.0
    

    【讨论】:

      【解决方案2】:

      不要使用df['Fault_count_diff'] = ... 和下一行,而是:

      df['cycle'] = (df.Fault_Count.diff() < 0).cumsum()
      

      然后获取每次计数更改之间的日期。

      选项 1。如果 df 中存在所有日历日期:

      ndays = df.groupby(['cycle', 'Fault_Count']).Date.size()
      

      选项 2。如果日期有可能没有出现在 df 中,并且您仍想获取事件之间的日历天数:

      ndays = df.groupby(['cycle', 'Fault_Count']).Date.min().diff().dropna()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-10-13
        • 2015-07-27
        • 1970-01-01
        • 1970-01-01
        • 2018-11-15
        • 1970-01-01
        • 2020-10-08
        相关资源
        最近更新 更多