微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用一年中离散天数的窗口,pandas 数据框使用 groupby 为 Nans 进行插值 分析

如何解决使用一年中离散天数的窗口,pandas 数据框使用 groupby 为 Nans 进行插值 分析

下面的小型可重复示例设置了一个长度为 100 年的数据帧,其中包含一些随机生成的值。然后插入 3 个 100 天的缺失值范围。使用这个小例子,我试图整理将使用一年中那一天的平均值(因此使用 .groupby)和条件来填充缺失天数的 Pandas 命令。例如,如果缺少 4 月 12 日,如何更改最后一行代码,以便仅使用最接近 4 月 12 日的 10 个来填充缺失值?换句话说,1920 年缺失的 4 月 12 日值将使用 1915 年至 1925 年之间的 4 月 12 日平均值来填补; 2000 年缺失的 4 月 12 日值将用 1995 年至 2005 年之间的平均 4 月 12 日值填充,等等。我尝试在脚本的最后一行中将 .rolling() 添加到 lambda 函数,但在我的尝试。

奖励问题:下面的例子从 1918 年到 2018 年。例如,如果一个值在 1919 年 4 月 12 日缺失,如果使用 10 个 4 月 12 日来填充缺失值,即使窗口不能因为它接近时间序列的开头,所以不要“集中”在缺少的那一天。当缺失值接近时间序列的开头和结尾时,上述第一个问题是否有足够灵活的解决方案,可以仍然使用至少 10 个值?

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()))

解决方法

这两个部分都回答了

  • 构建一个 DF dfr,这是您想要的计算
  • lambda 函数返回一个字典 {year:val,...}
  • 确保以合理的方式命名索引
  • dict展开apply(pd.Series)
  • 通过将年份列重新放入索引来重塑
  • merge() 使用原始 DF 构建 DF。 vals 列包含 NaN 0 列是要填充的值
  • 终于fillna()
# 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])

分析

  • 1918 年 4 月 11 日采用 NaN,默认值为 22,因为它是从 1921 年回填的
  • (12+2+47+47+2)/5 == 22
dfm.query("key_0==4 & key_1==11").head(7)
key_0 key_1 key_2 日期 vals 0
100 4 11 1918 1918-04-11 00:00:00 nan 22
465 4 11 1919 1919-04-11 00:00:00 12 22
831 4 11 1920 1920-04-11 00:00:00 2 22
1196 4 11 1921 1921-04-11 00:00:00 47 27
1561 4 11 1922 1922-04-11 00:00:00 47 36
1926 4 11 1923 1923-04-11 00:00:00 2 34.6
2292 4 11 1924 1924-04-11 00:00:00 37 29.4
,

我不知道我对你的问题的意图有多深。我采取的方法是满足两个要求

  1. 需要任意数量的平均值
  2. 使用这些平均值填写 NA

我已经解决了 简而言之,我不是用前后日期填充 NA,而是用从连续任意年数中提取的平均值填充 NA。

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,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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。