Python pandas数据帧使用一年中的离散天数窗口使用groupby为NAN插值
下面的小型可再现示例设置了一个长度为100年的数据帧,其中包含一些随机生成的值。然后插入3个100天的缺失值。使用这个小示例,我试图整理pandas命令,这些命令将使用一年中某一天的平均值(因此使用.groupby)和条件来填充缺少的天数。例如,如果缺少4月12日,如何更改最后一行代码,以便仅使用10个最接近的4月12日来填充缺少的值?换句话说,1920年缺失的4月12日值将使用1915年至1925年之间的平均4月12日值进行填充;2000年缺少的April 12th值将用1995年到2005年之间的平均April 12th值填充,等等。我尝试在脚本的最后一行向lambda函数添加.rolling(),但尝试失败 奖金问题:下面的例子从1918年延续到2018年。例如,如果在1919年4月12日缺少一个值,那么如果使用4月12日的10个值来填充缺少的值仍然是很好的,即使窗口不能“居中”于缺少的日期,因为它接近时间序列的开始。对于上面的第一个问题,是否有一个足够灵活的解决方案,当缺少的值接近时间序列的开始和结束时,仍然使用至少10个值Python pandas数据帧使用一年中的离散天数窗口使用groupby为NAN插值,python,pandas,Python,Pandas,下面的小型可再现示例设置了一个长度为100年的数据帧,其中包含一些随机生成的值。然后插入3个100天的缺失值。使用这个小示例,我试图整理pandas命令,这些命令将使用一年中某一天的平均值(因此使用.groupby)和条件来填充缺少的天数。例如,如果缺少4月12日,如何更改最后一行代码,以便仅使用10个最接近的4月12日来填充缺少的值?换句话说,1920年缺失的4月12日值将使用1915年至1925年之间的平均4月12日值进行填充;2000年缺少的April 12th值将用1995年到2005年
import pandas as pd
import numpy as np
import random
# create 100 yr time series
dates = pd.date_range(start="1918-01-01", end="2018-12-31").strftime("%Y-%m-%d")
vals = [random.randrange(1, 50, 1) for i in range(len(dates))]
# Create some arbitrary gaps
vals[100:200] = vals[9962:10062] = vals[35895:35995] = [np.nan] * 100
# Create dataframe
df = pd.DataFrame(dict(
list(
zip(["Date", "vals"],
[dates, vals])
)
))
# confirm missing vals
df.iloc[95:105]
df.iloc[35890:35900]
# set a date index (for use by groupby)
df.index = pd.DatetimeIndex(df['Date'])
df['Date'] = df.index
# Need help restricting the mean to the 10 nearest same-days-of-the-year:
df['vals'] = df.groupby([df.index.month, df.index.day])['vals'].transform(lambda x: x.fillna(x.mean()))
我不确定我对你问题的意图了解到了什么程度。我采取的方法是满足两个要求
import pandas as pd
import numpy as np
import random
# create 100 yr time series
dates = pd.date_range(start="1918-01-01", end="2018-12-31").strftime("%Y-%m-%d")
vals = [random.randrange(1, 50, 1) for i in range(len(dates))]
# Create some arbitrary gaps
vals[100:200] = vals[9962:10062] = vals[35895:35995] = [np.nan] * 100
# Create dataframe
df = pd.DataFrame(dict(
list(
zip(["Date", "vals"],
[dates, vals])
)
))
df['Date'] = pd.to_datetime(df['Date'])
df['mm-dd'] = df['Date'].apply(lambda x:'{:02}-{:02}'.format(x.month, x.day))
df['yyyy'] = df['Date'].apply(lambda x:'{:04}'.format(x.year))
df = df.iloc[:,1:].pivot(index='mm-dd', columns='yyyy')
df.columns = df.columns.droplevel(0)
df['nans'] = df.isnull().sum(axis=1)
df['10n_mean'] = df.iloc[:,:-1].sample(n=10, axis=1).mean(axis=1)
df['10n_mean'] = df['10n_mean'].round(1)
df.loc[df['nans'] >= 1]
yyyy 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 ... 2011 2012 2013 2014 2015 2016 2017 2018 nans 10n_mean
mm-dd
02-29 NaN NaN 34.0 NaN NaN NaN 2.0 NaN NaN NaN ... NaN 49.0 NaN NaN NaN 32.0 NaN NaN 76 21.6
04-11 NaN 43.0 12.0 28.0 29.0 28.0 1.0 38.0 11.0 3.0 ... 17.0 35.0 8.0 17.0 34.0 NaN 5.0 33.0 3 29.7
04-12 NaN 19.0 38.0 34.0 48.0 46.0 28.0 29.0 29.0 14.0 ... 41.0 16.0 9.0 39.0 8.0 NaN 1.0 12.0 3 21.3
04-13 NaN 33.0 26.0 47.0 21.0 26.0 20.0 16.0 11.0 7.0 ... 5.0 11.0 34.0 28.0 27.0 NaN 2.0 46.0 3 21.3
04-14 NaN 36.0 19.0 6.0 45.0 41.0 24.0 39.0 1.0 11.0 ... 30.0 47.0 45.0 14.0 48.0 NaN 16.0 8.0 3 24.7
df_mean = df.T.fillna(df['10n_mean'], downcast='infer').T
df_mean.loc[df_mean['nans'] >= 1]
yyyy 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 ... 2011 2012 2013 2014 2015 2016 2017 2018 nans 10n_mean
mm-dd
02-29 21.6 21.6 34.0 21.6 21.6 21.6 2.0 21.6 21.6 21.6 ... 21.6 49.0 21.6 21.6 21.6 32.0 21.6 21.6 76.0 21.6
04-11 29.7 43.0 12.0 28.0 29.0 28.0 1.0 38.0 11.0 3.0 ... 17.0 35.0 8.0 17.0 34.0 29.7 5.0 33.0 3.0 29.7
04-12 21.3 19.0 38.0 34.0 48.0 46.0 28.0 29.0 29.0 14.0 ... 41.0 16.0 9.0 39.0 8.0 21.3 1.0 12.0 3.0 21.3
04-13 21.3 33.0 26.0 47.0 21.0 26.0 20.0 16.0 11.0 7.0 ... 5.0 11.0 34.0 28.0 27.0 21.3 2.0 46.0 3.0 21.3
04-14 24.7 36.0 19.0 6.0 45.0 41.0 24.0 39.0 1.0 11.0 ... 30.0 47.0 45.0 14.0 48.0 24.7 16.0 8.0 3.0 24.7
这两部分都能回答
- 构建一个DF
,这是您想要的计算dfr
函数返回一个dictlambda
{year:val,…}
- 确保以合理的方式命名索引
- 用
apply(pd.Series)
- 通过将年份列放回索引中来重塑
使用原始DF构建DFVAL列包含merge()
0列是要填充的值NaN
- 最后
fillna()
- 以1918年4月11日的NaN为例,违约率为22,因为它是从1921年开始回填的
- (12+2+47+47+2)/5==22
如果你的NA不是太多,也就是说,速度不令人担忧,试试这个基本上循环通过所有的NAN和排序(按年的距离),得到头10
# create 100 yr time series
dates = pd.date_range(start="1918-01-01", end="2018-12-31")
vals = [random.randrange(1, 50, 1) for i in range(len(dates))]
# Create some arbitrary gaps
vals[100:200] = vals[9962:10062] = vals[35895:35995] = [np.nan] * 100
# Create dataframe - simplified from question...
df = pd.DataFrame({"Date":dates,"vals":vals})
df[df.isna().any(axis=1)]
ystart = df.Date.dt.year.min()
# generate rolling means for month/day. bfill for when it's start of series
dfr = (df.groupby([df.Date.dt.month, df.Date.dt.day])["vals"]
.agg(lambda s: {y+ystart:v for y,v in enumerate(s.dropna().rolling(5).mean().bfill())})
.to_frame().rename_axis(["month","day"])
)
# expand dict into columns and reshape to by indexed by month,day,year
dfr = dfr.join(dfr.vals.apply(pd.Series)).drop(columns="vals").rename_axis("year",axis=1).stack().to_frame()
# get df index back, plus vals & fillna (column 0) can be seen alongside each other
dfm = df.merge(dfr, left_on=[df.Date.dt.month,df.Date.dt.day,df.Date.dt.year], right_index=True)
# finally what we really want to do - fill tha NaNs
df.fillna(dfm[0])
dfm.query("key_0==4 & key_1==11").head(7)