【问题标题】:Finding the beginning and end dates of when a sequence of values occurs in Pandas查找 Pandas 中出现一系列值的开始和结束日期
【发布时间】:2020-08-17 17:29:56
【问题描述】:

我有一个带有索引列和另一列的数据框,该列用 1 或 0 标记当天是否发生了事件。

如果一个事件发生,它通常会在很长一段时间内连续发生。他们通常会标记是否发生了经济衰退,因此可能会连续 60-180 天被标记为 1,然后再次变为 0。

我需要做的是找到标记每个 1 序列开始和结束的日期。

这里有一些快速示例代码:

dates = pd.date_range(start='2010-01-01', end='2015-01-01')
nums = np.random.normal(50, 5, 1827)
df = pd.DataFrame(nums, index=dates, columns=['Nums'])
df['Recession'] = np.where((df.index.month == 3) | (df.index.month == 12), 1, 0)

对于示例数据框,值 1 出现在 3 月和 12 月,因此理想情况下,我应该有一个名为 [2010-03-01, 2010-03-31, 2010-12-01, 2010-12-30, ......, 2015-12-01, 2015-12-30] 的列表。

我知道我可以通过使用 for 循环找到这些值,但这似乎效率低下。我也尝试使用groupby,但找不到任何能提供我想要的结果的东西。

不确定是否有 pandas 或 numpy 方法可以在索引中搜索适当的条件。

【问题讨论】:

  • dates = df.loc[df['Recession'] != df['Recession'].shift(), 'date_column']
  • 数据科学导论 - 密歇根大学 :-D 我也在第 4 周。

标签: python pandas


【解决方案1】:

让我们试试这个,使用DataFrameGroupBy.idxmin + DataFrameGroupBy.idxmax

# group-by on month, year & aggregate on date
g = (
    df.assign(day=df.index.day)
        .groupby([df.index.month, df.index.year]).day
)

# create mask of max date & min date for each (month, year) combination
mask = df.index.isin(g.idxmin()) | df.index.isin(g.idxmax())

# apply previous mask with month filter..
df.loc[mask & (df.index.month.isin([3,12])), 'Recession'] = 1

print(df[df['Recession'] == 1])

                 Nums  Recession
2010-03-01  45.698168        1.0
2010-03-31  47.969167        1.0
2010-12-01  49.388595        1.0
2010-12-31  46.689064        1.0
2011-03-01  50.120603        1.0
2011-03-31  58.379980        1.0
2011-12-01  53.745407        1.0
...
...

【讨论】:

    【解决方案2】:

    我会使用 diff 来查找句点,diff 可以找到它何时从一种状态切换到另一种状态,因此将找到的索引分成两部分,即开始和结束。

    取决于数据是否从衰退开始:

    locs = (df.Recession.diff().fillna(0)!=0).values.nonzero()[0]
    if df.Recession.iloc[0]==0:
        start = df.index[locs[::2]]
        end = df.index[locs[1::2]-1]
    else:
        start = df.index[locs[::2]-1]
        end = df.index[locs[1::2]]
    

    如果数据已经从经济衰退开始,您是否想将第一个日期作为开始日期由您决定,以上不包括它。

    【讨论】:

      【解决方案3】:

      据我了解,您需要找到序列中的第一个值?如果是这样,我们可以使用groupbycumsum 对每个连续组求和,并使用cumcount 对每个组进行计数。

      df["keyGroup"] = (
          df.groupby(df["Recession"].ne(df["Recession"].shift()).cumsum()).cumcount() + 1
      )
      
      df[df['keyGroup'].eq(1)]
      
                       Nums  Recession  keyGroup
      2010-01-01  51.944742          0         1
      2010-03-01  54.809271          1         1
      2010-04-01  52.632831          0         1
      2010-12-01  55.863695          1         1
      2011-01-01  52.944778          0         1
      2011-03-01  58.164943          1         1
      2011-04-01  49.590640          0         1
      2011-12-01  47.884919          1         1
      2012-01-01  44.128065          0         1
      2012-03-01  54.846231          1         1
      2012-04-01  51.312064          0         1
      2012-12-01  46.091171          1         1
      2013-01-01  49.287102          0         1
      2013-03-01  54.727874          1         1
      2013-04-01  53.163730          0         1
      2013-12-01  42.373602          1         1
      2014-01-01  43.822791          0         1
      2014-03-01  51.203125          1         1
      2014-04-01  54.322415          0         1
      2014-12-01  44.052536          1         1
      2015-01-01  53.438015          0         1
      

      您可以调用.index 来获取列表中的值。

      df[df['keyGroup'].eq(1)].index
      
      
      DatetimeIndex(['2010-01-01', '2010-03-01', '2010-04-01', '2010-12-01',
                     '2011-01-01', '2011-03-01', '2011-04-01', '2011-12-01',
                     '2012-01-01', '2012-03-01', '2012-04-01', '2012-12-01',
                     '2013-01-01', '2013-03-01', '2013-04-01', '2013-12-01',
                     '2014-01-01', '2014-03-01', '2014-04-01', '2014-12-01',
                     '2015-01-01'],
                    dtype='datetime64[ns]', name='date', freq=None)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-30
        • 2020-02-17
        • 1970-01-01
        • 1970-01-01
        • 2020-11-03
        • 2013-01-08
        • 1970-01-01
        相关资源
        最近更新 更多