大熊猫棘手的柱内逻辑

时间:2016-06-07 10:09:55

标签: python pandas dataframe nan cumsum

我有一个包含三列的DataFrame,tbh

              t          b           h
0           NaN      False           6
1      6.023448      False          38
2     12.996233      False          46
3      2.484907      False          67
4      5.062595      False          81
5      4.624973      False          82
6      3.367296      False          38
7      3.688879      False          53
8      6.926577       True          38
9     14.972346      False          81
10    14.442651      False          78
11     3.367296      False          67
12     5.236442      False          46
13     5.298317       True           8

我希望生成一个新列,该列向h向后传播b==True的每个实例的值,并且仅传递到下一个此类实例或第一次出现的事件t>9.5。剩下的就是NaN。这是我需要的输出示例:

              t          b           h       i
0           NaN      False           6     NaN
1      6.023448      False          38     NaN
2     12.996233      False          46      38
3      2.484907      False          67      38
4      5.062595      False          81      38
5      4.624973      False          82      38
6      3.367296      False          38      38
7      3.688879      False          53      38
8      6.926577       True          38      38
9     14.972346      False          81     NaN
10    14.442651      False          78       8
11     3.367296      False          67       8
12     5.236442      False          46       8
13     5.298317       True           8       8

我想避免迭代行,因为我有数百万行。我尝试使用b==True获取where个实例,然后使用bfill选项获取fillna,但无法告诉他何时开始填充。此外,对于apply中的各个组,这将groupby,因此我需要一个向其参数添加列并返回整个框架的函数

def get_i(x):
    x['i']=x['h'].where(x['b']==True).fillna(value=None,method='backfill').dropna()
    return x

2 个答案:

答案 0 :(得分:2)

您可以使用:

#create NaN where False values
df['i'] = np.where(df.b, df.h, np.nan)
#bfill all NaN
df['i'] = df.i.fillna(method='bfill')

#create NaN by condition
a = df[::-1].groupby('i')['t'].apply(lambda x: (x > 9.5).shift().cumsum()) >= 1
df['i'] = df.i.mask(a, np.nan)

print (df)
            t      b   h     i
0         NaN  False   6   NaN
1    6.023448  False  38   NaN
2   12.996233  False  46  38.0
3    2.484907  False  67  38.0
4    5.062595  False  81  38.0
5    4.624973  False  82  38.0
6    3.367296  False  38  38.0
7    3.688879  False  53  38.0
8    6.926577   True  38  38.0
9   14.972346  False  81   NaN
10  14.442651  False  78   8.0
11   3.367296  False  67   8.0
12   5.236442  False  46   8.0
13   5.298317   True   8   8.0

答案 1 :(得分:1)

首先,我颠倒了数据帧的顺序。它使我更简单,但没有必要:

df = df.iloc[::-1]

为了隔离b == True的实例,我添加了一个新列:

df['cum_b'] = df['b'].cumsum()

这意味着我可以按cum_b进行分组,以便分别处理每个实例。

我定义了一个函数,它找到第一个索引t > 9.5,并填充列i直到该索引:

def func(dfg):
    idx = max(dfg[dfg.t > 9.5].index, default=-1)
    dfg.loc[:, 'i'] = dfg.h.iloc[0]
    dfg.loc[dfg.index < idx, 'i'] = np.nan
    return dfg.i

请注意我如何使用maxindex < idx,因为我在恢复其订单后没有重置数据框的索引。

当我应用该功能时,我得到了您想要的结果:

In [44]: df.groupby('cum_b').apply(func)
Out[44]: 
cum_b    
1      13     8.0
       12     8.0
       11     8.0
       10     8.0
       9      NaN
2      8     38.0
       7     38.0
       6     38.0
       5     38.0
       4     38.0
       3     38.0
       2     38.0
       1      NaN
       0      NaN