在Pandas DataFrame中查找连续日期组

smm*_*smm 3 python datetime pandas

我正在尝试从Pandas DataFrame中获取具有连续日期的数据块。我的df样子如下。

      DateAnalyzed           Val
1       2018-03-18      0.470253
2       2018-03-19      0.470253
3       2018-03-20      0.470253
4       2018-09-25      0.467729
5       2018-09-26      0.467729
6       2018-09-27      0.467729
Run Code Online (Sandbox Code Playgroud)

在此df,我想获取前3行,进行一些处理,然后获取后3行,并对此进行处理。

我通过应用以下代码计算了1滞后的差异。

df['Delta']=(df['DateAnalyzed'] - df['DateAnalyzed'].shift(1))
Run Code Online (Sandbox Code Playgroud)

但是在那之后,我无法弄清楚如何在不进行迭代的情况下获取连续行的组。

Cai*_*lva 9

在此处此处之后还有类似的问题,具有更具体的输出要求。由于这个问题比较笼统,我也想在这里做出贡献。

我们可以使用一行代码轻松地将唯一标识符分配给连续的组:

df['grp_date'] = df.DateAnalyzed.diff().dt.days.ne(1).cumsum()
Run Code Online (Sandbox Code Playgroud)

在这里,每当我们看到差异大于一天的日期时,我们都会向该日期添加一个值,否则它保留以前的值,以便我们最终为每个组提供唯一的标识符。

查看输出:

  DateAnalyzed       Val  grp_date
1   2018-03-18  0.470253         1
2   2018-03-19  0.470253         1
3   2018-03-20  0.470253         1
4   2018-09-25  0.467729         2
5   2018-09-26  0.467729         2
6   2018-09-27  0.467729         2
Run Code Online (Sandbox Code Playgroud)

现在,很容易“grp_date”并用或groupby做任何你想做的事情。applyagg


例子:

df['grp_date'] = df.DateAnalyzed.diff().dt.days.ne(1).cumsum()
Run Code Online (Sandbox Code Playgroud)


Bra*_*mon 6

似乎您需要两个布尔掩码:一个用于确定组之间的间隔,另一个用于确定哪个日期首先在组中。

还有一个棘手的部分可以通过示例来充实。请注意,df下面包含一个添加的行,该行之前或之后没有任何连续的日期。

>>> df
  DateAnalyzed       Val
1   2018-03-18  0.470253
2   2018-03-19  0.470253
3   2018-03-20  0.470253
4   2017-01-20  0.485949  # < watch out for this
5   2018-09-25  0.467729
6   2018-09-26  0.467729
7   2018-09-27  0.467729

>>> df.dtypes
DateAnalyzed    datetime64[ns]
Val                    float64
dtype: object
Run Code Online (Sandbox Code Playgroud)

以下答案假定您要2017-01-20完全忽略而不处理它。(如果您确实想处理该日期,请参阅答案的结尾以获取解决方案。)

第一:

>>> dt = df['DateAnalyzed']
>>> day = pd.Timedelta('1d')
>>> in_block = ((dt - dt.shift(-1)).abs() == day) | (dt.diff() == day)
>>> in_block
1     True
2     True
3     True
4    False
5     True
6     True
7     True
Name: DateAnalyzed, dtype: bool
Run Code Online (Sandbox Code Playgroud)

现在,in_block将告诉您哪些日期在“连续”块中,但不会告诉您每个日期属于哪些组。

下一步是派生分组本身:

>>> filt = df.loc[in_block]
>>> breaks = filt['DateAnalyzed'].diff() != day
>>> groups = breaks.cumsum()
>>> groups
1    1
2    1
3    1
5    2
6    2
7    2
Name: DateAnalyzed, dtype: int64
Run Code Online (Sandbox Code Playgroud)

然后,您可以df.groupby(groups)选择进行呼叫。

>>> for _, frame in filt.groupby(groups):
...     print(frame, end='\n\n')
... 
  DateAnalyzed       Val
1   2018-03-18  0.470253
2   2018-03-19  0.470253
3   2018-03-20  0.470253

  DateAnalyzed       Val
5   2018-09-25  0.467729
6   2018-09-26  0.467729
7   2018-09-27  0.467729
Run Code Online (Sandbox Code Playgroud)

要将其合并回去df,分配给它,孤立的日期将是NaN

>>> df['groups'] = groups
>>> df
  DateAnalyzed       Val  groups
1   2018-03-18  0.470253     1.0
2   2018-03-19  0.470253     1.0
3   2018-03-20  0.470253     1.0
4   2017-01-20  0.485949     NaN
5   2018-09-25  0.467729     2.0
6   2018-09-26  0.467729     2.0
7   2018-09-27  0.467729     2.0
Run Code Online (Sandbox Code Playgroud)

如果您确实想包括“孤独”日期,事情会变得更加简单:

dt = df['DateAnalyzed']
day = pd.Timedelta('1d')
breaks = dt.diff() != day
groups = breaks.cumsum()
Run Code Online (Sandbox Code Playgroud)

  • 我来自未来,需要这样做,并发现 `(df.Date.diff(-1) == -day) | (df.Date.diff() == day)` 更干净一些。在我的例子中,“df.Date”是日期列。 (2认同)