我有一个DataFrame > id s和date s。我想创建另一个DataFrame,它列出了一个给定的月份中是否存在一个预定义的时间段(例如2018个)。此外,如果有2个月或更小的存在差距,我想填写它们。
我想我应该包括第一部分,因为从一开始就有更好的解决方案。这是开始id

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我创建了一个新的列df_exist并与一个平铺的时间段[cc]合并
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

我决定用id_existsdf_per,因为这允许我使用下面的函数和fillna,但是如果有一个解决方案可以使用False的话,那也不错。
现在我定义了一个函数,它似乎可以做我想做的事情:索引比较确保我不填充任何边上的东西,而与gap_size的比较则确保我只填充小的空白。if IOR确保它是否正确工作,无论第一个条目是真还是假,存在于cumsum
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))

不过,在大型NaN上速度相当慢。有什么办法让这个更快的吗?看起来,任何内置的df方法都不适用于这种情况,因为可能存在多个间隙。
这是预期的产出。(我已经做了一些合并,所以它没有格式化为一个令人烦恼的长表)。关键是,没有一个边缘受到干扰,只有2个月或更少的间隙被填充,并且在开始只有一个值的情况下DataFrame没有失败。
       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

最佳答案

有一种方法:

month = df.date - pd.Timedelta('1 day') * (df.date.dt.day - 1)
df_exist = df.id.astype(str).str.get_dummies().groupby(month).sum() != 0

def fill_gaps(arr):
    notnan, = (~np.isnan(arr)).nonzero()
    return np.nan if not notnan.size else arr[notnan[-1]]

date_range = pd.date_range('2018-01-01', '2018-12-31', freq='MS')
rolling = df_exist.reindex(date_range).rolling(window=2, min_periods=1)
result = rolling.apply(fill_gaps).fillna(False).astype(bool)
result[date_range > month.max()] = False

第一部分应该比手动连接快得多。第二部分对数据帧使用滚动API。
输出如下:
                1      2      3
2018-01-01  False  False  False
2018-02-01   True  False   True
2018-03-01   True  False  False
2018-04-01   True  False  False
2018-05-01   True  False  False
2018-06-01  False   True  False
2018-07-01  False   True  False
2018-08-01  False   True  False
2018-09-01  False   True  False
2018-10-01   True  False  False
2018-11-01   True  False  False
2018-12-01  False  False  False

这似乎和你例子中的结果相符。

关于python - 是否只有在间隙小于一定大小时,才可以快速填充间隙之间的NA值(可能是多个)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49823073/

10-12 01:13