我有连续的NaN值周期。我想从连续的NaN值的周期中计算NaN值,并且我还想要NaN值的连续周期的开始和结束日期。
df :
TMIN
2017-01-01 00:00:00 2.5
2017-01-02 00:00:00 NaN
2017-01-03 00:00:00 NaN
2017-01-04 00:00:00 2.2
2018-01-01 00:00:00 NaN
2018-01-02 00:00:00 NaN
2018-01-03 00:00:00 NaN
2018-01-04 00:00:00 5.0
2019-01-01 00:00:00 9.0
2019-01-02 00:00:00 8.0
2019-01-03 00:00:00 2.0
2019-01-04 00:00:00 NaN
2020-01-01 00:00:00 NaN
2020-01-02 00:00:00 NaN
2020-01-03 00:00:00 1.0
2020-01-04 00:00:00 NaN
Expected results :
Start_Date End date number of contiguous missing values
2017-01-02 00:00:00 2017-01-03 00:00:00 2
2018-01-01 00:00:00 2018-01-03 00:00:00 3
2019-01-04 00:00:00 2019-01-04 00:00:00 1
2020-01-01 00:00:00 2020-01-02 00:00:00 2
2020-01-04 00:00:00 2020-01-04 00:00:00 1
我该如何解决这个问题?提前谢谢。
CODE:
s = df.index.to_series()
m1, m2 = s.diff().dt.days.eq(1), df['TMIN'].isna()
out = s[m2].groupby([(~m1).cumsum(), (~m2).cumsum()])
.agg(['first', 'last', 'count']).reset_index(drop=True)
细节:
创建布尔掩码m1
和m2
,使m1
表示连续日期之差为1 days
的条件,m2
表示列TMIN
包含NaN
值的条件:
>>> m1
2017-01-01 False
2017-01-02 True
2017-01-03 True
2017-01-04 True
2018-01-01 False
2018-01-02 True
2018-01-03 True
2018-01-04 True
2019-01-01 False
2019-01-02 True
2019-01-03 True
2019-01-04 True
2020-01-01 False
2020-01-02 True
2020-01-03 True
2020-01-04 True
dtype: bool
>>> m2
2017-01-01 False
2017-01-02 True
2017-01-03 True
2017-01-04 False
2018-01-01 True
2018-01-02 True
2018-01-03 True
2018-01-04 False
2019-01-01 False
2019-01-02 False
2019-01-03 False
2019-01-04 True
2020-01-01 True
2020-01-02 True
2020-01-03 False
2020-01-04 True
Name: TMIN, dtype: bool
使用带有上述布尔掩码的cumsum
来标识连续的dates
和NaN
值的块:
>>> (~m1).cumsum()
2017-01-01 1
2017-01-02 1
2017-01-03 1
2017-01-04 1
2018-01-01 2
2018-01-02 2
2018-01-03 2
2018-01-04 2
2019-01-01 3
2019-01-02 3
2019-01-03 3
2019-01-04 3
2020-01-01 4
2020-01-02 4
2020-01-03 4
2020-01-04 4
dtype: int64
>>> (~m2).cumsum()
2017-01-01 1
2017-01-02 1
2017-01-03 1
2017-01-04 2
2018-01-01 2
2018-01-02 2
2018-01-03 2
2018-01-04 3
2019-01-01 4
2019-01-02 5
2019-01-03 6
2019-01-04 6
2020-01-01 6
2020-01-02 6
2020-01-03 7
2020-01-04 7
Name: TMIN, dtype: int64
最后group
和上述块上datframe的index
,并使用first
、last
和count
进行聚合,得到结果:
>>> out
first last count
0 2017-01-02 2017-01-03 2
1 2018-01-01 2018-01-03 3
2 2019-01-04 2019-01-04 1
3 2020-01-01 2020-01-02 2
4 2020-01-04 2020-01-04 1
尝试使用more_iterools(标准python库)
from more_itertools import consecutive_groups
m = df[df['TMIN'].isna()]
l = [list(i) for i in consecutive_groups(m.index.map(pd.Timestamp.toordinal))]
d = {pd.Timestamp.fromordinal(ele):e for e,item in enumerate(l) for ele in item}
out = (pd.Series(m.index,index=m.index.map(d))
.groupby(level=0).agg(['min','max','count']))
#out.columns = ['Start_Date','End date','number of contiguous missing values']
print(out)
min max count
0 2017-01-02 2017-01-03 2
1 2018-01-01 2018-01-03 3
2 2019-01-04 2019-01-04 1
3 2020-01-01 2020-01-02 2
4 2020-01-04 2020-01-04 1