Pandas 如何获取数据框中所有非零值范围的第一个和最后一个日期?

Pandas how to get the first and last dates of all non-zero value ranges in a data frame?

我有一个如下所示的数据框:

df = pd.DataFrame({"A":[10,0,30,40,0,60,70,80,90]}, index = pd.date_range(start='1/1/2020', end='1/09/2020'))
df


            A
2020-01-01  10
2020-01-02  0
2020-01-03  30
2020-01-04  40
2020-01-05  0
2020-01-06  60
2020-01-07  70
2020-01-08  80
2020-01-09  90

我想遍历数据框以获取 t0t1,它们分别代表 [ 的每个非零值范围的第一个和最后一个日期(即索引值) =14=].

在上面的 table 中,我想为 t0t1 获取以下值:

t0 = 2020-01-01 , t1 = 2020-01-01

t0 = 2020-01-03 , t1 = 2020-01-04

t0 = 2020-01-06 , t1 = 2020-01-09

在 Pandas 中有没有简单的方法来做到这一点?

一种选择是根据 A=0 的位置创建布尔索引。然后 groupby cumsum of that Index and aggregate firstlast 日期(假设索引按此处排序):

new_df = df.reset_index()
m = new_df['A'].eq(0)
new_df = (
    new_df.groupby(m.cumsum()[~m])
        .agg(t0=('index', 'first'), t1=('index', 'last'))
        .reset_index(drop=True)
)
          t0         t1
0 2020-01-01 2020-01-01
1 2020-01-03 2020-01-04
2 2020-01-06 2020-01-09

获取 minmax 索引值而不是 firstlast 的替代方法:

new_df = df.reset_index()
m = new_df['A'].eq(0)
new_df = (
    new_df.groupby(m.cumsum()[~m])
        .agg(t0=('index', 'min'), t1=('index', 'max'))
        .reset_index(drop=True)
)
          t0         t1
0 2020-01-01 2020-01-01
1 2020-01-03 2020-01-04
2 2020-01-06 2020-01-09

索引:

m:

0    False
1     True
2    False
3    False
4     True
5    False
6    False
7    False
8    False
Name: A, dtype: bool

创建由 0 分隔的组:

m.cumsum()
0    0
1    1
2    1
3    1
4    2
5    2
6    2
7    2
8    2
Name: A, dtype: int32

自我过滤以排除 0 行:

m.cumsum()[~m]
0    0
2    1
3    1
5    2
6    2
7    2
8    2
Name: A, dtype: int32

然后将这些行组合在一起以确定关联的日期。

您可以使用 groupbyagg 同时查找每个范围的第一个日期和最后一个日期。

试试这个:

df = df.reset_index().groupby('A').agg({'first','last'})
df.columns = df.columns.droplevel(0)
print(df)

输出:

        first        last
A                       
0    2020-01-02   2020-01-05
10   2020-01-01   2020-01-01
30   2020-01-03   2020-01-03
40   2020-01-04   2020-01-04
60   2020-01-06   2020-01-06
70   2020-01-07   2020-01-07
80   2020-01-08   2020-01-08
90   2020-01-09   2020-01-09