我将从一些非常简单的可视化开始,然后慢慢地转向一些高级的可视化技术和工具
在开始之前,我需要再弄清楚一件事。
标题中的“完整指南”并不意味着,它有所有的可视化。在这么多不同的库中有这么多的可视化方法,所以在一篇文章中包含所有这些方法是不实际的。
但是本文可以为您提供足够的工具和技术来清楚地讲述一个故事或理解和可视化时间序列数据。我试图解释一些简单的方法和一些先进的技术。
数据集
如果您正在阅读本文以进行学习,则最好的方法是自己跟踪并运行所有代码。请随时从以下链接下载数据集:
https://github.com/rashida048/Datasets/blob/master/stock_data.csv
代码语言:javascript复制 import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.read_csv("stock_data.csv", parse_dates=True, index_col = "Date")
df.head()
我在read_csv函数中使用了“ parse_dates”参数将“日期”列转换为DatetimeIndex格式。在大多数情况下,日期是以字符串格式存储的,而字符串格式不是用于时间序列数据分析的正确格式。如果采用DatetimeIndex格式,则将其作为时间序列数据进行处理将非常有帮助。
我们先从基本开始。最基本的图形应该是使用Pandas的线形图。我将在这里绘制“Volume”数据。看看它是怎样的:
代码语言:javascript复制 df['Volume'].plot()
这是我们的“Volume”数据图,看起来有些忙碌而有一些大的峰值。将所有其他列也绘制在一个图中以同时检查所有它们的曲线将是一个好主意。
代码语言:javascript复制 df.plot(subplots=True, figsize=(10,12))
‘Open’, ‘Close’, ‘High’ ,‘Low’ 数据的曲线形状具有相同的形状。只有“Volume”具有不同的形状。
我上面使用的折线图非常适合显示季节性。重新采样数月或数周并绘制条形图是发现季节性的另一种非常简单且广泛使用的方法。我在这里绘制2016年和2017年月份数据的条形图。对于指数,我将使用[2016:]。因为我们的数据集包含直到2017年的数据。所以,2016年末应该带来2016年和2017年。
代码语言:javascript复制 df_month = df.resample("M").mean()fig, ax = plt.subplots(figsize=(10, 6))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
ax.bar(df_month['2016':].index, df_month.loc['2016':, "Volume"], width=25, align='center'
有24个小节。每个条代表一个月。2017年7月大幅飙升。
找到季节性的一种方法是使用一组箱线图。这里我将为每个月制作箱线图。我将使用Open’, ‘Close’, ‘High’ ,‘Low’数据来绘制这个图。。
代码语言:javascript复制 import seaborn as sns
#start, end = '2016-01', '2016-12'
fig, axes = plt.subplots(4, 1, figsize=(10, 16), sharex=True)
for name, ax in zip(['Open', 'Close', 'High', 'Low'], axes):
sns.boxplot(data = df, x='Month', y=name, ax=ax)
ax.set_ylabel("")
ax.set_title(name)
if ax != axes[-1]:
ax.set_xlabel('')
它清楚地显示了每月的价值差异。
有更多的方式来显示季节性。在本文的最后我用另一种方式进行讨论。
重采样和滚动
请记住上面的“Volume”数据的第一行图。正如我们之前讨论过的,这里数据量太大了。它可以通过重采样来修复。绘制月平均数据将在很大程度上解决这个问题,而不是绘制每日数据。为此,我将使用已经为上面的条形图和框图准备的df_month数据集。
代码语言:javascript复制 df_month['Volume'].plot(figsize=(8, 6))
更容易理解,更清楚!它能让你更好地了解长期趋势。
重采样在时间序列数据中很常见。大多数时候重采样是在较低的频率进行。
因此,本文将只处理低频的重采样。虽然重新采样的高频率也有必要,特别是为了建模的目的。不是为了数据分析。
在我们目前正在研究的“Volume”数据中,我们可以观察到一些大的峰值。这些类型的尖峰对数据分析或建模没有帮助。通常平滑尖峰,重新采样到较低的频率和滚动是非常有用的。
现在,将日数据和周平均“Volume”画在同一幅图上。首先,使用重采样方法制作每周平均数据集。
代码语言:javascript复制 df_week = df.resample("W").mean()
这个“df_week”和“df_month”在以后的可视化中也会很有用。
让我们把每日和每周的数据画在同一个图上。
代码语言:javascript复制 start, end = '2015-01', '2015-08'
fig, ax = plt.subplots()
ax.plot(df.loc[start:end, 'Volume'], marker='.', linestyle='-', linewidth = 0.5, label='Daily', color='black')
ax.plot(df_week.loc[start:end, 'Volume'], marker='o', markersize=8, linestyle='-', label='Weekly', color='coral')
label='Monthly', color='violet')
ax.set_ylabel("Open")
ax.legend()
周平均面积的峰值比日数据要小。
滚动是另一种非常有用的平滑曲线的方法。它取特定数据量的平均值。如果我想要一个7天的滚动,它会给我们7-d的平均数据。
让我们在上面的图中包含7-d滚动数据。
代码语言:javascript复制df_7d_rolling = df.rolling(7, center=True).mean()
start, end = '2016-06', '2017-05'fig, ax = plt.subplots()
ax.plot(df.loc[start:end, 'Volume'], marker='.', linestyle='-',
linewidth=0.5, label='Daily')
ax.plot(df_week.loc[start:end, 'Volume'], marker='o', markersize=5,
linestyle='-', label = 'Weekly mean volume')
ax.plot(df_7d_rolling.loc[start:end, 'Volume'], marker='.', linestyle='-', label='7d Rolling Average')
ax.set_ylabel('Stock Volume')
ax.legend()
在这个情节中发生了很多事情。但如果你仔细看,还是可以理解的。如果你注意到7-d的滚动平均比周平均平滑一些。
使用30-d或365-d滚动平均也很常见,以使曲线更平滑。
图表展示变化
很多时候,查看数据如何随时间变化比查看日常数据更有用。
有几种不同的方法可以计算和可视化数据的变化。
shift
shift函数在指定的时间之前或之后移动数据。如果我不指定时间,它将转移数据一天默认。这意味着你将获得前一天的数据。在像这样的财务数据中,把前一天的数据和今天的数据放在一起是很有帮助的。
因为这篇文章只专注于可视化,所以我将只绘制前一天的数据:
代码语言:javascript复制df['Change'] = df.Close.div(df.Close.shift())
df['Change'].plot(figsize=(20, 8), fontsize = 16)
在上面的代码中,.div()帮助填充丢失的数据。div()的意思是“除”。df.div(6)将把df中的每个元素除以6。但这里我用的是' df.Close.shift() '因此,df的每个元素将被' df. close .shift() '的每个元素除。这样做是为了避免' shift() '操作创建的空值。
您可以简单地指定一个时间段并进行绘图以使外观更清晰。这仅是2017年的情节。
代码语言:javascript复制df['2017']['Change'].plot(figsize=(10, 6))
尽管这种转变在很多方面都很有用。但我发现百分比变化在很多情况下很有用。
变化百分比
我将使用开始计算的月度数据。这次我选择了条形图。它清楚地显示了百分比的变化。有一个百分比更改函数可用来获取percent_change数据。
代码语言:javascript复制df_month.loc[:, 'pct_change'] = df.Close.pct_change()*100
fig, ax = plt.subplots()
df_month['pct_change' ].plot(kind='bar', color='coral', ax=ax)
ax.xaxis.set_major_locator(mdates.WeekdayLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %d'))
plt.xticks(rotation=45)
ax.legend()
我在这里画出了封闭数据的变化百分比。这里用的是月变化百分比。
差分
差分取指定距离值的差值。默认情况下,是1。如果像“df.High.diff(2)”那样指定2,它将取‘High’列的第一个和第三个元素、第二个和第四个元素的差值,依此类推。
在数据中去除趋势是一种流行的方法。这种趋势不利于预测或建模。
代码语言:javascript复制df.High.diff().plot(figsize=(10, 6))
扩展窗口
另一种转变方式。它不断增加累积。例如,如果向' High '列元素添加展开函数,则第一项元素保持不变。第二个元素成为第一个和第二个元素的累积,第三个元素成为第一个、第二个和第三个元素的累积,以此类推。你也可以在上面使用聚合函数,比如平均值、中位数、标准差等等。
这样,它就能提供随时间变化的均值、中位数、和或标准差。它对财务数据、业务销售或利润数据不是很有用吗?
代码语言:javascript复制fig, ax = plt.subplots()
ax = df.High.plot(label='High')
ax = df.High.expanding().mean().plot(label='High expanding mean')
ax = df.High.expanding().std().plot(label='High expanding std')
ax.legend()
这里我加了均值和标准差。看看每天的数据和平均值。在2017年底,每日数据显示一个巨大的高峰。但它并没有显示平均值的峰值。如果只看2017年的数据,不断扩大的平均水平可能会有所不同。
热点图
热点图通常是一种随处使用的常见数据可视化类型。在时间序列数据中,热点图也是非常有用的。
但是在深入研究热点图之前,我们需要开发一个日历来表示我们数据集的年和月数据。让我们看一个例子。
在这个演示中,我将导入一个日历包并使用pivot表函数来生成值。
代码语言:javascript复制import calendar
all_month_year_df = pd.pivot_table(df, values="Open",
index=["month"],
columns=["year"],
fill_value=0,
margins=True)
named_index = [[calendar.month_abbr[i] if isinstance(i, int) else i for i in list(all_month_year_df.index)]] # name months
all_month_year_df = all_month_year_df.set_index(named_index)
all_month_year_df
日历已经准备好了每月平均“Open”数据。现在,用它生成热点图。
代码语言:javascript复制ax = sns.heatmap(all_month_year_df, cmap='RdYlGn_r', robust=True, fmt='.2f',
annot=True, linewidths=.5, annot_kws={'size':11},
cbar_kws={'shrink':.8, 'label':'Open'})
ax.set_yticklabels(ax.get_yticklabels(), rotation=0, fontsize=10)
ax.set_xticklabels(ax.get_xticklabels(), rotation=0, fontsize=10)
plt.title('Average Opening', fontdict={'fontsize':18}, pad=14);
深红色意味着非常高的数值,深绿色意味着非常低的数值。
分解图
分解将在同一个图中显示观察结果和这三个元素:
趋势:时间序列一致的向上或向下的斜率。
季节性:时间序列的明确周期模式
噪声:异常值或缺失值
使用stats模型库,很容易做到:
代码语言:javascript复制from pylab import rcParams
import statsmodels.api as sm
rcParams['figure.figsize'] = 11, 9
decomposition = sm.tsa.seasonal_decompose(df_month['Volume'], model='Additive')
fig = decomposition.plot()
plt.show()
趋势是移动平均线。为了让对最后一行的残差有一个高层次的概念,下面是一般公式:
原始观测值=趋势 季节性 残差
尽管关于分解的文档本身说它是一种非常简单的表示,但它仍然很流行。
总结
如果你能运行上面所有的代码,恭喜你!今天,您已经学习了足够多的时间序列数据可视化。正如我在开始时提到的,有很多很酷的可视化技术可用。
作者:Rashida Nasrin Sucky
deephub翻译组
原文地址:https://towardsdatascience.com/a-complete-guide-to-time-series-data-visualization-in-python-da0ddd2cfb01