“数”览十年黄金周:数据指标选择,与Python动态图表绘制

    科技2022-07-13  128

    全文总览:

    数据是会骗人的,比起绝对数字,比率更适合作为数据指标央视新闻报道中使用了炫酷的动态条形图,展现十年黄金周出行人数和旅游收入的变化,看着每年都在3. 增长,但是情况是否真的变好?使用Python,计算年增长率,使用matplotlib和seaborn库,绘制超级炫酷的动态线形图

    前言:

    十月一号,央视新闻网发布了一篇报道:《“数”览近十年国庆黄金周!今年“十一”超长假期有这些变化》。

    报道中,用两张动态图表,展现了近十年来的黄金周全国接待旅客数量与收入的变化情

    首先,读一下这两个图表的内容。

    从两张图中可以看出:

    近十年来国内黄金周的旅游人数和收入的绝对值均不断上升; 其中,2012年不论是旅游人数还是旅游收入,相对于2011年均有大幅度上升。2015年旅游人数的上升幅度,看起来没有旅游收入的上升幅度大,或表示2015年,民众的旅行消费升级。

    提出问题:只看数字在变大,真的对吗?

    从这个案例来说,看动态条形图,每一年的柱子都比上一年高,但是具体高多少?不知道。近几年的增长,是否能跟过去几年的增长比?如果不能,是什么原因?有些年份的旅游人数增长,但是旅游收入是否实现同步增长?因为,收入、挣钱才是关键啊!

    显然,想要更确切的看出每年的增长情况,单看绝对数量,是不太明显的。

    此时,需要计算一下每年的增长率指标:

    增长率指标计算公式:

    用Python进行指标计算,和绘制动态折线图:

    按照国际惯例,先上结果: 以下代码,以绘制十年内旅行人数增长率变化为例,最终输出上面这个gif图。

    1 导入所需库

    import numpy as np import pandas as pd import seaborn as sns import matplotlib import matplotlib.pyplot as plt import matplotlib.animation as ani

    实际中,使用matplotlib和seaborn就已经足够绘制出很漂亮的静态图表。

    想要让图片动起来,使用matplotlib中的ainmation对象,配合构建的动态函数,就可以让图表动起来。还可以保存成gif、mp4等多种格式。

    2 导入数据,计算增长率指标

    # 原始数据 year = np.array([i for i in range(2010, 2020)]) revenue_list = [1166, 1458, 2105, 2233, 2453, 4213, 4822, 5836, 5990.8, 6497.1] number_list = [2.54, 3.02, 4.25, 4.28, 4.75, 5.26, 5.93, 7.05, 7.26, 7.82]

    数据比较少,所以直接敲成列表。

    year是年份;revenue_list是旅游年收入(亿元);number_list是年旅行人数(亿/人次)

    # 计算增长率,保存为numpy列格式 def cal_rate(cal_list): list_c = [0] # 临时列表的第一个元素,即2010年,定为0 for i in range(len(cal_list)-1): list_c.append((cal_list[i+1]-cal_list[i])/cal_list[i]) return np.array(list_c) num_growth_rate = cal_rate(number_list) #定义一个用于往原始列表中,增加元素的函数 # 没有这个函数,保存的gif图片变化就会比较大 def augment(xold, yold, numsteps): xnew = [] ynew = [] for i in range(len(xold)-1): difx = xold[i+1] - xold[i] stepsX = difx/numsteps dify = yold[i+1] - yold[i] stepsY = dify/numsteps for s in range(numsteps): xnew = np.append(xnew, xold[i]+s*stepsX) ynew = np.append(ynew, yold[i]+s*stepsY) return xnew, ynew # numsteps=10,表示在原本列表的每两个数字之间,增加9个数字 # 原本长度为10的列表,最后变成100 # 相应的,最后生成动态图表的时候,迭代次数,frames变量要设置为100帧。 year_new, num_growth_new = augment(year, num_growth_rate, 10) num_df = pd.DataFrame(num_growth_new, year_new) num_df.columns = {'num_growth'}

    3 定义画布参数:

    fig, ax = plt.subplots(figsize=(10, 6)) plt.xlim((2009, 2020)) plt.ylim((0, 0.45)) plt.xlabel('Year', fontsize=10) plt.ylabel('Number of Tourists', fontsize=10) plt.title('Number of Tourist in Golden Week for the Pass Ten Years', fontsize=14)

    这里似乎没有什么可说的,就正常的绘图参数。

    第一行,定义画布大小,坐标轴名称为ax; 第二、三行,分别定义横纵坐标的标签范围。 第四、五行,定义横纵坐标的名称和字体大小 最后,title,定义图标的名称和字体大小。

    4 构建动画函数并调用绘图

    # 构建动画函数 def animate(i): data = num_df.iloc[:int(i+1)] sns.lineplot(x=data.index, y=data['num_growth'], data=data, color='r', ax=ax, linewidth=5) j = int(i) // 10 if isinstance(j, int): ax.text(year[j], num_growth_rate[j], str(round(num_growth_rate[j]*100, 2))+'%', color='black', fontsize=10, ha='center', va='bottom') animator = matplotlib.animation.FuncAnimation(fig, animate, frames=100, repeat=True) animator.save('number_of_t.gif') # plt.show()

    接下来,按照每一行说什么来讲解一下:

    animator = matplotlib.animation.FuncAnimation(fig, animate, frames=100, repeat=True)

    这一行代码,是将绘制动画的matplotlib对象实例化为animator。方便接下来进行保存等操作。

    其中frames=100,表示迭代100次,也就是animate(i)中的i=100,函数会迭代100次。

    repeat=True,意味着如果使用plt.show(),那么动图会自动循环播放。

    接下来讲解animate函数中的代码:

    def animate(i): data = num_df.iloc[:int(i+1)] sns.lineplot(x=data.index, y=data['num_growth'], data=data, color='r', ax=ax, linewidth=5) j = int(i) // 10 if isinstance(j, int): ax.text(year[j], num_growth_rate[j], str(round(num_growth_rate[j]*100, 2))+'%', color='black', fontsize=10, ha='center', va='bottom') 提取绘图数据——data,每次都提取num_df表中的前i+1行数据,用于绘图。 这样,看起来才有一点点画出来的感觉。使用seaborn绘制线型图。没有什么好说的。重点是数据标签的绘制。我希望达到的感觉是,数据走到了那个点上,正好,标签也打上去。 定义了一个变量j,要使用地板除法,只取整数的部分。如果地板除法的结果是整数,那就正好是原本的增长率,而不是我们之前为了平滑图片增加的其他数据。 animator.save('number_of_t.gif') # plt.show()

    最后,将animator对象保存为gif图片。

    或者,注意是“或者”,只能二选一哦,如果用plt.show(),那么就要将save备注起来。

    用同样的方法,将旅游人数的数据,改为旅游收入的数据,就可以得到十年来黄金周旅游收入增长率变化图。

    最后,对绘图函数做了一下改装:

    def line_plot(df, type_list, ylabel, title): # 定义画布参数: fig, ax = plt.subplots(figsize=(10, 6)) plt.xlim((2009, 2020)) plt.ylim((0, max(df[ylabel])+0.1)) plt.xlabel('Year', fontsize=10) plt.ylabel(ylabel, fontsize=10) plt.title(title, fontsize=14) # 构建动画函数 def animate(i): data = df.iloc[:int(i+1)] sns.lineplot(x=data.index, y=data[ylabel], data=data, color='r', ax=ax, linewidth=5) j = int(i) // 10 if isinstance(j, int): ax.text(year[j], type_list[j], str(round(type_list[j]*100, 2))+'%', color='black', fontsize=10, ha='center', va='bottom') animator = matplotlib.animation.FuncAnimation(fig, animate, frames=100, repeat=True) animator.save(ylabel+'.gif') # plt.show() # 绘制旅行人数数量增长率变化: line_plot(num_df, num_growth_rate, 'num_growth_rate', 'Growth Rate of Tourist Numbers in Golden Week for the Pass Ten Years') # 绘制旅行收入增长率变化: line_plot(rev_df, rev_growth_rate, 'rev_growth_rate', 'Growth Rate of Tourist Income in Golden Week for the Pass Ten Years')

    将整个绘图过程封装成为line_plot函数,传入数据表、数据列,y轴标签和表名称,三个变量,生成相应的动态图表。

    最终生成的结果如下:

    简单分析:

    为了更直观的看出变化,人数与增长率的数据贴出来: 结合上面绘制的动图进行分析:

    2012年,相比2011年,不论是出行人数还是旅游收入,均有大幅度上升。人数增长和收入增长的幅度持平。约为40%多。2013年,相比于2012年,虽然出行人数增长率仅为0.70%, 但是旅游收入的增长率却增加了6.1%。重点在于2015年,相比于2014年,出行人数增长10.7%,而旅游收入却大幅度增长,增长了71.8%。前文提到,2015年旅行消费升级,此处验证了这一点。接下来,民众在黄金周的出行和消费均呈现同步增长。2016-2017年,增长幅度较大,2018年增长幅度大幅降低,2019年,稍微恢复增长。

    简单说一说数据分析指标选取——为什么非要计算增长率?

    这里,还是要借鉴《精益数据分析》的指标判定方法。

    什么才是好的数据指标:

    1. 简单易懂 2. 最好是一个比率

    原因如下:

    **比率的可操控性强,显示的是一种行动状态。**比如,案例中40%的增长率,对比与其他,可以发现处在一个快速上升状态。比率是天生的比较指标。每一年的增长率进行比较,就知道下一次,要保持在一个什么样的增长才算合理。**比率,还适用于比较因素之间的正相关和负相关性。**比如,本例中,出行人数与收入的增长幅度并不匹配,这时候就可以猜测是发生了什么情况。 在本案例中,只看数量变化,有一种粉饰太平的感觉。

    计算增长率之后,发现2018年以来,不论是出行人数还是旅游收入,增长率都比如以往年份。

    这可能是2015之后,旅行消费升级的弊端开始显现。十一黄金周的旅行消费升级,是不是仅仅价格上涨了,而服务各方面都没有配套上涨,因而开始导致游客对旅行质量感到不满呢?

    对于这个问题,当前的数据就没有办法进行预测。还需要搜集其他数据来验证想法。

    这就超出了这篇文章的范畴,暂时先不去套路了! 码字不易!!

    如果您能看到这里,动动手

    点赞、关注、转发一下吧!

    Processed: 0.012, SQL: 8