【问题标题】:pandas tricky intra-column logic熊猫棘手的列内逻辑
【发布时间】:2016-06-07 10:09:54
【问题描述】:

我有一个包含三列的 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 的每个实例的值向后传播,并且只传播到下一个此类实例或 t>9.5 的第一次出现。其余的都是NaN's。这是我需要的输出示例:

              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

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

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

【问题讨论】:

    标签: python pandas dataframe nan cumsum


    【解决方案1】:

    你可以使用:

    #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
    

    【讨论】:

      【解决方案2】:

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

      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 &lt; 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-14
        • 2019-06-06
        • 2023-01-09
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        • 2016-06-23
        相关资源
        最近更新 更多