Python 算法交易秘籍(一)(2)https://developer.aliyun.com/article/1523075
它是如何工作的…
在步骤 1中,从datetime
模块导入datetime
类和pandas
包。在步骤 2中,创建一个时间序列数据,这通常由第三方 API 返回历史数据。这个数据是一个字典列表,每个字典有相同的键集——date
、open
、high
、low
、close
和volume
。注意date
键的值是一个datetime
对象,其他键的值是float
对象。
在步骤 3中,通过直接调用构造函数并将time_series_data
作为参数来创建一个 pandas DataFrame
对象,并将返回数据分配给df
。字典的键成为df
的列名,值成为数据。在步骤 4中,使用columns
属性和tolist()
方法将df
的列作为列表提取出来。您可以验证time_series_data
中字典的键与列名相同。
在步骤 5中,通过向构造函数传递columns
参数以特定顺序的列来创建一个DataFrame
,该参数是一个字符串列表。
还有更多
当创建一个DataFrame
对象时,会自动分配一个索引,这是所有行的地址。前面示例中最左边的列是索引列。默认情况下,索引从0
开始。可以通过向DataFrame
构造函数传递一个index
参数以迭代器的形式设置自定义索引。如下所示:
- 从
time_series_data
创建一个新的 DataFrame 对象,带有自定义索引:
>>> pandas.DataFrame(time_series_data, index=range(10, 20))
我们得到以下输出:
date open high low close volume 10 2019-11-13 09:00:00 71.8075 71.8450 71.7775 71.7925 219512 11 2019-11-13 09:15:00 71.7925 71.8000 71.7800 71.7925 59252 12 2019-11-13 09:30:00 71.7925 71.8125 71.7600 71.7625 57187 13 2019-11-13 09:45:00 71.7600 71.7650 71.7350 71.7425 43048 14 2019-11-13 10:00:00 71.7425 71.7800 71.7425 71.7775 45863 15 2019-11-13 10:15:00 71.7750 71.8225 71.7700 71.8150 42460 16 2019-11-13 10:30:00 71.8150 71.8300 71.7775 71.7800 62403 17 2019-11-13 10:45:00 71.7750 71.7875 71.7475 71.7525 34090 18 2019-11-13 11:00:00 71.7525 71.7825 71.7475 71.7625 39320 19 2019-11-13 11:15:00 71.7625 71.7925 71.7600 71.7875 20190
注意输出中的索引从10
开始到19
结束。默认索引值应该是从0
到9
。
DataFrame 操作—重命名、重新排列、反转和切片
创建DataFrame
对象后,你可以对其执行各种操作。本示例涵盖了对DataFrame
对象进行以下操作。重命名列、重新排列列、反转DataFrame
,以及对DataFrame
进行切片以提取行、列和数据子集。
准备工作完成
确保df
对象在你的 Python 命名空间中可用。请参考本章的创建 pandas.DataFrame 对象示例来设置该对象。
如何执行…
对这个示例执行以下步骤:
- 将
df
的date
列重命名为timestamp
。打印它:
>>> df.rename(columns={'date':'timestamp'}, inplace=True) >>> df
我们得到以下输出:
timestamp open high low close volume 0 2019-11-13 09:00:00 71.8075 71.8450 71.7775 71.7925 219512 1 2019-11-13 09:15:00 71.7925 71.8000 71.7800 71.7925 59252 2 2019-11-13 09:30:00 71.7925 71.8125 71.7600 71.7625 57187 3 2019-11-13 09:45:00 71.7600 71.7650 71.7350 71.7425 43048 4 2019-11-13 10:00:00 71.7425 71.7800 71.7425 71.7775 45863 5 2019-11-13 10:15:00 71.7750 71.8225 71.7700 71.8150 42460 6 2019-11-13 10:30:00 71.8150 71.8300 71.7775 71.7800 62403 7 2019-11-13 10:45:00 71.7750 71.7875 71.7475 71.7525 34090 8 2019-11-13 11:00:00 71.7525 71.7825 71.7475 71.7625 39320 9 2019-11-13 11:15:00 71.7625 71.7925 71.7600 71.7875 20190
- 通过重新排列
df
中的列创建一个新的DataFrame
对象:
>>> df.reindex(columns=[ 'volume', 'close', 'timestamp', 'high', 'open', 'low' ])
我们得到以下输出:
volume close timestamp high open low 0 219512 71.7925 2019-11-13 09:00:00 71.8450 71.8075 71.7775 1 59252 71.7925 2019-11-13 09:15:00 71.8000 71.7925 71.7800 2 57187 71.7625 2019-11-13 09:30:00 71.8125 71.7925 71.7600 3 43048 71.7425 2019-11-13 09:45:00 71.7650 71.7600 71.7350 4 45863 71.7775 2019-11-13 10:00:00 71.7800 71.7425 71.7425 5 42460 71.8150 2019-11-13 10:15:00 71.8225 71.7750 71.7700 6 62403 71.7800 2019-11-13 10:30:00 71.8300 71.8150 71.7775 7 34090 71.7525 2019-11-13 10:45:00 71.7875 71.7750 71.7475 8 39320 71.7625 2019-11-13 11:00:00 71.7825 71.7525 71.7475 9 20190 71.7875 2019-11-13 11:15:00 71.7925 71.7625 71.7600
- 通过反转
df
中的行创建一个新的DataFrame
对象:
>>> df[::-1]
我们得到以下输出:
timestamp open high low close volume 9 2019-11-13 11:15:00 71.7625 71.7925 71.7600 71.7875 20190 8 2019-11-13 11:00:00 71.7525 71.7825 71.7475 71.7625 39320 7 2019-11-13 10:45:00 71.7750 71.7875 71.7475 71.7525 34090 6 2019-11-13 10:30:00 71.8150 71.8300 71.7775 71.7800 62403 5 2019-11-13 10:15:00 71.7750 71.8225 71.7700 71.8150 42460 4 2019-11-13 10:00:00 71.7425 71.7800 71.7425 71.7775 45863 3 2019-11-13 09:45:00 71.7600 71.7650 71.7350 71.7425 43048 2 2019-11-13 09:30:00 71.7925 71.8125 71.7600 71.7625 57187 1 2019-11-13 09:15:00 71.7925 71.8000 71.7800 71.7925 59252 0 2019-11-13 09:00:00 71.8075 71.8450 71.7775 71.7925 219512
- 从
df
中提取close
列:
>>> df['close']
我们得到以下输出:
0 71.7925 1 71.7925 2 71.7625 3 71.7425 4 71.7775 5 71.8150 6 71.7800 7 71.7525 8 71.7625 9 71.7875 Name: close, dtype: float64
- 从
df
中提取第一行:
>>> df.iloc[0]
我们得到以下输出:
timestamp 2019-11-13 09:00:00 open 71.8075 high 71.845 low 71.7775 close 71.7925 volume 219512 Name: 10, dtype: object
- 提取一个2 × 2矩阵,只包括前两行和前两列:
>>> df.iloc[:2, :2]
我们得到以下输出:
timestamp open 0 2019-11-13 09:00:00 71.8075 1 2019-11-13 09:15:00 71.7925
它的工作原理…
重命名:在步骤 1 中,你使用 pandas 的 DataFrame 的rename()
方法将date
列重命名为timestamp
。你通过将columns
参数作为一个字典传递,其中要替换的现有名称作为键,其新名称作为相应的值。你还将inplace
参数传递为True
,以便直接修改df
。如果不传递,其默认值为False
,意味着将创建一个新的DataFrame
而不是修改df
。
重新排列:在步骤 2 中,你使用reindex()
方法从df
创建一个新的DataFrame
,重新排列其列。你通过传递columns
参数以字符串列表的形式传递所需的顺序的列名。
反转:在步骤 3 中,你通过以一种特殊的方式使用索引运算符[::-1]
从df
创建一个新的DataFrame
,其中的行被反转。这类似于我们反转常规的 Python 列表的方式。
切片:在步骤 4 中,你使用df
上的索引运算符提取列close
。你在这里传递列名close
作为索引。返回的数据是一个pandas.Series
对象。你可以在 DataFrame 对象上使用iloc
属性来提取行、列或子集 DataFrame 对象。在步骤 5 中,你使用iloc
提取第一行,并使用0
作为索引。返回的数据是一个pandas.Series
对象。在步骤 6 中,你使用iloc
提取从df
中的(:2, :2)
开始的 2x2 子集。这意味着提取直到索引 2(即 0 和 1)的所有行和直到索引 2(再次是 0 和 1)的所有列的数据。返回的数据是一个pandas.DataFrame
对象。
在此示例中显示的所有操作中,返回一个新的DataFrame
对象的地方,原始的DataFrame
对象保持不变。
还有更多
.iloc()
属性也可以用于从DataFrame
中提取列。以下代码展示了这一点。
从df
中提取第四列。观察输出:
>>> df.iloc[:, 4]
我们得到以下输出:
0 71.7925 1 71.7925 2 71.7625 3 71.7425 4 71.7775 5 71.8150 6 71.7800 7 71.7525 8 71.7625 9 71.7875 Name: close, dtype: float64
注意,此输出和 步骤 4 的输出相同。
DataFrame 操作 — 应用、排序、迭代和连接
在上一个食谱的基础上,本食谱演示了可以对 DataFrame
对象执行的更多操作:对列中的所有元素应用函数、基于列进行排序、迭代行以及垂直和水平连接多个 DataFrame
对象。
准备工作
在尝试此食谱之前,请确保您已经完成了上一个食谱。确保您的 Python 命名空间中有来自上一个食谱的 df
。
如何做…
为此食谱执行以下步骤:
- 导入必要的模块
>>> import random >>> import pandas
- 使用不同的日期和时间格式
DD-MM-YYYY HH:MM:SS
修改df
的时间戳列中的值:
>>> df['timestamp'] = df['timestamp'].apply( lambda x: x.strftime("%d-%m-%Y %H:%M:%S")) >>> df
我们得到以下输出:
timestamp open high low close volume 0 13-11-2019 09:00:00 71.8075 71.8450 71.7775 71.7925 219512 1 13-11-2019 09:15:00 71.7925 71.8000 71.7800 71.7925 59252 2 13-11-2019 09:30:00 71.7925 71.8125 71.7600 71.7625 57187 3 13-11-2019 09:45:00 71.7600 71.7650 71.7350 71.7425 43048 4 13-11-2019 10:00:00 71.7425 71.7800 71.7425 71.7775 45863 5 13-11-2019 10:15:00 71.7750 71.8225 71.7700 71.8150 42460 6 13-11-2019 10:30:00 71.8150 71.8300 71.7775 71.7800 62403 7 13-11-2019 10:45:00 71.7750 71.7875 71.7475 71.7525 34090 8 13-11-2019 11:00:00 71.7525 71.7825 71.7475 71.7625 39320 9 13-11-2019 11:15:00 71.7625 71.7925 71.7600 71.7875 20190
- 创建一个按照
close
列升序排列的新的DataFrame
对象:
>>> df.sort_values(by='close', ascending=True)
我们得到以下输出:
timestamp open high low close volume 3 13-11-2019 09:45:00 71.7600 71.7650 71.7350 71.7425 43048 7 13-11-2019 10:45:00 71.7750 71.7875 71.7475 71.7525 34090 2 13-11-2019 09:30:00 71.7925 71.8125 71.7600 71.7625 57187 8 13-11-2019 11:00:00 71.7525 71.7825 71.7475 71.7625 39320 4 13-11-2019 10:00:00 71.7425 71.7800 71.7425 71.7775 45863 6 13-11-2019 10:30:00 71.8150 71.8300 71.7775 71.7800 62403 9 13-11-2019 11:15:00 71.7625 71.7925 71.7600 71.7875 20190 0 13-11-2019 09:00:00 71.8075 71.8450 71.7775 71.7925 219512 1 13-11-2019 09:15:00 71.7925 71.8000 71.7800 71.7925 59252 5 13-11-2019 10:15:00 71.7750 71.8225 71.7700 71.8150 42460
- 创建一个按照
open
列降序排列的新的DataFrame
对象:
>>> df.sort_values(by='open', ascending=False)
我们得到以下输出:
timestamp open high low close volume 6 13-11-2019 10:30:00 71.8150 71.8300 71.7775 71.7800 62403 0 13-11-2019 09:00:00 71.8075 71.8450 71.7775 71.7925 219512 2 13-11-2019 09:30:00 71.7925 71.8125 71.7600 71.7625 57187 1 13-11-2019 09:15:00 71.7925 71.8000 71.7800 71.7925 59252 7 13-11-2019 10:45:00 71.7750 71.7875 71.7475 71.7525 34090 5 13-11-2019 10:15:00 71.7750 71.8225 71.7700 71.8150 42460 9 13-11-2019 11:15:00 71.7625 71.7925 71.7600 71.7875 20190 3 13-11-2019 09:45:00 71.7600 71.7650 71.7350 71.7425 43048 8 13-11-2019 11:00:00 71.7525 71.7825 71.7475 71.7625 39320 4 13-11-2019 10:00:00 71.7425 71.7800 71.7425 71.7775 45863
- 遍历
df
以找到每行的open
、close
、high
和low
的平均值:
>>> for _, row in df.iterrows(): avg = (row['open'] + row['close'] + row['high'] + row['low'])/4 print(f"Index: {_} | Average: {avg}")
我们得到以下输出:
Index: 0 | Average: 71.805625 Index: 1 | Average: 71.79124999999999 Index: 2 | Average: 71.781875 Index: 3 | Average: 71.750625 Index: 4 | Average: 71.760625 Index: 5 | Average: 71.795625 Index: 6 | Average: 71.800625 Index: 7 | Average: 71.765625 Index: 8 | Average: 71.76124999999999 Index: 9 | Average: 71.775625
- 逐列迭代
df
的第一行的所有值:
>>> for value in df.iloc[0]: print(value)
我们得到以下输出:
13-11-2019 09:00:00 71.8075 71.845 71.7775 71.7925 219512
- 创建一个样本时间序列数据作为字典对象的列表。将其分配给
df_new
:
>>> df_new = pandas. DataFrame([ {'timestamp': datetime.datetime(2019, 11, 13, 11, 30), 'open': 71.7875, 'high': 71.8075, 'low': 71.77, 'close': 71.7925, 'volume': 18655}, {'timestamp': datetime.datetime(2019, 11, 13, 11, 45), 'open': 71.7925, 'high': 71.805, 'low': 71.7625, 'close': 71.7625, 'volume': 25648}, {'timestamp': datetime.datetime(2019, 11, 13, 12, 0), 'open': 71.7625, 'high': 71.805, 'low': 71.75, 'close': 71.785, 'volume': 37300}, {'timestamp': datetime.datetime(2019, 11, 13, 12, 15), 'open': 71.785, 'high': 71.7925, 'low': 71.7575, 'close': 71.7775, 'volume': 15431}, {'timestamp': datetime.datetime(2019, 11, 13, 12, 30), 'open': 71.7775, 'high': 71.795, 'low': 71.7725, 'close': 71.79, 'volume': 5178}]) >>> df_new
我们得到以下输出:
timestamp open high low close volume 0 2019-11-13 11:30:00 71.7875 71.8075 71.7700 71.7925 18655 1 2019-11-13 11:45:00 71.7925 71.8050 71.7625 71.7625 25648 2 2019-11-13 12:00:00 71.7625 71.8050 71.7500 71.7850 37300 3 2019-11-13 12:15:00 71.7850 71.7925 71.7575 71.7775 15431 4 2019-11-13 12:30:00 71.7775 71.7950 71.7725 71.7900 5178
- 通过垂直连接
df
和df_new
创建一个新的 DataFrame:
>>> pandas.concat([df, df_new]).reset_index(drop=True)
我们得到以下输出:
timestamp open high low close volume 0 13-11-2019 09:00:00 71.8075 71.8450 71.7775 71.7925 219512 1 13-11-2019 09:15:00 71.7925 71.8000 71.7800 71.7925 59252 2 13-11-2019 09:30:00 71.7925 71.8125 71.7600 71.7625 57187 3 13-11-2019 09:45:00 71.7600 71.7650 71.7350 71.7425 43048 4 13-11-2019 10:00:00 71.7425 71.7800 71.7425 71.7775 45863 5 13-11-2019 10:15:00 71.7750 71.8225 71.7700 71.8150 42460 6 13-11-2019 10:30:00 71.8150 71.8300 71.7775 71.7800 62403 7 13-11-2019 10:45:00 71.7750 71.7875 71.7475 71.7525 34090 8 13-11-2019 11:00:00 71.7525 71.7825 71.7475 71.7625 39320 9 13-11-2019 11:15:00 71.7625 71.7925 71.7600 71.7875 20190 10 2019-11-13 11:30:00 71.7875 71.8075 71.7700 71.7925 18655 11 2019-11-13 11:45:00 71.7925 71.8050 71.7625 71.7625 25648 12 2019-11-13 12:00:00 71.7625 71.8050 71.7500 71.7850 37300 13 2019-11-13 12:15:00 71.7850 71.7925 71.7575 71.7775 15431 14 2019-11-13 12:30:00 71.7775 71.7950 71.7725 71.7900 5178
它是如何工作的…
在 步骤 1 中,您导入 pandas
包。
应用:在 步骤 2 中,您通过使用 apply
方法修改 df
的 timestamp
列中的所有值。此方法接受要应用的函数作为输入。您在此处传递一个期望一个 datetime
对象作为单个输入的 lambda 函数,并使用 strftime()
将其转换为所需格式的字符串。(有关 strftime()
的更多详细信息,请参阅 将 datetime 对象转换为字符串 食谱)。apply
方法调用在 df
的 timestamp
列上,这是一个 pandas.Series
对象。lambda 函数应用于列中的每个值。此调用返回一个新的 pandas.Series
对象,您将其重新分配给 df
的 timestamp
列。注意,之后,df
的 timestamp
列保存的是字符串对象,而不是之前的 datetime
对象。
排序:在 步骤 3 中,您通过按照 df
的 close
列升序排列来创建一个新的 DataFrame
对象。您使用 sort_values()
方法来执行排序。类似地,在 步骤 4 中,您通过按照 df
的 open
列降序排列来创建一个新的 DataFrame
对象。
迭代:在步骤 5中,您使用iterrows()
方法迭代df
以找到并打印出每行的open
、close
、high
和low
的平均值。iterrows()
方法将每行作为一个(index, pandas.Series
)对进行迭代。在步骤 6中,您使用df.iloc[0]
迭代df
的第一行的所有值。您将第一行的timestamp
、open
、high
、low
、close
和volume
列值作为输出。
连接:在步骤 6中,您创建了一个新的DataFrame
,类似于创建 pandas.DataFrame 对象配方中创建的那个,并将其赋值给df_new
。您使用pandas.concat()
函数通过垂直连接dt
和df_new
来创建一个新的DataFrame
。这意味着将创建一个新的DataFrame
,其中df_new
的行附加在df
的行下面。您将包含df
和df_new
的列表作为参数传递给pandas.concat()
函数。另外,为了创建一个从0
开始的新索引,您使用了reset_index()
方法,并将参数 drop 传递为True
。如果您不使用reset_index()
,则连接的DataFrame
的索引会看起来像这样—0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4
。(有关DataFrame
索引的更多信息,请参阅创建 pandas.DataFrame 对象配方。)
还有更多
您也可以使用pandas.concat()
函数将两个DataFrame
对象水平连接在一起,即列方向上,通过将axis
参数传递给pandas.concat()
方法一个值为1
。这在以下步骤中显示:
- 从 Python 标准库导入
random
模块:
>>> import random
- 使用一个单列
open
和随机值创建一个DataFrame
对象。将其赋值给df1
并打印出来:
>>> df1 = pandas.DataFrame([random.randint(1,100) for i in range(10)], columns=['open']) >>> df1
我们得到以下输出。您的输出可能会有所不同:
open 0 99 1 73 2 16 3 53 4 47 5 74 6 21 7 22 8 2 9 30
- 使用一个单列
close
和随机值创建另一个DataFrame
对象。将其赋值给df2
并打印出来:
>>> df2 = pandas.DataFrame([random.randint(1,100) for i in range(10)], columns=['close']) >>> df2
我们得到以下输出:
close 0 63 1 84 2 44 3 56 4 25 5 1 6 41 7 55 8 93 9 82
- 通过水平连接
df1
和df2
创建一个新的DataFrame
>>> pandas.concat([df1, df2], axis=1)
我们得到以下输出。您的输出可能会有所不同:
open close 0 99 93 1 73 42 2 16 57 3 53 56 4 47 25 5 74 1 6 21 41 7 22 55 8 2 93 9 30 82
Python 算法交易秘籍(一)(4)https://developer.aliyun.com/article/1523093