作者简介:Mort,数据分析爱好者,擅长数据可视化,比较关注机器学习领域,希望能和业内朋友多学习交流
很多人在用Python做数据可视化时都会用到matplotlib,但主要都用其来做静态图片,很少有人来做交互式的可视化,笔者今天就用matplotlib来做一个交互式的展示,而笔者今天就用matplotlib来做一个交互式的展示,而展示的对象就是最近比较热(熔)门(断)的美股数据。展示的对象就是最近比较热(熔)门(断)的美股数据。
大体构思如下,首先获取美股数据,经过处理之后用matplotlib(jupyter notebook)来展示,用户可以在点击相关数据点后,在图片的标题处显示相关信息,也就是把图片的标题作为交互式的输出口,而图片本身作为数据的选取处。大致效果如下图所示(动图)。
图1. 整体效果动图
这次选取的美股是AMD,AMD作为全球第二大X86芯片厂商,近几年发展迅速,股价涨势喜人,所以选择这只股票还是具有一定代表意义的。
图2. AMD CEO苏妈
首先还 是导入各种库。
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import yfinance as yf
%matplotlib
这里有一个不太常见的库是yfinance,这是从Yahoo网站获取数据的一个库,其使用非常简单,不需要相关api,同时也是免费的,而市场上其他不少库都要api,很多还是收费的,同时还有很多限制,所以我们选用了yfinance作为数据来源。yfinance直接用pip安装即可,笔者用的是anaconda,但用了conda安装会失败,最好还是用pip安装。而%matplotlib命令是在作图时弹出一个新窗口,这样才能交互式显示。接下来是获取数据。
df_amd = yf.download('AMD', start='2010-01-02', end='2020-01-01', progress=False) #progress是进度显示条,最好关闭
yfinance下载的数据直接是pandas的dataframe格式,这里我们只要输入股票代码以及起止时间就可以了,后面的progress是进度条选项,最好关闭,否则下载好之后结果中会有一个进度条(影响也不大)。这里我们下载AMD过去10年的股票数据,从2010年1月1日到2019年12月31日。这里有一个问题要注意,就是yfinance的数据获取时间是提前1天的,比如设置起始时间start='2010-01-02',但最终得到的股票数据时间是从2010年1月1日开始的, 同样截止时间end='2020-01-01'也就意味着数据的截止时间是2019年12月31日。下载之后的部分数据如下图所示。
图3. yf下载的部分美股数据
然后是数据处理部分,代码如下。
df = df_amd[['Adj Close']] #这里要用两个[],否则是一个series而不是df
df['s_r'] = df/df.shift(1)-1 #计算简单收益率
df.rename(columns={'Adj Close':'adj_close'},inplace=True) #更改columns
df_rolling = df[['s_r']].rolling(window=21).agg(['mean', 'std']) #以21天为窗口期,计算窗口期内的平均值和标准差
df_rolling.columns = df_rolling.columns.droplevel() #columns标签有两层,去掉外面的一层
df_abnorm = df.join(df_rolling) #合并数据
def scout(row): #这个函数用来找出异常值
rtn = row['s_r']
mean = row['mean']
std = row['std']
if (rtn > mean + 3 * std) or (rtn < mean - 3 * std):
return 1
else:
return 0
df_abnorm['abnorm'] = df_abnorm.apply(scout, axis=1)
abnorm = df_abnorm[df_abnorm['abnorm'] == 1]['s_r']
这里的代码较长,详细解释一下。我们在下载好数据后,只用到里面的Adj Close这一列,然后用这一列来计算简单收益率,即simple returns,方法是用后一天数据除以前一天数据,再减一,当然这里用dataframe的pct_change方法也可以,得到的结果是一样的,我们将得到的结果命名为s_r,意思就是simple returns。然后把Adj Close这一列改名为adj_close,便于以后操作。而df_rolling = df[['s_r']].rolling(window=21).agg(['mean', 'std'])这一行可能很多人不明白,意思就是以21天的时间为窗口期,滚动计算这个窗口期内的平均值和标准差,为什么是21天,因为股票交易一个月内大概就有21天,毕竟要除去节假日。而df_rolling.columns = df_rolling.columns.droplevel()这一行则是去掉column外层的标签,我们可以先看下操作前的df_rolling是什么样的。
图4. 处理前的
df\_rolling
去掉之后是这样的。也就是少了s_r这一层标签。
图5. 处理后的
df\_rolling
然后再让df_rolling和df合并一下。最后这个scout函数,就是找出异常点,凡是在[均值-3x标准差,均值+3x标准差]这个范围内的都是正常值,之外的都是异常值,正常值标为0,异常值标为1,这个scout函数是以横向数据也就是每一行作为单位的。最后我们得出异常点的数据序列,命名为abnorm。接下来是交互函数,设定一个函数on_pick,这个函数在之后的数据可视化时会用到。其中event是指交互事件,比如移动鼠标、点击、选取等,这里主要是指点击,本文中当我们点击图片中某个点时,就会触发event事件,然后event.ind是指所点击的那个点的序列号,比如点击点是第5个点,那么其event.ind就是[4],是一个长度为1的list,因为Python起始数值为0,所以为4。下面x和y都是这个点的坐标。
def on_pick(event):
ind = event.ind[0] #ind是一个list,这点一定注意
x = event.mouseevent.xdata
y = event.mouseevent.ydata
date = abnorm.index[ind]
string_date = 'The date is %s, and the simple return is %s' % (date.date(), round(y, 2))
plt.title(string_date)
fig.canvas.draw()
然后是数据可视化。
fig, ax = plt.subplots(figsize=(12,8))
ax.plot(df_abnorm.index, df_abnorm.s_r, color='blue', label='Normal')
ax.scatter(abnorm.index, abnorm.values, picker=5, color='red', label='Abnormal')
ax.set_title("AMD stock ananlysis")
ax.legend(loc='upper left')
fig.canvas.mpl_connect('pick_event', on_pick)
plt.show()
这里把所有的简单收益率的数据用蓝色的线条来表示,异常点用红色的圆圈来表示,当点击某个异常点时图片的题目处就会显示这个点的日期和简单收益率。静态效果图如下。
图6. 完成效果静态截图
最后再放一张动态图。
图7. 完成效果动态图
赞 赏 作 者
Python中文社区作为一个去中心化的全球技术社区,以成为全球20万Python中文开发者的精神部落为愿景,目前覆盖各大主流媒体和协作平台,与阿里、腾讯、百度、微软、亚马逊、开源中国、CSDN等业界知名公司和技术社区建立了广泛的联系,拥有来自十多个国家和地区数万名登记会员,会员来自以工信部、清华大学、北京大学、北京邮电大学、中国人民银行、中科院、中金、华为、BAT、谷歌、微软等为代表的政府机关、科研单位、金融机构以及海内外知名公司,全平台近20万开发者关注。
推荐阅读:
扫码关注下方公号回复 “ 美股 ” 获取源码
▼点击阅读原文 立即秒杀云产品!
