Отслеживание 3-дневных полос, когда условие выполняется в столбце кадра данных, без двойного учета полос - PullRequest
0 голосов
/ 08 мая 2019

У меня есть план данных наблюдений за климатом для 8 разных городов США.

Я пытаюсь найти количество тепловых волн (3 дня подряд с максимумом на уровне или выше 90 градусов) за каждый годдля каждого местоположения в наборе данных.

Я определяю волну жары как 3 дня подряд, но 3 дня подряд.Например:

If Aug. 8 hit 87
   Aug. 9 hit 90
   Aug. 10 hit 92
   Aug. 11 hit 94
   Aug. 12 hit 93
   Aug. 13 hit 101
   Aug. 14 hit 94
   Aug. 15 hit 77

В столбце «HeatWave» 9 и 12 августа будут значения «1», отражающие 2 отдельных трехдневных периода, в которых максимальное значение достигло 90 или выше.

Моя текущая стратегия не работает с такими полосами дней.

Я пытался использовать np.where.Сначала я проверяю, достигла ли температура в этот день 90 или выше.Затем я проверяю заранее, чтобы увидеть, достиг ли максимума на уровне или выше 90 в течение следующих двух дней.Наконец, я проверяю два дня до того, чтобы увидеть, не содержит ли столбец HeatWave «1».Если все эти условия выполнены, в столбце «HeatWave» для строки помещается 1.

summer['Next90'] = summer.Max.shift(-1)
summer['Following90'] = summer.Max.shift(-2)
summer['HeatWave'] = 0    
summer['HeatWave'] = np.where((summer['Next90']>=90) & 
(summer['Max']>=90) & (summer['Following90']>=90) & (summer.shift(1) 
['HeatWave']!=1) & (summer.shift(2)['HeatWave']!=1), 1, np.nan) 

Проблема с этой последовательностью в том, что я не думаю, что np.where может проверить столбец «HeatWave» после того, как он просто поместил 1 (или np.nan) в предыдущей строке.Итак, я получаю много «1» в столбце «HeatWave», но в итоге последовательности засчитываются дважды.Я также попробовал это в цикле for, используя iterrows, но приземлился в той же борьбе.Кто-нибудь может предложить лучший способ пойти по этому поводу?

1 Ответ

0 голосов
/ 09 мая 2019

Вот один из способов, которым вы можете попробовать (примерные данные показаны в конце поста)

  1. получить данные и затем установить количество дней в серии = 3

    df = pd.read_csv('/path/to/file', sep='\s\s+', engine='python', parse_dates=['date'])
    # N-day streak
    N = 3
    
  2. удалить потенциальные дубликаты, исправить пропущенные даты и установить для NULL 'temp' значение 0

    # if there are duplicates in the same date, drop them and keep the one with highest temp
    df = df.sort_values(['date', 'temp'], ascending=[1,0]).drop_duplicates(subset=['date'])
    
    # fix missing dates issue and fill missing 'temp' with 0
    df = df.set_index('date').asfreq('D').reset_index().fillna(0)
    print(df)
    #         date  temp
    #0  2018-08-01    83
    #1  2018-08-02    99
    #2  2018-08-03    99
    #3  2018-08-04    87
    #4  2018-08-05    90
    #5  2018-08-06    92
    #6  2018-08-07     0
    #7  2018-08-08    92
    #8  2018-08-09    90
    #9  2018-08-10    92
    #10 2018-08-11    94
    #11 2018-08-12    93
    #12 2018-08-13   101
    #13 2018-08-14    94
    #14 2018-08-15    77
    
  3. установить условия, которые соответствуют критериямволна тепла

    # contition-1  df.temp >= 90
    c1 = df.temp.ge(90)
    
  4. сгруппировать последовательные строки на основе условия-1 и пометить их g

    # group label (each group forms a streak)
    g = (c1 != c1.shift()).cumsum()
    
  5. , определив новый df1.Для каждой группы g найдите следующее:

    • cnt: общее количество строк
    • n: cumcount () в качестве порядкового номера
    • g:добавлено здесь только для справки, не используется для дальнейших расчетов

      df1 = df.assign(
          cnt=df.groupby(g).date.transform('count')
        , n=df.groupby(g).agg('cumcount')
        , g=g
      )
      print(df1)
      #         date  temp  cnt  g  n
      #0  2018-08-01    83    1  1  0
      #1  2018-08-02    99    2  2  0
      #2  2018-08-03    99    2  2  1
      #3  2018-08-04    87    1  3  0
      #4  2018-08-05    90    2  4  0
      #5  2018-08-06    92    2  4  1
      #6  2018-08-07     0    1  5  0
      #7  2018-08-08    92    7  6  0
      #8  2018-08-09    90    7  6  1
      #9  2018-08-10    92    7  6  2
      #10 2018-08-11    94    7  6  3
      #11 2018-08-12    93    7  6  4
      #12 2018-08-13   101    7  6  5
      #13 2018-08-14    94    7  6  6
      #14 2018-08-15    77    1  7  0
      
  6. определяют еще два условия:

    # condition-2: cnt >= N , a streak must have at least N rows
    c2 = df1.cnt.ge(N)
    
    # condition-3: (n%N)==0 and (n+N) <= cnt
    # the last n%N==0 might not have enough dates for a N-day streak
    c3 = df1.n.mod(N).eq(0) & df1.n.le(df1.cnt-N)
    
  7. последний флаг в df должен иметь:

    df['flag'] = np.where(c1 & c2 & c3, 1, 0)
    print(df)
    #         date  temp  flag
    #0  2018-08-01    83     0
    #1  2018-08-02    99     0
    #2  2018-08-03    99     0
    #3  2018-08-04    87     0
    #4  2018-08-05    90     0
    #5  2018-08-06    92     0
    #6  2018-08-07     0     0
    #7  2018-08-08    92     1
    #8  2018-08-09    90     0
    #9  2018-08-10    92     0
    #10 2018-08-11    94     1
    #11 2018-08-12    93     0
    #12 2018-08-13   101     0
    #13 2018-08-14    94     0
    #14 2018-08-15    77     0
    
  8. удалить временный df1:

    del(df1)
    

Примерданные

date           temp
Aug 1, 2018    83
Aug 2, 2018    99
Aug 2, 2018    65
Aug 3, 2018    99
Aug 2, 2018    70
Aug 4, 2018    87
Aug 5, 2018    90
Aug 6, 2018    92
Aug 8, 2018    92
Aug 9, 2018    90
Aug 10, 2018    92
Aug 11, 2018    94
Aug 12, 2018    93
Aug 13, 2018    101
Aug 14, 2018    94
Aug 15, 2018    77
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...