【问题标题】:Pandas: flag consecutive valuesPandas:标记连续值
【发布时间】:2019-02-18 23:36:48
【问题描述】:

我有一个[0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0 , 0 , 1]. 形式的熊猫系列

0: indicates economic increase.
1: indicates economic decline.

连续两次下降表明经济衰退 (1)。

连续两次增长 (0) 标志着经济衰退的结束。

在上面的数据集中,我有两次衰退,从索引 3 开始,在索引 5 结束,从索引 8 开始,在索引 11 结束。

我不知道如何使用 pandas 来解决这个问题。我想确定衰退开始和结束的指数。任何帮助将不胜感激。

这是我在解决方案中的 python 尝试。

np_decline =  np.array([0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0 , 0 , 1])
recession_start_flag = 0
recession_end_flag = 0
recession_start = []
recession_end = []

for i in range(len(np_decline) - 1):
    if recession_start_flag == 0 and np_decline[i] == 1 and np_decline[i + 1] == 1:
        recession_start.append(i)
        recession_start_flag = 1
    if recession_start_flag == 1 and np_decline[i] == 0 and np_decline[i + 1] == 0:
        recession_end.append(i - 1)
        recession_start_flag = 0

print(recession_start)
print(recession_end)

是一种更以熊猫为中心的方法吗? 里昂

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    运行 1 的开始满足条件

    x_prev = x.shift(1)
    x_next = x.shift(-1)
    ((x_prev != 1) & (x == 1) & (x_next == 1))
    

    也就是说,一个run开始的值为1,前一个值不是1,下一个值为1。同理,一个run的结束满足条件

    ((x == 1) & (x_next == 0) & (x_next2 == 0))
    

    因为运行结束时的值为 1,接下来的两个值为 0。 我们可以使用np.flatnonzero 找到满足这些条件的索引:

    import numpy as np
    import pandas as pd
    
    x = pd.Series([0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0 , 0 , 1])
    x_prev = x.shift(1)
    x_next = x.shift(-1)
    x_next2 = x.shift(-2)
    df = pd.DataFrame(
        dict(start = np.flatnonzero((x_prev != 1) & (x == 1) & (x_next == 1)),
             end = np.flatnonzero((x == 1) & (x_next == 0) & (x_next2 == 0))))
    print(df[['start', 'end']])
    

    产量

       start  end
    0      3    5
    1      8   11
    

    【讨论】:

      【解决方案2】:

      你可以使用shift:

      df = pd.DataFrame([0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0 , 0 , 1], columns=['signal'])
      df_prev = df.shift(1)['signal']
      df_next = df.shift(-1)['signal']
      df_next2 = df.shift(-2)['signal']
      df.loc[(df_prev != 1) & (df['signal'] == 1) & (df_next == 1), 'start'] = 1
      df.loc[(df['signal'] != 0) & (df_next == 0) & (df_next2 == 0), 'end'] = 1
      df.fillna(0, inplace=True)
      df = df.astype(int)
      
          signal  start  end
      0        0      0    0
      1        1      0    0
      2        0      0    0
      3        1      1    0
      4        1      0    0
      5        1      0    1
      6        0      0    0
      7        0      0    0
      8        1      1    0
      9        1      0    0
      10       0      0    0
      11       1      0    1
      12       0      0    0
      13       0      0    0
      14       1      0    0
      

      【讨论】:

      • 也许只是 .fillna 加上 0 以使其整洁。
      【解决方案3】:

      使用shift 的类似想法,但将结果写入单个布尔列:

      # Boolean indexers for recession start and stops.
      rec_start = (df['signal'] == 1) & (df['signal'].shift(-1) == 1)
      rec_end = (df['signal'] == 0) & (df['signal'].shift(-1) == 0)
      
      # Mark the recession start/stops as True/False.
      df.loc[rec_start, 'recession'] = True
      df.loc[rec_end, 'recession'] = False
      
      # Forward fill the recession column with the last known Boolean.
      # Fill any NaN's as False (i.e. locations before the first start/stop).
      df['recession'] = df['recession'].ffill().fillna(False)
      

      结果输出:

          signal recession
      0        0     False
      1        1     False
      2        0     False
      3        1      True
      4        1      True
      5        1      True
      6        0     False
      7        0     False
      8        1      True
      9        1      True
      10       0      True
      11       1      True
      12       0     False
      13       0     False
      14       1     False
      

      【讨论】:

        【解决方案4】:

        使用rolling(2)

        s = pd.Series([0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0 , 0 , 1])
        

        我减去.5,所以当衰退开始时rolling 和为1,当衰退停止时为-1

        s2 = s.sub(.5).rolling(2).sum()
        

        由于1-1 都评估为True,我可以将滚动信号屏蔽为刚开始和停止以及ffill。使用gt(0) 获取正负值的真值。

        pd.concat([s, s2.mask(~s2.astype(bool)).ffill().gt(0)], axis=1, keys=['signal', 'isRec'])
        

        【讨论】:

        • 嗨@piRSquared。我怎么能修改你在衰退开始和衰退结束两栏所做的事情。如果经济衰退开始,则经济衰退开始为真,否则为假,当然,如果经济衰退结束,则衰退结束为真,否则为假。
        【解决方案5】:

        你可以使用 scipy.signal.find_peaks 来解决这个问题。

            from scipy.signal import find_peaks
        
            np_decline =  np.array([0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0 , 0 , 1])
            peaks = find_peaks(np_decline,width=2)
            recession_start_loc =  peaks[1]['left_bases'][0]
        

        【讨论】:

          猜你喜欢
          • 2019-03-26
          • 1970-01-01
          • 2018-04-29
          • 1970-01-01
          • 2016-02-20
          • 2018-03-03
          • 2020-05-29
          • 2017-08-17
          • 1970-01-01
          相关资源
          最近更新 更多