计算连续几天的温度数据

问题描述

所以我有一些海面温度异常数据。这些数据已被过滤掉,因此这些值低于某个阈值。但是,我正在尝试识别寒潮——也就是说,隔离持续时间超过连续 5 天的事件。我的数据示例如下(我一直在 xarray 数据集/数据数组和 Pandas 数据帧之间工作)。请注意,“天”是我正在查看的月份的天数(最终将扩展到全年)。我一直在搜索 SO/互联网,寻找基于“天”列提取这些 5 天或更长时间事件的方法,但我没有得到任何工作。我对编码还是比较陌生,所以我的第一个想法是遍历“day”列的行,但我不确定。任何见解表示赞赏。

以下是我的一些数据作为 Pandas df 的样子:

        lat     lon     time        day  ssta
5940    24.125  262.375 1984-06-03  3   -1.233751
21072   24.125  262.375 1984-06-04  4   -1.394495
19752   24.125  262.375 1984-06-05  5   -1.379742
10223   24.125  262.375 1984-06-27  27  -1.276407
47355   24.125  262.375 1984-06-28  28  -1.840763
... ... ... ... ... ...
16738   30.875  278.875 2015-06-30  30  -1.345640
3739    30.875  278.875 2020-06-16  16  -1.212824
25335   30.875  278.875 2020-06-17  17  -1.446407
41891   30.875  278.875 2021-06-01  1   -1.714249
27740   30.875  278.875 2021-06-03  3   -1.477497

64228 rows × 5 columns

作为过滤后的 xarray:

xarray.Dataset
Dimensions:  lat: 28,lon: 68,time: 1174
Coordinates:  
time (time)  datetime64[ns]   1982-06-01 ... 2021-06-04
lon (lon) float32 262.1 262.4 262.6 ... 278.6 278.9
lat (lat) float32 24.12 24.38 24.62 ... 30.62 30.88
day (time) int64 1 2 3 4 5 6 7 ... 28 29 30 1 2 3 4
Data variables:
ssta (time,lat,lon) float32 nan nan nan nan ... nan nan nan nan
Attributes: (0)

TLDR;我想识别(并保留)连续 5 天以上的事件,即是否有第 3 天到第 8 天,或第 21 天到第 30 天等。

解决方法

我认为,与其过滤原始数据,不如尝试使用 pandas 的方式,在这种情况下,这意味着根据您的条件获得具有真假值的系列。

您的数据似乎不包括温度,所以这是我的示例:

import pandas as pd
import numpy as np

df = pd.DataFrame(data={'temp':np.random.randint(10,high=40,size=64228,dtype='int64')})

将生成一个 DataFrame,其中有一列包含 10 到 40 度之间的随机温度。请注意,我只能使用自动生成的索引,但您可能需要使用 .set_index 将其切换到时间或日期等列。假设我们对连续超过 30 度的日子感兴趣。

is_over_30 = df['temp'] > 30

会给我们一个包含该信息的 True/False 数组。请注意,这种格式非常有用,因为我们可以使用它进行索引。例如。 df[is_over_30] 将为我们提供温度超过 30 度的日子的 dataframe 行。现在我们想将 is_over_30 中的 True/False 值向前移动一个位置,并生成一个新系列,如果两者都为真,则为真

is_over_30 & np.roll(is_over_30,-1) 

基本上我们到这里就完成了,可以再写 3 个这样的卷。但是有一种方法可以写得更简洁。

from functools import reduce

is_consecutively_over_30 = reduce(lambda a,b: a&b,[np.roll(is_over_30,-i) for i in range(5)])

请记住,即使过去 4 天不能连续超过 30 度,这也可能在这里发生,因为滚动会将第一个值移动到与此相关的位置。但是您可以将最后 4 个值设置为 False 来解决此问题。

is_consecutively_over_30[-4:] = False
,

您可以使用这种方法提取法术的日期范围:

min_spell_days = 6
days = {'day': [1,2,5,6,7,8,9,10,17,19,21,22,23,24,25,26,27,31]}
df = pd.DataFrame(days)

查找连续条目之间的天数:

diff = df['day'].diff()

标记咒语的最后一天:

df['last'] = (diff == 1) & (diff.shift(-1) > 1)

累计每个法术的天数:

df['diff0'] = np.where(diff > 1,diff)
df['cs'] = df['diff0'].eq(0).cumsum()
df['spell_days'] = df.groupby('cs')['diff0'].transform('cumsum')

如果适用,将最后一个条目标记为法术的最后一天:

if diff.iat[-1] == 1:
    df['last'].iat[-1] = True

选择所有符合条件的法术的最后一天:

df_spells = (df[df['last'] & (df['spell_days'] >= (min_spell_days-1))]).copy()

确定每个法术的开始、结束和持续时间:

df_spells['end_day'] = df_spells['day']
df_spells['start_day'] = (df_spells['day'] - df['spell_days'])
df_spells['spell_days'] = df['spell_days'] + 1

结果 df

df_spells[['start_day','end_day','spell_days']].astype('int')

    start_day  end_day  spell_days
7           5       10           6
16         21       27           7

此外,使用日期算术“day”,您可以表示相对于某个基准日期的连续日数 - 例如 1/1/1900。这样就可以处理跨越月份和年份界限的法术。然后使用日期算术和该序列号转换回日期将是微不足道的。