【问题标题】:Pandas Apply and Loc - efficiency and indexingPandas Apply 和 Loc - 效率和索引
【发布时间】:2018-01-28 21:56:48
【问题描述】:

我想在满足特定条件的每一行之后找到第一个值。因此,例如,我想在增加 5% 的当前行之后找到第一个速率/值(不一定是第一个 row)。添加的列将是最后一个“first5percentIncrease”,并且是增加了 5% 的第一行(在当前行之后)的索引(和/或值)。注意每个不能低于当前行的索引。

          amount    date    rate    total   type first5percentIncreaseValue first5percentIncreaseIndex
9248    0.05745868  2018-01-22 06:11:36 10  0.00099984  buy 10.5 9341
9249    1.14869147  2018-01-22 06:08:38 20  0.01998989  buy 21 9421
9250    0.16498080  2018-01-22 06:02:59 15  0.00286241  sell 15.75 9266
9251    0.02881844  2018-01-22 06:01:54 2   0.00049999  sell 2.1 10911

我尝试使用 loc 将其应用于每一行。对于大约 9k 行,输出至少需要 10 秒。这可以完成工作(我得到一个比给定行高 5% 的所有值的列表)但是有没有更有效的方法来做到这一点?此外,我只想获得第一个值,但是当我这样做时,我认为它是从第一行开始的。有没有办法从当前行开始 .locs 搜索,这样我就可以取第一个值?

coin_trade_history_df['rate'].apply(
    lambda y: coin_trade_history_df['rate'].loc[coin_trade_history_df['rate'].apply(
        lambda x: y  >= x + (x*.005))])

0    [0.01387146, 0.01387146, 0.01387148, 0.0138714...
1    [0.01387146, 0.01387146, 0.01387148, 0.0138714...
2    [0.01387146, 0.01387146, 0.01387148, 0.0138714...
3    [0.01387146, 0.01387146, 0.01387148, 0.0138714...
4    [0.01387146, 0.01387146, 0.01387148, 0.0138714...
Name: rate, dtype: object

进一步澄清Peter Leimbigler说得比我好:

哦,我想我现在明白了! “对于每一行,向下扫描并获得您遇到的第一行显示至少增加 5%,”对吗?我会编辑我的答案 :) – Peter Leimbigler

【问题讨论】:

  • 想到的一件事是预先计算前一行的百分比变化列,然后根据新列的布尔索引选择行。
  • 好主意 - 但不理想;这只占前一行/分钟。然后,我需要为每个“班次”/行预先计算一个列,这可能会起作用,因为通常在 90 分钟内似乎会发生微不足道的 0.5% 的增长 = 90 个额外的列——尽管谢谢!
  • 如果您可以发布一个小样本数据框并显示所需的结果,这将非常有帮助,否则任何人都很难测试他们的答案。我添加了 numpy/numba 标签,因为对于此类问题,这些方法可能会更快

标签: python pandas apply pandas-loc


【解决方案1】:

以下是使用显示至少增加 5% 的下一个可用行的索引标记每一行的具体示例的方法。

# Example data
df = pd.DataFrame({'rate': [100, 105, 99, 110, 130, 120, 98]})

# Series.shift(n) moves elements n places forward = down. We use
# it here in the denominator in order to compare each change with 
# the initial value, rather than the final value.

mask = df.rate.diff()/df.rate.shift() >= 0.05

df.loc[mask, 'next_big_change_idx'] = df[mask].index
df.next_big_change_idx = df.next_big_change_idx.bfill().shift(-1)

# output
df
   rate  next_big_change_idx
0   100                  1.0
1   105                  3.0
2    99                  3.0
3   110                  4.0
4   130                  NaN
5   120                  NaN
6    98                  NaN

【讨论】:

  • 对不起,这不是我要找的,而是非常pythonic :) 我澄清了措辞,因为我理解混淆“所以例如我想找到第一个速率/值(不一定是第一行after) 在增加 5% 的当前行之后。"
  • 哦,我想我现在明白了! “对于每一行,向下扫描并获得您遇到的第一行显示至少增加 5%,”对吗?我会编辑我的答案:)
  • 是的 - 我实际上在问题本身中添加了您的解释
  • @LiamHanninen,我已经编辑了我的答案 - 希望这更接近您正在寻找的内容。可能有更快和/或单行的解决方案,但至少这应该比嵌套的 apply!
  • @LiamHanninen,我错过了那个细节。添加df.next_big_change_idx = df.next_big_change_idx.shift(-1)怎么样? (我会将其编辑为答案)
【解决方案2】:

彼得的回答要快得多,但它只查看了下一行。我希望它在每一行都执行此操作。下面是我最终得到的结果 - 不是很快,但它遍历每一行并返回满足我的标准(增加 5%)的第一个值(或在我的情况下的最后一个值,因为我的时间序列正在下降)。

def test_rows(x):
    return trade_history_df['rate'].loc[
        trade_history_df['rate'] >= x['rate'] + (x['rate'] * .05)].loc[
        trade_history_df['date'] > x['date']].last_valid_index()

test1 = trade_history_df[['rate','date']].apply(test_rows,axis = 1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    • 2017-03-11
    • 2015-02-14
    • 1970-01-01
    • 2019-03-03
    • 2021-05-20
    相关资源
    最近更新 更多