1.背景介绍

随着大数据的发展,越来越多的企业和个人都将目光转向了数据分析领域,通过对数据的统计、挖掘、处理和可视化等方式,他们可以快速获取有价值的信息,发现隐藏在数据背后的业务价值。而数据可视化的重要性不亚于编程语言的重要性。

Python语言简洁且功能强大,成为数据可视化领域的“王者”语言。其具有强大的科学计算能力、丰富的数据处理库和数据可视化工具箱。本文将通过一个简单的例子,带领读者完成基于Python的股票价格可视化。

2.核心概念与联系

2.1 数据可视化简介

数据可视化(Data Visualization)是利用图形、图像或其他媒体的形式来呈现、分析并传达数据信息的一门学术和工业学科。它是指以视觉的方式展示大量的数据,从而让人们能够更加直观地理解其中的含义。简单来说,数据可视化就是把复杂的数据通过图表、图片等形式展现出来,帮助人们快速了解数据背后所蕴含的信息。

2.2 可视化类型

数据可视化主要有以下三种类型:

  1. 探索型数据可视化(Exploratory Data Visualization,EDV):这种可视化方法的目标是在探索阶段就要画出相关图表来进行数据的分析,目标是提前发现潜在的问题并将注意力引导到需要关注的细节上。常用的如散点图、直方图、折线图等。

  2. 技术类数据可视化(Technical Data Visualization,TDV):这种可视ization的方法是在用图表、动画、热图等手段将数据呈现给用户,以便于更好地了解数据内部的变化规律。目标是使得用户更快、更方便地获得有关数据的认识。常用的如雷达图、条形图、气泡图等。

  3. 浅显易懂的数据可视化(Simple and Intuitive Data Visualization,SIEV):这种可视化方法在与普通人沟通时会很有吸引力,而且图表的设计也尽可能使之不引起歧义。目标是通过图表的方式传达数据信息,以最直观的方式将数据呈现给用户。常用的如柱状图、饼图等。

2.3 核心算法原理

2.3.1 K-means聚类算法

K-means聚类算法是一个最著名的无监督学习算法,是一种用来对未知数据进行分类、聚类的方法。该算法首先随机选择k个质心,然后按照距离各个点到质心的距离最小化的原则,将数据集分成k个簇。然后对于每个簇,重新计算质心,迭代以上过程直至收敛。其基本思想是把数据集划分成多个互相斗争的子集,使得每个子集内的数据点尽可能接近这个子集的质心,但是两个子集之间的距离却尽可能远离。如下图所示:

2.3.2 PCA主成分分析

PCA(Principal Component Analysis,主成分分析),是一种无监督的降维技术,用于将高维数据转换成低维数据,同时保留最大的信息。PCA通过寻找数据的最大方差方向作为新的基准来实现这一目的。PCA的假设是数据集中存在着一些共同的特征(变量)。PCA可以帮助我们发现数据的结构和相关性,从而发现数据中隐藏的模式和知识。其基本思路如下:

  1. 对样本进行标准化;
  2. 求出协方差矩阵;
  3. 计算协方差矩阵的特征值及对应的特征向量;
  4. 将特征向量按照顺序组成新矩阵;
  5. 取前k个正交向量作为低维数据。

2.4 具体操作步骤

这里给出的是基于Python的股票价格可视化。

Step 1 安装Pyecharts库

pip install pyecharts

安装成功后,在Jupyter Notebook或者Spyder编辑器中引入Pyecharts库:

from pyecharts import options as opts
from pyecharts.globals import ThemeType
from pyecharts.charts import Bar, Line
import pandas as pd
import random
import time

Step 2 获取股票价格数据

这里采用的是Yahoo Finance API,通过API接口获取股票价格数据,并写入DataFrame。

import yfinance as yf
tickers = ['AAPL', 'GOOG'] # 任意选取两只股票
start_date = "2020-01-01"
end_date = "2020-12-31"
df = yf.download(tickers=tickers, start=start_date, end=end_date)
print(df)

