【问题标题】:pd.DataFrame: get average value per id between two datetimes; if NaN, get last non-NaN valuepd.DataFrame:获取两个日期时间之间每个 id 的平均值;如果是 NaN,则获取最后一个非 NaN 值
【发布时间】:2021-06-06 09:03:06
【问题描述】:

假设我有以下pd.DataFrame (df.to_dict()):

    eff_timestamp       val         id  begin_timestamp     end_timestamp
0   2021-01-01 00:00:00 0.677085    1   2021-01-01 02:00:00 2021-01-01 05:30:00
1   2021-01-01 01:00:00 -0.356381   1   2021-01-01 02:00:00 2021-01-01 05:30:00
2   2021-01-01 02:00:00 1.697311    1   2021-01-01 02:00:00 2021-01-01 05:30:00
3   2021-01-01 03:00:00 0.910820    1   2021-01-01 02:00:00 2021-01-01 05:30:00
4   2021-01-01 04:00:00 -1.024458   1   2021-01-01 02:00:00 2021-01-01 05:30:00
5   2021-01-01 05:00:00 -0.430950   1   2021-01-01 02:00:00 2021-01-01 05:30:00
6   2021-01-01 06:00:00 -1.124934   1   2021-01-01 02:00:00 2021-01-01 05:30:00
7   2021-01-01 07:00:00 0.791751    1   2021-01-01 02:00:00 2021-01-01 05:30:00
8   2021-01-02 00:00:00 0.629035    2   2021-01-02 02:00:00 2021-01-02 05:30:00
9   2021-01-02 01:00:00 0.445033    2   2021-01-02 02:00:00 2021-01-02 05:30:00
10  2021-01-02 02:00:00 NaN         2   2021-01-02 02:00:00 2021-01-02 05:30:00
11  2021-01-02 03:00:00 NaN         2   2021-01-02 02:00:00 2021-01-02 05:30:00
12  2021-01-02 04:00:00 NaN         2   2021-01-02 02:00:00 2021-01-02 05:30:00
13  2021-01-02 05:00:00 NaN         2   2021-01-02 02:00:00 2021-01-02 05:30:00
14  2021-01-02 06:00:00 NaN         2   2021-01-02 02:00:00 2021-01-02 05:30:00
15  2021-01-02 07:00:00 -0.637133   2   2021-01-02 02:00:00 2021-01-02 05:30:00

我想为每个唯一 id 获取一个值,它在begin_timestampend_timestamp 之间的时间段内保持val 的平均值(基于eff_timestamp)。如果该值返回np.nan,我想获得不是np.nan 的最后一个可用值。我知道如何在开始和结束时间戳之间获取“val”的平均值:

sliced = df[(df.eff_timestamp > df.begin_timestamp) & (df.eff_timestamp < df.end_timestamp)]
sliced
>>>
    eff_timestamp       val         id  begin_timestamp     end_timestamp
3   2021-01-01 03:00:00 0.910820    1   2021-01-01 02:00:00 2021-01-01 05:30:00
4   2021-01-01 04:00:00 -1.024458   1   2021-01-01 02:00:00 2021-01-01 05:30:00
5   2021-01-01 05:00:00 -0.430950   1   2021-01-01 02:00:00 2021-01-01 05:30:00
11  2021-01-02 03:00:00 NaN         2   2021-01-02 02:00:00 2021-01-02 05:30:00
12  2021-01-02 04:00:00 NaN         2   2021-01-02 02:00:00 2021-01-02 05:30:00
13  2021-01-02 05:00:00 NaN         2   2021-01-02 02:00:00 2021-01-02 05:30:00

sliced.groupby('id').val.mean()
>>>
id
1   -0.181529
2         NaN
Name: val, dtype: float64

因为 id=2 只有在 2021-01-02 02:00:002021-01-02 05:30:00 之间的 NaN 值,所以返回 NaN。但是,在这种情况下,我想获得 0.445033 的值,因为这是该患者的最后一个非 NaN 值。我该怎么做?因此输出应该是:

id
1   -0.181529
2   0.445033
Name: val, dtype: float64

【问题讨论】:

  • If that value returns np.nan, I would like to get the last available value that is not np.nan.。最后一个可用值是如何定义的?例如:当id = 2时,为什么应该是0.445033,而不是-0.637133?
  • @akilat90 它应该是begin_timestampend_timestamp 之间的句点之前的最后一个非nan 值。

标签: python pandas dataframe datetime


【解决方案1】:

你可以试试:

idx=df[df['val'].isna()].index-1

out=sliced.groupby('id')['val'].mean().fillna(df.loc[idx].groupby('id',sort=False)['val'].first())

out的输出:

id
1   -0.181529
2    0.445033
Name: val, dtype: float64

【讨论】:

    【解决方案2】:

    从您的代码继续,一旦您确定给定的 id (让我们 称之为nid)你有一个NaN值,我们可以确定切片开始的索引:

    slice_start = sliced[sliced['id'] == nid].index[0]
    

    现在我们可以得到切片之前的“val”系列部分:

    portion = df.loc[:slice_start, 'val'][df['id'] == nid]
    

    并使用last_valid_index() 获取您想要的值:

    val = df.loc[portion.last_valid_index(), 'val']
    

    【讨论】:

      【解决方案3】:

      使用您在获得上述sliced 后遗漏的数据框。叫它left_out

      # just the negation of what you've used
      left_out = df[~((df.eff_timestamp > df.begin_timestamp) & (df.eff_timestamp < df.end_timestamp))]  
      

      然后,按照上面的评论,为了过滤掉begin_timestamp之前的值:

      values_before_the_period = left_out.sort_values(["eff_timestamp", "begin_timestamp"])[left_out['eff_timestamp'] < left_out['begin_timestamp']]
      

      请注意,sort_values 可能不是必需的,如果它已经完成的话。

      这样,我们可以获得一个映射,其中包含 begin_timestamp 和 end_timestamp 之间的时间段之前的最后一个非 nan 值。

      mapping = values_before_the_period.groupby('id').tail(1)[['id', 'val']].set_index('id').to_dict()
      
      # {'val': {1: -0.3563813741494545, 2: 0.445032587866597}}
      

      制作一个系列:

      mapping_s = pd.Series((mapping['val']))
      mapping_s
      
      1   -0.356381
      2    0.445033
      dtype: float64
      

      现在,这可以与您获得的s 结合使用,只有np.nan 的值将被替换为s

      s.combine_first(mapping_s)
      
      1   -0.181529
      2    0.445033
      Name: val, dtype: float64
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-04-30
        • 2022-01-14
        • 1970-01-01
        • 1970-01-01
        • 2014-12-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多