如何在 Python 中创建一个简单的标志
How to create a simple flag in Python
从 Yahoo 获取 SPY 数据后,我创建了一个收盘价通道,如下所示,最大和最小滚动 window。列是 HC 和 HL。
我需要创建一个列(我称之为标志),当收盘价等于 HC 时显示 1,并且该值一直持续到收盘价等于 HL。此时Flag的值将为-1。如您所见,它非常简单,Flag 可以只有两个值; 1 或 -1。
简单的公式类似于:
- 如果 Close == HC 则标志为 1
- 如果 Close == HL 则标志为 -1
- 如果 Close != HC 和 Close !=HL 那么标志等于变量标志上保存的最后一个值。
我尝试了几件事,包括下面的代码,但没有成功。此代码的问题在于显示了 0 值。而且我不知道如何通过条件让它消失:
import pandas as pd
import pandas_datareader as dr
import numpy as np
from datetime import date
df = dr.data.get_data_yahoo('SPY',start='01-01-2019',end=date.today())
df['HC'] = df['Close'].rolling(20).max()
df['LC'] = df['Close'].rolling(20).min()
df['Flag'] = [1 if (df.loc[ei, 'Close'] == df.loc[ei, 'HC']) else
-1 if (df.loc[ei, 'Close'] == df.loc[ei, 'LC']) else
0 for ei in df.index]
您可以在下方看到我的代码结果以蓝色显示,以红色显示我需要的结果。
有没有简单的方法可以做到这一点?如果有人可以帮助我,我将不胜感激。谢谢!
一种简单的方法是使用循环,但就时间而言效率很低。但是,如果你不介意,你可以遍历数组
flag01 = 0
for ei in df.index:
if (df.loc[ei, 'Close'] == df.loc[ei, 'HC']):
flag01 = 1
if (df.loc[ei, 'Close'] == df.loc[ei, 'LC'])
flag01 = -1
df.loc[ei, 'Flag'] = flag01
基本上你设置零,只要你发现条件为真,你设置为1并保持一直到满足条件变为-1,依此类推。这比您使用的方法慢,但这是 "keep the last value" 的最简单方法,因为您正在增加该值并且您知道您之前拥有的值。
您可以使用 Pandas 的更多内置功能,特别是 fillna
逻辑索引的方法和用法。
我已将一部分代码添加到您的原始代码中以创建额外的 Good_Flag
:
import pandas_datareader as dr
from datetime import date
df = dr.data.get_data_yahoo('SPY',start='01-01-2019',end=date.today())
df['HC'] = df['Close'].rolling(20).max()
df['LC'] = df['Close'].rolling(20).min()
df['Flag'] = [1 if (df.loc[ei, 'Close'] == df.loc[ei, 'HC']) else
-1 if (df.loc[ei, 'Close'] == df.loc[ei, 'LC']) else
0 for ei in df.index]
pos_indexes = df.Close == df.HC
neg_indexes = df.Close == df.LC
df.loc[pos_indexes, 'Good_Flag'] = 1
df.loc[neg_indexes, 'Good_Flag'] = -1
df = df.fillna(method='ffill')
请注意,我使用 fillna
方法和 ffill
属性来指定 "Forward Pass"。
编辑:
为了清楚起见,原来的 Flag
列特意留在这里,新的 Good_Flag
列的计算不依赖于 Flag
.
为了展示理想的行为:
plt.plot(df.Flag, color='blue')
plt.plot(df.Good_Flag, color='red')
plt.legend(['Flag', 'Good_Flag'])
plt.show()
虽然已经回答了这个问题,但是,计算此类结果的最快方法通常是使用 np.where
,如下所示:
import pandas as pd
import pandas_datareader as dr
import numpy as np
from datetime import date
df = dr.data.get_data_yahoo('SPY',start='01-01-2019',end=date.today())
df['HC'] = df['Close'].rolling(20).max()
df['LC'] = df['Close'].rolling(20).min()
下面存在嵌套逻辑:
- 创建一个空数组
- 根据条件
将值替换为-1
- 根据条件将值替换为 1
df['Flag'] = np.where((df.Close == df.HC), 1,
np.where(df.Close == df.LC, -1, np.full(df.Close.count(), np.nan)))
df.Flag.fillna(method='ffill', inplace=True)
性能方面:
%%timeit
df['Flag'] = np.where((df.Close == df.HC), 1,
np.where(df.Close == df.LC, -1, np.full(df.Close.count(), np.nan)))
df.Flag.fillna(method='ffill', inplace=True)
912 µs ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
这绝对比循环或嵌套 if 条件更好。
例如@Tim Mironov 回答:
%%timeit
pos_indexes = (df.Close == df.HC)
neg_indexes = (df.Close == df.LC)
df.loc[pos_indexes, 'Good_Flag'] = 1
df.loc[neg_indexes, 'Good_Flag'] = -1
df.fillna(method='ffill', inplace=True)
4.43 ms ± 92 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
从 Yahoo 获取 SPY 数据后,我创建了一个收盘价通道,如下所示,最大和最小滚动 window。列是 HC 和 HL。
我需要创建一个列(我称之为标志),当收盘价等于 HC 时显示 1,并且该值一直持续到收盘价等于 HL。此时Flag的值将为-1。如您所见,它非常简单,Flag 可以只有两个值; 1 或 -1。
简单的公式类似于:
- 如果 Close == HC 则标志为 1
- 如果 Close == HL 则标志为 -1
- 如果 Close != HC 和 Close !=HL 那么标志等于变量标志上保存的最后一个值。
我尝试了几件事,包括下面的代码,但没有成功。此代码的问题在于显示了 0 值。而且我不知道如何通过条件让它消失:
import pandas as pd
import pandas_datareader as dr
import numpy as np
from datetime import date
df = dr.data.get_data_yahoo('SPY',start='01-01-2019',end=date.today())
df['HC'] = df['Close'].rolling(20).max()
df['LC'] = df['Close'].rolling(20).min()
df['Flag'] = [1 if (df.loc[ei, 'Close'] == df.loc[ei, 'HC']) else
-1 if (df.loc[ei, 'Close'] == df.loc[ei, 'LC']) else
0 for ei in df.index]
您可以在下方看到我的代码结果以蓝色显示,以红色显示我需要的结果。
有没有简单的方法可以做到这一点?如果有人可以帮助我,我将不胜感激。谢谢!
一种简单的方法是使用循环,但就时间而言效率很低。但是,如果你不介意,你可以遍历数组
flag01 = 0
for ei in df.index:
if (df.loc[ei, 'Close'] == df.loc[ei, 'HC']):
flag01 = 1
if (df.loc[ei, 'Close'] == df.loc[ei, 'LC'])
flag01 = -1
df.loc[ei, 'Flag'] = flag01
基本上你设置零,只要你发现条件为真,你设置为1并保持一直到满足条件变为-1,依此类推。这比您使用的方法慢,但这是 "keep the last value" 的最简单方法,因为您正在增加该值并且您知道您之前拥有的值。
您可以使用 Pandas 的更多内置功能,特别是 fillna
逻辑索引的方法和用法。
我已将一部分代码添加到您的原始代码中以创建额外的 Good_Flag
:
import pandas_datareader as dr
from datetime import date
df = dr.data.get_data_yahoo('SPY',start='01-01-2019',end=date.today())
df['HC'] = df['Close'].rolling(20).max()
df['LC'] = df['Close'].rolling(20).min()
df['Flag'] = [1 if (df.loc[ei, 'Close'] == df.loc[ei, 'HC']) else
-1 if (df.loc[ei, 'Close'] == df.loc[ei, 'LC']) else
0 for ei in df.index]
pos_indexes = df.Close == df.HC
neg_indexes = df.Close == df.LC
df.loc[pos_indexes, 'Good_Flag'] = 1
df.loc[neg_indexes, 'Good_Flag'] = -1
df = df.fillna(method='ffill')
请注意,我使用 fillna
方法和 ffill
属性来指定 "Forward Pass"。
编辑:
为了清楚起见,原来的 Flag
列特意留在这里,新的 Good_Flag
列的计算不依赖于 Flag
.
为了展示理想的行为:
plt.plot(df.Flag, color='blue')
plt.plot(df.Good_Flag, color='red')
plt.legend(['Flag', 'Good_Flag'])
plt.show()
虽然已经回答了这个问题,但是,计算此类结果的最快方法通常是使用 np.where
,如下所示:
import pandas as pd
import pandas_datareader as dr
import numpy as np
from datetime import date
df = dr.data.get_data_yahoo('SPY',start='01-01-2019',end=date.today())
df['HC'] = df['Close'].rolling(20).max()
df['LC'] = df['Close'].rolling(20).min()
下面存在嵌套逻辑:
- 创建一个空数组
- 根据条件 将值替换为-1
- 根据条件将值替换为 1
df['Flag'] = np.where((df.Close == df.HC), 1,
np.where(df.Close == df.LC, -1, np.full(df.Close.count(), np.nan)))
df.Flag.fillna(method='ffill', inplace=True)
性能方面:
%%timeit
df['Flag'] = np.where((df.Close == df.HC), 1,
np.where(df.Close == df.LC, -1, np.full(df.Close.count(), np.nan)))
df.Flag.fillna(method='ffill', inplace=True)
912 µs ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
这绝对比循环或嵌套 if 条件更好。
例如@Tim Mironov 回答:
%%timeit
pos_indexes = (df.Close == df.HC)
neg_indexes = (df.Close == df.LC)
df.loc[pos_indexes, 'Good_Flag'] = 1
df.loc[neg_indexes, 'Good_Flag'] = -1
df.fillna(method='ffill', inplace=True)
4.43 ms ± 92 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)