Python 是否有一种快速的方法来填充间隙(可能是多个)之间的NA值,并且仅当间隙小于某个大小时?

Python 是否有一种快速的方法来填充间隙(可能是多个)之间的NA值,并且仅当间隙小于某个大小时?,python,pandas,pandas-groupby,Python,Pandas,Pandas Groupby,我有一个带有ids和dates的DataFrame。我想创建另一个DataFrame,其中列出了id是否存在于给定的一个月内,在预定义的时间段内(比如2018年全年)。此外,如果存在2个月或更小的差距,我愿意填补 我想我应该包括第一部分,以防从一开始就有更好的解决方案。这是开始的df import pandas as pd import numpy as np df = pd.DataFrame({'id': [1,1,1,1,1,2,2,2,3], 'date

我有一个带有
id
s和
date
s的
DataFrame
。我想创建另一个
DataFrame
,其中列出了
id
是否存在于给定的一个月内,在预定义的时间段内(比如2018年全年)。此外,如果存在2个月或更小的差距,我愿意填补

我想我应该包括第一部分,以防从一开始就有更好的解决方案。这是开始的
df

import pandas as pd
import numpy as np
df = pd.DataFrame({'id': [1,1,1,1,1,2,2,2,3],
                 'date': ['2018-02-01', '2018-03-12', '2018-05-10', 
                         '2018-10-10', '2018-11-04', '2018-06-07', '2018-07-07', 
                         '2018-09-16', '2018-02-02']})
df['date'] = pd.to_datetime(df.date)
为了获得一个存在
df\u exist
我创建了一个新列
id\u exists
并与一个平铺时间段合并
df\u per

df['id_exists'] = True
per = pd.date_range('2018-01-01', '2018-12-31', freq='MS')

df_per = pd.DataFrame({'id': np.tile(df.id.unique(), len(per)),
    'Period': np.repeat(per,df.id.nunique())})
df_exist = df_per.merge(df, left_on=['id', df_per.Period.dt.year, df_per.Period.dt.month],
             right_on=['id', df.date.dt.year, df.date.dt.month], how='left').drop(columns='date').fillna(False)

#      Period  id  id_exists
#0 2018-01-01   1      False
#1 2018-01-01   2      False
#2 2018-01-01   3      False
#3 2018-02-01   1       True
#4 2018-02-01   2      False
我决定使用
False
fillna
,因为这允许我使用下面的函数和
cumsum
,但是如果有一个解决方案利用了
NaN
的话,那当然也一样好

现在,我定义了一个函数,它似乎实现了我想要的功能:索引比较确保我不填充任何边上的内容,而与gap_size的比较确保我只填充了小的间隙。if-else确保无论存在
df
中的第一个条目是真是假,它都能正常工作

def FillGaps(df, gap_size):
    gb = df.groupby(df.id_exists.cumsum()).size()

    if df.id_exists.values[0] == False:
        to_fill = gb[(gb.index > gb.index.min()) & (gb.index < gb.index.max()) &
            (gb.values <= gap_size)].index.values
    else:
        to_fill = gb[(gb.index < gb.index.max()) & (gb.values <= gap_size)].index.values

    df.loc[df.id_exists.cumsum().isin(to_fill), 'id_exists'] = True
    return df

df_exist = df_exist.groupby('id').apply(lambda df: FillGaps(df, gap_size=2))

这里有一种方法:

month=df.date-pd.Timedelta('1天')*(df.date.dt.day-1)
df_exist=df.id.astype(str).str.get_dummies().groupby(month).sum()!=0
def填充_间隙(arr):
notnan,=(~np.isnan(arr)).nonzero()
如果不是notnan,则返回np.nan.size else arr[notnan[-1]]
日期范围=局部放电日期范围('2018-01-01','2018-12-31',频率='MS')
滚动=df\u存在。重新索引(日期范围)。滚动(窗口=2,最小周期=1)
结果=滚动。应用(填补空白)。填充NA(假)。astype(布尔)
结果[date_range>month.max()]=False
第一部分应该比手动连接快得多。第二部分为数据帧使用滚动API

输出如下所示:

123
2018-01-01假假假
2018-02-01正确-错误-正确
2018-03-01真假假假
2018-04-01真假假假
2018-05-01真假假假
2018-06-01假-真-假
2018-07-01假-真-假
2018-08-01假-真-假
2018-09-01假-真-假
2018-10-01真假假假
2018-11-01真假假假
2018-12-01假假假假

这似乎与您的示例中的结果相匹配。

虽然它适用于第一部分,但似乎无助于解决问题的根源;如何填补生存期之间的空白。它不仅仅是用
False
简单地替换
NaN
。即使我重新编制了索引,在上面的输出中,对于
id==1
id==2
id==3,我需要用
True
替换
2018-04-01
。一个简单的
fillna
不起作用,因为它不仅仅是一个焊盘或fffill,我不想弄乱边缘,我只想在间隙小于给定大小的情况下通过整个间隙传播真值。如果差距太大,我不想部分填补。如果我选择的差距足够大,比如说6个月,我甚至需要将输出中的一些非
NaN
False
更改为
True
@ALollz,我肯定错过了问题的第二部分;我已经更新了解决方案。
       Period  id_1  id_exists_1  id_2  id_exists_2  id  id_exists
0  2018-01-01     1        False     2        False   3      False
1  2018-02-01     1         True     2        False   3       True
2  2018-03-01     1         True     2        False   3      False
3  2018-04-01     1         True     2        False   3      False
4  2018-05-01     1         True     2        False   3      False
5  2018-06-01     1        False     2         True   3      False
6  2018-07-01     1        False     2         True   3      False
7  2018-08-01     1        False     2         True   3      False
8  2018-09-01     1        False     2         True   3      False
9  2018-10-01     1         True     2        False   3      False
10 2018-11-01     1         True     2        False   3      False
11 2018-12-01     1        False     2        False   3      False