1.3 EDA
EDA(探索性数据分析,Exploratory Data Analysis)是数据处理的一部分,通过统计方法和可视化技术来探索数据集,发现数据中的模式、关系、异常值和分布情况。
(1)加载Salesforce股票历史数据,将日期列转换为时间格式并设置为索引,然后显示数据的日期范围和前几行数据。
import warnings
warnings.filterwarnings('ignore') # 忽略警告信息
data = pd.read_csv('input/salesforce-stock-date-latest-and-updated/Salesforce_stock_history.csv') # 读取Salesforce股票历史数据
data['Date'] = pd.to_datetime(data['Date']) # 将日期列转换为日期时间格式
data = data.set_index('Date') # 将日期列设置为索引
print(data.index.min(), data.index.max()) # 打印数据的最小日期和最大日期
data.head() # 显示数据的前几行
执行后会输出:
2004-06-23 00:00:00 2021-11-18 00:00:00
Open High Low Close Volume Dividends Stock Splits
Date
2004-06-23 3.7500 4.3250 3.6875 4.30 43574400 0 0.0
2004-06-24 4.3875 4.4225 4.1250 4.19 8887200 0 0.0
2004-06-25 4.1275 4.1875 3.9475 3.95 6710000 0 0.0
2004-06-28 4.0000 4.0525 3.8600 4.00 2270800 0 0.0
2004-06-29 4.0000 4.1750 3.9575 4.10 2112000 0 0.0
(2)根据指定的日期date_split将股票数据集分为训练集和测试集,并计算训练集和测试集的样本数量。
date_split = '2013-01-01'
train = data[:date_split] # 将数据集在指定日期之前的数据分为训练集
test = data[date_split:] # 将数据集在指定日期及之后的数据分为测试集
len(train), len(test) # 计算训练集和测试集的样本数量
执行后会输出:
(2147, 2238)
(3)定义函数 plot_train_test,用于可视化训练集和测试集的数据。函数使用Candlestick图(蜡烛图)来展示股票价格数据,并在图中标记出训练集和测试集的分界线。
def plot_train_test(train, test, date_split):
data = [
Candlestick(x=train.index, open=train['Open'], high=train['High'], low=train['Low'], close=train['Close'], name='train'),
Candlestick(x=test.index, open=test['Open'], high=test['High'], low=test['Low'], close=test['Close'], name='test')
]
layout = {
'shapes': [
{'x0': date_split, 'x1': date_split, 'y0': 0, 'y1': 1, 'xref': 'x', 'yref': 'paper', 'line': {'color': 'rgb(0,0,0)', 'width': 1}}
],
'annotations': [
{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'left', 'text': '测试数据'},
{'x': date_split, 'y': 1.0, 'xref': 'x', 'yref': 'paper', 'showarrow': False, 'xanchor': 'right', 'text': '训练数据 '}
]
}
figure = Figure(data=data, layout=layout)
iplot(figure) # 绘制图形
(4)调用 plot_train_test(train, test, date_split) 函数绘制蜡烛图,帮助我们直观地比较训练集和测试集的数据,了解模型的训练和测试时间段。
plot_train_test(train, test, date_split)
对上述代码的具体说明如下所示:
- 训练集数据 (train):使用蜡烛图显示训练集中的股票开盘价、最高价、最低价和收盘价。
- 测试集数据 (test):使用蜡烛图显示测试集中的股票开盘价、最高价、最低价和收盘价。
- 添加分界线和注释:在图中添加一条垂直的分界线,标记出训练集和测试集的分界日期(date_split)。在分界线左右添加注释,分别标记“训练数据”和“测试数据”。
- 绘制图形:使用Plotly库中的iplot函数在Notebook中显示生成的图形,如图1-8所示。绿色表示收盘价相比前一天上涨,红色表示收盘价相比前一天下跌。
图1-8 绘制的蜡烛图
(5)定义一个名为 Environment1 的类,模拟一个简单的股票交易环境。类Environment1允许在给定的历史数据上执行买入、卖出或持有操作,并计算相应的奖励。环境会根据操作更新状态,并返回当前状态、奖励和是否结束的标志。
class Environment1:
def __init__(self, data, history_t=90):
self.data = data
self.history_t = history_t
self.reset()
def reset(self):
self.t = 0
self.done = False
self.profits = 0
self.positions = []
self.position_value = 0
self.history = [0 for _ in range(self.history_t)]
return [self.position_value] + self.history # 观测值
def step(self, act):
reward = 0
# act = 0: 持有, 1: 买入, 2: 卖出
if act == 1: # 买入
self.positions.append(self.data.iloc[self.t, :]['Close'])
elif act == 2: # 卖出
if len(self.positions) == 0:
reward = -1
else:
profits = 0
for p in self.positions:
profits += (self.data.iloc[self.t, :]['Close'] - p)
reward += profits
self.profits += profits
self.positions = []
# 设置下一个时间
self.t += 1
self.position_value = 0
for p in self.positions:
self.position_value += (self.data.iloc[self.t, :]['Close'] - p)
self.history.pop(0)
self.history.append(self.data.iloc[self.t, :]['Close'] - self.data.iloc[(self.t-1), :]['Close'])
# 奖励裁剪
if reward > 0:
reward = 1
elif reward < 0:
reward = -1
return [self.position_value] + self.history, reward, self.done # 观测值, 奖励, 是否结束
(6)如下代码通过创建 Environment1 类的实例并对其进行初始化和测试,模拟股票交易环境的初始状态。随后,代码随机选择了三个操作(持有、买入、卖出),并输出了每个操作后的环境状态、奖励以及是否交易结束的标志。
env = Environment1(train) # 创建环境实例
print(env.reset()) # 重置环境并打印初始状态
for _ in range(3):
pact = np.random.randint(3) # 生成一个随机操作(0: 持有, 1: 买入, 2: 卖出)
print(env.step(pact)) # 执行操作并打印结果
执行后会输出:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
([-0.1100001335144043, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.1100001335144043], 0, False)
([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.1100001335144043, -0.24000000953674316], -1, False)
([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0.1100001335144043, -0.24000000953674316, 0.04999995231628418], -1, False)