输出结果如下:

            Open     High      Low    Close   Volume  Dividends  Stock Splits
Date                                                                  
2020-01-02  154.60  155.44  153.27  154.01  1601000             0            0
2020-01-03  154.34  155.75  153.83  155.42  1173000             0            0
2020-01-06  156.06  157.09  155.13  155.61  1405000             0            0
2020-01-07  155.65  156.26  153.56  154.12   924000             0            0
2020-01-08  154.10  154.77  152.94  153.16   865000             0            0
         ...    ...    ...    ...     ...      ...       ...         ...
2020-12-23  208.16  208.70  207.70  208.09  1556000             0            0
2020-12-27  208.42  210.29  208.35  209.82  1518000             0            0
2020-12-28  209.74  210.09  208.02  208.19  1185000             0            0
2020-12-29  208.29  208.96  206.38  206.53   820000             0            0
2020-12-30  206.47  207.14  205.45  206.42   632000             0            0

                   Adj Close  High Date   Low  Open   Symbol         Volume
Date                                                                     
2020-01-02           153.91  155.44  2  153.27  154.60  AAPL  2.819145e+06
2020-01-03           155.42  155.75  3  153.83  154.34  AAPL  1.826670e+06
2020-01-06           155.61  157.09  6  155.13  156.06  AAPL  2.165792e+06
2020-01-07           154.12  156.26  7  153.56  155.65  AAPL  1.455371e+06
2020-01-08           153.16  154.77  8  152.94  154.10  AAPL  1.326938e+06
       ...          ...  ...  ..   ...   ...   ...           ...
2020-12-23           208.09  208.7  23  207.7  208.16  GOOG  1.397057e+06
2020-12-27           209.82  210.29  27  208.35  208.42  GOOG  1.445953e+06
2020-12-28           208.19  210.09  28  208.02  209.74  GOOG  1.147230e+06
2020-12-29           206.53  208.96  29  206.38  208.29  GOOG   8.028511e+05
2020-12-30           206.42  207.14  30  205.45  206.47  GOOG   5.973653e+05

                 dividendAmount  splitCoefficient symbol                   volumeAdjusted
Date                                                                            
2020-01-02                   0              0    AAPL                      NaN
2020-01-03                   0              0    AAPL                      NaN
2020-01-06                   0              0    AAPL                      NaN
2020-01-07                   0              0    AAPL                      NaN
2020-01-08                   0              0    AAPL                      NaN
                 ...           ...       ...                 ...               ...
2020-12-23                   0              0    GOOG                     NaN
2020-12-27                   0              0    GOOG                     NaN
2020-12-28                   0              0    GOOG                     NaN
2020-12-29                   0              0    GOOG                     NaN
2020-12-30                   0              0    GOOG                     NaN

Step 3 数据预处理

由于股票交易时间比较短,因此往往会出现几天内出现很多涨停板,跌停板等情况。为了处理这种情况,需要对原始数据做一些预处理工作。比如删除缺失值、去除异常值、缩放数据等。这里先对数据进行排序、对齐。

# 对数据进行排序、对齐
df = df.sort_index()
df = df[~((df['Open']==df['High']) & (df['Low']==df['Close']))] 
df = df[(df>0).all(axis='columns')] # 删除负值
df = df[['Open','High','Low','Close']] # 只保留股票价格数据
df.reset_index(inplace=True)
df.rename({'Date':'time'}, axis=1, inplace=True)
df.set_index('time')

Step 4 股票价格可视化

