我有以下数据框和预期输出,我在 True
列中搜索 balance
的值。找到后,我对该行使用 balPrice
列值并将其与 endPrice
列进行比较,以查找 endPrice
低于 balPrice
的第一个实例并计算balance == True
行中的行以及找到的较低值行的第一个实例。如果没有找到更低的值,则行数设置为 0。
balance balPrice endPrice
0 False 5.34 5.34
1 False 5.34 5.34
2 False 5.34 5.34
3 False 5.34 5.27
4 False 5.44 5.25
5 False 5.28 5.12
6 True 5.31 5.2
7 False 5.44 5.35
8 False 5.485 5.44
9 False 5.525 5.5
10 False 5.53 5.53
11 False 5.58 5.51
12 False 5.65 5.52
13 False 5.3 5.3
14 False 5.58 5.54
15 False 5.64 5.55
16 True 5.69 5.65
17 False 5.69 5.59
18 False 5.7 5.62
19 False 5.81 5.77
20 False 5.65 5.73
21 False 5.65 5.86
22 True 6.00 5.89
23 False 5.65 5.85
24 False 5.65 5.83
25 False 5.9 5.88
这是我尝试过的,看起来很复杂。正在寻找更好的解决方案。
df_filtered = df[df.balance == True]
idx = []
for i in df_filtered.index:
pos = np.where(df.endPrice[i+1:] <= df.balPrice[i])[0]
if pos.size > 0:
idx.append(pos[0]+1)
else:
idx.append(0)
df_filtered['numrows'] = idx
预期输出:
balance balPrice endPrice numrows
True 5.31 5.2 7
True 5.69 5.65 1
True 6.00 5.89 1
答案 0 :(得分:0)
更新
对于较大的数据集,使用屏蔽/索引似乎比使用连接方法(至少在我的本地测试中)快得多。
start_idxs = df.loc[ df.balance ].index
df.loc[start_idxs, 'Price'] = df.loc[start_idxs, 'balPrice']
df.ffill(inplace=True)
end_rows = (df.balance == False) & (df.endPrice <= df.Price)
df.loc[end_rows, 'index'] = df.loc[end_rows].index
df.bfill(inplace=True)
df.loc[start_idxs, 'index'] -= start_idxs
df.rename(dict(index='numrows'), axis=1, inplace=True)
df.drop(columns='Price', inplace=True)
df.loc[df.balance == False, 'numrows'] = 0
join()
方法
不确定您是否会认为它更好,但一种方法是将您的条件所需的列添加到过滤后的行中 - 然后执行连接。
df['numrows'] = 0
has_balance = df.loc[ df.balance ]
has_balance = has_balance.assign(
index=has_balance.index,
lastPrice=has_balance.balPrice
)
df1 = df.join(has_balance, rsuffix='_r').ffill()
df1 = df1.query('balance == False and endPrice <= lastPrice').drop_duplicates('index')
df1['numrows'] = df1.index - df1['index']
has_balance.update(df1.set_index('index')['numrows'])
df.update(has_balance)
平衡 | balPrice | endPrice | numrows | |
---|---|---|---|---|
6 | 真 | 5.31 | 5.2 | 7 |
16 | 真 | 5.69 | 5.65 | 1 |
22 | 真 | 6 | 5.89 | 1 |
在没有 df1
变量的情况下编写
df['numrows'] = 0
has_balance = df.loc[ df.balance ]
has_balance = has_balance.assign(
index=has_balance.index,
lastPrice=has_balance.balPrice
)
has_balance.update((
df.join(has_balance, rsuffix='_r')
.ffill()
.query('balance == False and endPrice <= lastPrice')
.drop_duplicates('index')
.assign(numrows=lambda df: df.index - df['index'])
.set_index('index')
.numrows
))
df.update(has_balance)
答案 1 :(得分:0)
您可以使用 balance == True
和 groupby(df.balance.cumsum())
将行从一个 apply(numrows)
分组到下一个组:
def numrows(group):
index = (group.endPrice.iloc[1:] <= group.balPrice.iloc[0]).idxmax()
result = index - group.index[0]
return result
numrows = df.groupby(df.balance.cumsum()).apply(numrows)[1:]
df['numrows'] = numrows.set_axis(df[df.balance].index)
df['numrows'] = df.numrows.fillna(0).astype(int)
这给出了除 numrows
行之外的 balance == True
列:
df.tail()
# balance balPrice endPrice numrows
# ...
# 21 False 5.65 5.86 0
# 22 True 6.00 5.89 1
# 23 False 5.65 5.85 0
# 24 False 5.65 5.83 0
# 25 False 5.90 5.88 0
所以最后你可以这样做:
df[df.balance]
# balance balPrice endPrice numrows
# 6 True 5.31 5.20 7
# 16 True 5.69 5.65 1
# 22 True 6.00 5.89 1