首页 > 数据库 > 数据库开发技术 > python数据分析:一行代码让你的可视化动起来
前言(Preface)
今天在看书时发现了一个挺有意思的技术,就是在用Python做数据分析的过程中,可以将可视化的静态图表做成动画,可以清楚的看到目标变量随着特征变量的变化轨迹,生动而形象,有些时候可以让我们更直观的观察数据的变化趋势,从而获取有价值的见解。只需要一行代码就可以实现静态图表的动态化,本文通过几个示例将这种方法分享给大家,希望您有所收获。
动画是叙述现象的一种引人入胜的方式,任何有智力的生物总是容易被动画和互动的可视化所吸引。动画在分析时间序列数据时特别有用,它有助于我们更好地理解趋势、季节性以及特定特征在时间序列数据范围内的表现。在这篇文章中,我们将使用一个有趣的库(gif)创建一些有趣的动画。
本文,我们将使用伦敦的天气数据作为示例数据集,该数据集记录了从2011年到2014年期间伦敦市的各项天气参数变化情况(以小时为单位)。示例数据获取方式见文末。
首先导入必要的库:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import HTML
import gif
创建动画的库就是 gif,如果没有安装,请使用 pip install gif 在终端进行安装。
示例数据概览:
df = pd.read_csv('datasets/london_weather_hourly_darksky.csv')
df
接下来,我们将 time 列修改为 date,并将其设置为索引(因为该列的值是唯一的):
df = df.rename(columns={'time': 'date'})
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', drop=True, inplace=True)
df
该数据是以小时为单位记录的,这使得数据非常庞大,难以可视化,并且在内存方面计算成本非常高,因此我将使用样本函数以月为单位对数据进行重新采样。
df = df.select_dtypes(np.number).resample('M').mean()
df.head()
要实现这一点,我们将使用 Max Humber 开发的 gif 库,它允许我们通过标准的for循环创建和添加一堆“帧”,从而很简单地制作gif动画。用 @gif.frame 修饰绘图函数。
# 定义起止日期
START = df.index[0]
END = df.index[-1]
@gif.frame
def plot(df, date):
df = df.loc[df.index[0]:pd.Timestamp(date)]
fig, ax = plt.subplots(1, figsize=(20, 10), dpi=100)
ax.plot(df.temperature, marker='o', linestyle='--',
linewidth=6, markersize=15, color='tab:pink')
max_y = round(df.temperature.max() + 5)
ax.set_title('Average Monthly Temperature in London over the 2012-2014 span ', fontsize=30)
ax.set_xlim([START, END])
ax.set_ylim([0, max_y])
ax.set_ylabel('Temperature C°', color='tab:blue', fontsize=25)
frames)。frames = []
for date in pd.date_range(start=df.index[0],
end=df.index[-1], freq='1M'):
frame = plot(df, date)
frames.append(frame)
save 函数即可将静态图表转换为动画并保存:# 保存为 GIF 图片
gif.save(frames, 'images/avgMonthlyTemperature.gif', duration=0.5*1000)
# 显示刚保存的 GIF 图片
HTML('<img src="images/avgMonthlyTemperature.gif" />')
从这个动态图像中我们可以很直观地看出每个月平均气温的升降趋势。
例如,如何将数据分成训练集和测试集。这里我使用 axvspan和 text 函数。
@gif.frame
def plot_split(df, date, split_date):
df = df.loc[df.index[0]:pd.Timestamp(date)]
fig, ax = plt.subplots(1, figsize=(20, 5), dpi=100)
# 训练数据
if date < pd.Timestamp(split_date):
ax.axvspan(START, date, alpha=0.5, color='#33FF92')
ax.text(pd.Timestamp('2012-01-31'), y=12, s='Train', fontsize=30)
# 测试数据
if date > pd.Timestamp(split_date):
ax.axvspan(pd.Timestamp(split_date), date, color='#F933FF')
ax.text(pd.Timestamp('2014-01-31'), y=12, s='Test', fontsize=30)
ax.plot(df.temperature, marker='o', linestyle='--',
linewidth=5, markersize=15, color='tab:orange')
max_y = round(df.temperature.max() + 5)
ax.set_title('Train/Test-Split', fontsize=30)
ax.set_xlim([START, END])
ax.set_ylim([0, max_y])
ax.set_ylabel('Temperature', color='tab:blue', fontsize=30)
创建帧,将其变化动画并保存展示:
frames = []
for date in pd.date_range(start=df.index[0],
end=df.index[-1], freq='1M'):
frame = plot_split(df, date, '2013-06-21')
frames.append(frame)
gif.save(frames, 'images/split.gif', duration=0.5*1000)
HTML('<img src="images/split.gif" />')
现在,有了前面的基础了解,我们可以对两个特征的变化趋势进行动画:
@gif.frame
def two_features_plot(df, date):
df = df.loc[df.index[0]:pd.Timestamp(date)]
fig, ax1 = plt.subplots(1, figsize=(15, 20), dpi=100)
ax1.plot(df.temperature, marker='o', linestyle='--',
linewidth=5, markersize=15, color='tab:orange')
ax1.set_ylabel('Temperature', color='tab:orange', fontsize=20)
ax2 = ax1.twinx()
ax2.plot(df.visibility, marker='o', linestyle='--',
linewidth=5, markersize=15, color='tab:blue')
ax2.set_ylabel('Visibility', color='tab:blue', fontsize=20)
plt.title('Temperature vs Visibility', fontsize=30)
# 创建动画
frames = []
for date in pd.date_range(start=df.index[0], end=df.index[-1], freq='1M'):
frame = two_features_plot(df, date)
frames.append(frame)
gif.save(frames, 'images/two_features_animation.gif', duration=0.5*1000)
HTML('<img src="images/two_features_animation.gif" />')
@gif.frame
def multi_features_plot(df, date):
df = df.loc[df.index[0]:pd.Timestamp(date)]
fig, (ax1, ax2, ax3) = plt.subplots(3, figsize=(20, 10), dpi=100)
ax1.plot(df.temperature, marker='o', linestyle='--',
linewidth=5, markersize=15, color='g')
max_y1 = round(df.temperature.max() + 5)
ax1.set_title('Multi-Features Aimation', fontsize=30)
ax1.set_xlim([START, END])
ax1.set_ylim([0, max_y1])
ax1.set_ylabel('Temperature', color='green', fontsize=15)
ax2.plot(df.visibility, marker='o', linestyle='--',
linewidth=5, markersize=15, color='r')
max_y2 = round(df.visibility.max() + 3)
ax2.set_xlim([START, END])
ax2.set_ylim([0, max_y2])
ax2.set_ylabel('Visibility', color='red', fontsize=15)
ax3.plot(df.windSpeed, marker='o', linestyle='--',
linewidth=5, markersize=15, color='b')
max_y3 = round(df.windSpeed.max() + 3)
ax3.set_xlim([START, END])
ax3.set_ylim([0, max_y3])
ax3.set_ylabel('WinSpeed', color='blue', fontsize=15)
# 创建动画
frames = []
for date in pd.date_range(start=df.index[0], end=df.index[-1], freq='1M'):
frame = multi_features_plot(df, date)
frames.append(frame)
gif.save(frames, 'images/subplots.gif', duration=0.5*1000)
HTML('<img src="images/subplots.gif" />')
如果你想给你的gif添加一点亮点,在Matplotlib中有一个小函数 plt.xkcd(),它可以让你以流行的XKCD漫画的风格进行绘图,我觉得它确实别具一格且与众不同,有的人可能会喜欢这种风格。只需要在绘图前调用这个函数即可,比如将前面添加颜色的示例转化为漫画风格:
plt.xkcd() # 使用漫画风格绘制图片
frames = []
for date in pd.date_range(start=df.index[0],
end=df.index[-1], freq='1M'):
frame = plot_split(df, date, '2013-06-21')
frames.append(frame)
gif.save(frames, 'images/comic_style_plot.gif', duration=0.5*1000)
HTML('<img src="images/comic_style_plot.gif" />')
PS:添加
plt.xkcd()函数后,我在运行上述代码过程中会提示找不到相关字体,如下所示。即使我安装了缺失的字体再次运行还是同样的提示,网上找了几种办法都没解决。不过所幸并不影响动画的生成,如果你找到了解决方法,可以留言告诉我:)。
就我个人而言,我总是喜欢在我的可视化中添加一些额外的维度。然而,重要的是要记住,数据可视化中的每个功能都应该是需要才使用,得到最佳效果。在某些情况下,过度使用可视化会让事情变得难以解释。
我希望这个惊艳的 GIF 库提供的神奇工具可以帮助您在数据分析中获得漂亮的动画。在一天结束时,某些特征可能通过动态可视化比静态图表更好理解。
但是在使用后,我发现它的缺点也很明显,就是只适合应用在小数据集上,数据量增大对于时间和空间的消耗急剧增加,所以不适合用在中大型数据集上。
实践才是巩固学习,加深印象的最佳方式,赶快通过下方领取数据行动起来吧!
示例数据获取方式:下方关注我,在公众号聊天窗口回复关键字“gif示例数据”即可领取。这里提醒一下领取资源的小伙伴,关键字一定要正确完整,否则领取不到资源,错误的关键字会自动向笔者发送私信。所以为了避免手动输入关键字不完整,建议复制指定的关键字到公众号聊天窗口回复。
如果你觉得这篇文章对你有用,请“点赞➕在看➕分享➕关注”支持我,你的点赞和关注就是我持续创作分享的动力:),同时也能让更多的朋友发现并加入我们,共同学习和进步!
Thank you for reading! Happy leaning and coding!


原文作者:数据派探险家;如有侵权,请联系管理员删除。