我有这个df:
CODE DATE TMAX
0 000130 1963-09-01 NaN
1 000130 1963-09-02 29.4
2 000130 1963-09-03 27.8
3 000130 1963-09-04 25.0
4 000130 1963-09-05 27.8
... ... ...
7393858 158328 2020-12-27 12.2
7393859 158328 2020-12-28 8.8
7393860 158328 2020-12-29 NaN
7393861 158328 2020-12-30 10.3
7393862 158328 2020-12-31 9.2
[7393863 rows x 3 columns]
如果一个月内有5个或更多连续的NaN,我想将df['TMAX']
的值转换为NaN。这必须按月份和代码进行。
例如:
CODE DATE TMAX
0 000130 1963-09-01 NaN
1 000130 1963-09-02 NaN
2 000130 1963-09-03 NaN
3 000130 1963-09-04 NaN
4 000130 1963-09-05 NaN
5 000130 1963-09-06 27.8
6 000130 1963-09-07 27.8
7 000130 1963-09-08 27.8
8 000130 1963-09-09 27.8
... ... ...
预期df:
CODE DATE TMAX
0 000130 1963-09-01 NaN
1 000130 1963-09-02 NaN
2 000130 1963-09-03 NaN
3 000130 1963-09-04 NaN
4 000130 1963-09-05 NaN
5 000130 1963-09-06 NaN
6 000130 1963-09-07 NaN
7 000130 1963-09-08 NaN
8 000130 1963-09-09 NaN
... ... ...
所以我得到了这个代码:
def consecutivenan(d, n=5):
if d.isnull().astype(int).groupby(d.notnull().astype(int).cumsum()).sum().ge(n).any():
return np.nan
else:
return d
df["TMAX"] = df.groupby(["CODE", df.DATE.dt.year, df.DATE.dt.month], as_index=False)["TMAX"].transform(consecutivenan, n=5)
它工作得很好,但处理代码需要15分钟。
你有什么建议/代码可以让这个代码更高效、更快吗?
PD:我有一台24GB内存、2.7Ghz、4核的笔记本电脑。在文件中,我有700万行,这就是为什么这可能需要太长时间。
您有正确的逻辑,但代码可以简化。您不需要计算isnull
/notnull
的两倍,也不需要将布尔值转换为整数。
我还在这里测试cumcount
而不是sum
。
你能尝试一下这种潜在的改进吗?
df['DATE'] = pd.to_datetime(df['DATE'])
def consecutivenan(d, n=5):
s = d.notnull()
if s.groupby(s.cumsum()).cumcount().eq(n-1).any():
return np.nan
else:
return d
df["TMAX"] = df.groupby(["CODE", df['DATE'].dt.to_period('M')], as_index=False)["TMAX"].transform(consecutivenan, n=5)
输出:
CODE DATE TMAX
0 130 1963-09-01 NaN
1 130 1963-09-02 NaN
2 130 1963-09-03 NaN
3 130 1963-09-04 NaN
4 130 1963-09-05 NaN
5 130 1963-09-06 NaN
6 130 1963-09-07 NaN
7 130 1963-09-08 NaN
8 130 1963-09-09 NaN