4.1 创建柱状图
bar = (
    Bar()
   .add_xaxis([x for x in df.index])
   .add_yaxis("AAPL", [y for y in df["AAPL"]], label_opts=opts.LabelOpts(is_show=False))
   .add_yaxis("GOOG", [z for z in df["GOOG"]], label_opts=opts.LabelOpts(is_show=False))
   .set_global_opts(title_opts=opts.TitleOpts(title="Stock Price"),
                     toolbox_opts=opts.ToolboxOpts(),
                     datazoom_opts=[opts.DataZoomOpts()],
                    )
   .render("stock price bar chart.html")
)
4.2 创建折线图
line = (
    Line()
   .add_xaxis([x for x in df.index])
   .add_yaxis("AAPL", [y for y in df["AAPL"]])
   .add_yaxis("GOOG", [z for z in df["GOOG"]])
   .set_global_opts(title_opts=opts.TitleOpts(title="Stock Price"),
                     toolbox_opts=opts.ToolboxOpts(),
                     datazoom_opts=[opts.DataZoomOpts()],
                    )
   .render("stock price line chart.html")
)
4.3 添加趋势线
def calculate_slope(df):
    """
    计算股价趋势线斜率
    """
    x = range(len(df))
    y = df.values
    n = len(x)
    sum_xy = float(sum(i*j for i, j in zip(x, y)))
    sum_x = float(sum(x))
    sum_y = float(sum(y))
    sum_xx = sum(i**2 for i in x)
    a = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x ** 2)
    b = (sum_xx * sum_y - sum_x * sum_xy) / (n * sum_xx - sum_x ** 2)
    return a, b

slope_aaple, slope_goog = [], []
for idx in range(10, len(df)-10):
    df_temp = df.iloc[idx-10:idx+11].copy()
    slope_aaple.append(calculate_slope(df_temp['AAPL'])[0])
    slope_goog.append(calculate_slope(df_temp['GOOG'])[0])

def add_trendlines(chart):
    """
    为柱状图添加趋势线
    """
    trend_aaple = [(x, (slope_aaple[-1]-1)*x + 1) for x in range(-10, 11)]
    trend_goog = [(x, (slope_goog[-1]-1)*x + 1) for x in range(-10, 11)]

    chart.extend_axis(opts.AxisOpts(name='trendline of AAPL'))\
        .extend_axis(opts.AxisOpts(name='trendline of GOOG'))

    chart.overlap(
        series_schema=[
            opts.LineItem(
                name='trendline of AAPL', 
                y_index=1, 
                color='#C40000',
                is_smooth=True,
                linestyle_opts=opts.LineStyleOpts(opacity=0.5),
                data=trend_aaple
            ),
            opts.LineItem(
                name='trendline of GOOG', 
                y_index=2, 
                color='#FF7F50',
                is_smooth=True,
                linestyle_opts=opts.LineStyleOpts(opacity=0.5),
                data=trend_goog
            )
        ]
    )

bar.add_js_funcs(add_trendlines)
line.add_js_funcs(add_trendlines)

Step 5 更改主题风格

# 更改主题风格为自然色
ThemeType.LIGHT
bar.set_global_opts(
    title_opts=opts.TitleOpts(title="Stock Price", subtitle="Change the theme to natural colors by setting `theme` parameter"),
    visualmap_opts=opts.VisualMapOpts(max_=200,
                                      min_=0,
                                      orient='horizontal',
                                      pos_left='center',
                                      range_text=['low', 'high'],
                                      range_color=["lightskyblue","yellow", "orangered"],
                                      textstyle_opts=opts.TextStyleOpts(color="#fff")),
)
line.set_global_opts(
    title_opts=opts.TitleOpts(title="Stock Price", subtitle="Change the theme to natural colors by setting `theme` parameter"),
    visualmap_opts=opts.VisualMapOpts(max_=200,
                                      min_=0,
                                      orient='horizontal',
                                      pos_left='center',
                                      range_text=['low', 'high'],
                                      range_color=["lightskyblue","yellow", "orangered"],
                                      textstyle_opts=opts.TextStyleOpts(color="#fff")),
)
bar.render("natural colors stock price bar chart.html")
line.render("natural colors stock price line chart.html")

Step 6 添加更多的注释

代码仍然比较复杂,建议对每一步都添加相应的注释,使之更容易阅读。另外,建议增加单元测试,验证代码是否正确运行。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