【问题标题】:How to replace a loop that looks at previous value with a formula in Python如何用 Python 中的公式替换查看先前值的循环
【发布时间】:2020-01-11 09:00:41
【问题描述】:

我的问题

我有一个循环,它根据条件(“距新低的天数 = 0”)使用另一列中的值或列中前一个值的组合来创建一列。在庞大的数据集上它真的很慢,所以我想摆脱循环并找到一个更快的公式。

当前工作代码

import numpy as np
import pandas as pd

csv1 = pd.read_csv('stock_price.csv', delimiter = ',')
df = pd.DataFrame(csv1)

for x in range(1,len(df.index)):
    if df["days from new low"].iloc[x] == 0:
        df["q"].iloc[x] = df["RSI on new low"].iloc[x]
    else:
        df["q"].iloc[x] = df["q"].iloc[x-1]

df

输入数据和预期输出

RSI on new low,days from new low,q
29.6,0,29.6
29.6,1,29.6
29.6,2,29.6
29.6,3,29.6
29.6,4,29.6
21.7,0,21.7
21.7,1,21.7
21.7,2,21.7
21.7,3,21.7
21.7,4,21.7
21.7,5,21.7
21.7,6,21.7
21.7,7,21.7
21.7,8,21.7
21.7,9,21.7
25.9,0,25.9
25.9,1,25.9
25.9,2,25.9
23.9,0,23.9
23.9,1,23.9

尝试的解决方案

我尝试使用 .shift() 函数创建一个公式,但我无法让它工作。

知道我该怎么做吗?

干杯!

【问题讨论】:

  • 或者如果每行的值不同,请尝试df['q']=np.where(df["days from new low"].eq(0),df['RSI on new low'],df['RSI on new low'].shift())
  • 行得通!谢谢你。如果我想将 IF 语句更改为 df["qB"].iloc[x] = (df["RSI on new low"].iloc[x-1] - df["RSI on new low "].iloc[x]) / -df["距离新低的天数"].iloc[x-1] 而不是 df["q"].iloc[x] = df["RSI 处于新低"]。 iloc[x] ?
  • 不符合您发布的输出,因此未来的读者会感到困惑,我建议您在此处选择一个建议的答案,并在新条件+预期输出的情况下提出一个新问题

标签: python pandas loops dataframe formula


【解决方案1】:

也许你可以使用where

df['q']= df["RSI on new low"].where(df["days from new low"] == 0).fillna(method='ffill')

请参阅此处的文档:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.where.html

【讨论】:

  • 可行,但必须先检查输入数据集中没有 nan 值。
【解决方案2】:

np.where 子句执行向量化操作,移除慢速 python for 循环。

import numpy as np  
import pandas as pd  
csv1 = pd.read_csv('stock_price.csv', delimiter = ',') 
df = pd.DataFrame(csv1) 
df['p'] = np.where(df['days from new low'].eq(0), df['RSI on new low'], np.nan) 
df['p'] = df['p'].ffill() 
print(df) 

打印:

    RSI on new low  days from new low     q     p
0             29.6                  0  29.6  29.6
1             29.6                  1  29.6  29.6
2             29.6                  2  29.6  29.6
3             29.6                  3  29.6  29.6
4             29.6                  4  29.6  29.6
5             21.7                  0  21.7  21.7
6             21.7                  1  21.7  21.7
7             21.7                  2  21.7  21.7
8             21.7                  3  21.7  21.7
9             21.7                  4  21.7  21.7
10            21.7                  5  21.7  21.7
11            21.7                  6  21.7  21.7
12            21.7                  7  21.7  21.7
13            21.7                  8  21.7  21.7
14            21.7                  9  21.7  21.7
15            25.9                  0  25.9  25.9
16            25.9                  1  25.9  25.9
17            25.9                  2  25.9  25.9
18            23.9                  0  23.9  23.9
19            23.9                  1  23.9  23.9

【讨论】:

  • @EricLeschinski 感谢您更新我的答案。但是,仅仅因为我缺少read_csv 部分而将其标记为低质量是否合适,这甚至不是我用来开发代码的部分?
  • 我没有标记您的帖子,其他人做了,您的帖子被标记为已标记,因为它是纯代码。如果您留下我的编辑,它可能会被保存。如果您想回滚到之前的代码行,那很好,但它可能会再次作为纯代码出现并删除。由你决定。整个问题非常本地化,因此也不符合一个好问题的基本要求。您的来电。
【解决方案3】:

您可以应用一个函数,而不是 上一行的“q”值 到每一行并使用此函数之前执行的

保持此结果的一种可能解决方案是使用 属性 这个函数。

所以定义一个要应用的函数:

def fn(row):
    if row['days from new low'] == 0:
        fn.rVal = row['RSI on new low']
    return fn.rVal

然后将 fn.rVal 设置为您选择的任何初始值:

fn.rVal = 0

最后一步是应用这个函数:

df['q'] = df.apply(fn, axis=1)

此解决方案比您的循环和 iloc 运行得更快。

【讨论】:

  • 我喜欢这个想法,尽管在这种情况下使用global 是不好的做法。相反,您应该将 rVal 设为 fn:fn.rVal = row['RSI on new low'] 的属性,并丢失全局声明。
  • 我根据rje的建议更改了答案。我同意,使用全局变量是一种不好的做法,尤其是当你有很多变量时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-03
  • 2023-01-02
  • 2021-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多