pandas 棘手的列内逻辑
pandas tricky intra-column logic
我有一个包含三列的 DataFrame,t
、b
和 h
:
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
我想避免遍历行,因为我有数百万行。我尝试使用 where
获取 b==True
实例,然后使用 bfill 选项获取 fillna
实例,但无法告诉他何时开始填充。此外,这将被 apply
编辑到 groupby
中的各个组,因此我需要一个函数,将一列添加到它的参数和 returns 整个框架
def get_i(x):
x['i']=x['h'].where(x['b']==True).fillna(value=None,method='backfill').dropna()
return x
首先,我颠倒数据帧的顺序。它使我更简单,但这不是必需的:
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
请注意我是如何使用 max
和 index < 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
您可以使用:
#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
我有一个包含三列的 DataFrame,t
、b
和 h
:
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
我想避免遍历行,因为我有数百万行。我尝试使用 where
获取 b==True
实例,然后使用 bfill 选项获取 fillna
实例,但无法告诉他何时开始填充。此外,这将被 apply
编辑到 groupby
中的各个组,因此我需要一个函数,将一列添加到它的参数和 returns 整个框架
def get_i(x):
x['i']=x['h'].where(x['b']==True).fillna(value=None,method='backfill').dropna()
return x
首先,我颠倒数据帧的顺序。它使我更简单,但这不是必需的:
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
请注意我是如何使用 max
和 index < 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
您可以使用:
#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