python应用篇之数据可视化 您所在的位置:网站首页 python把数字转为字符串 python应用篇之数据可视化

python应用篇之数据可视化

2023-05-15 14:01| 来源: 网络整理| 查看: 265

前言

上篇文章主要给大家介绍了从网上下载的CSV数据,主要包括CSV文件在Python中的相关分析、读取数据、绘制相应的图表、以及在图表中加入日期、给绘图表区域着色以及相应缺失数据的处理。接下来本文给大家介绍的是另一个数据表示格式——Json格式。

1、下载收盘价数据

我们首先要做的就是首先把该json文件下载下来,该文件是来自于《Python编程从入门到实战》中,因此,下载下来就可以了。下载的文件如下:

具体该json文件的内容如下:

我们从上图中的可以得知该文件其实就是一个很长的Python列表,其中每一个元素都是一个字典,其中包含了五个键值对,分别是统计日期、月份、周数、周几以及收盘价。由于2017年1月1日是周日,作为2017年的第一周实在太短,因此将其计入2016年的第52周。于是2017年的第一周是从2017年1月2日(周一)开始的。如果用函数urlopen来下载数据,具体实现的代码如下:

from __future__ import (absolute_import, division, print_function, unicode_literals) try: # python 2.x版本、 from urllib2 import urlopen except ImportError: # python3.x版本 from urllib.request import urlopen import json json_url = 'https://raw.githubusercontent.com/muxuezi/btc/master/btc_close_2017.json' respose = urlopen(json_url) # 读取数据 req = respose.read() # 将数据写入文件 with open('btc_close_2017_urllib.json', 'wb') as f: f.write(req) # 加载json格式 file_urllib = json.loads(req) print(file_urllib)

但是很遗憾,代码没错,就是打不开这个网址,最近访问不了github。不过,我们本地有,因此,下载不下来也没关系,其实这就是Python爬虫的一小部分。尽管下载不下来,还是给大家详细介绍一下代码的实现过程;

我们首先导入下载文件使用的模块。这里我们用了python中的try/except语句实现兼容Python2.x和Python3.x的方式;如果用Python2.x版本运行代码,from urllib2 import urlopen代码就会执行;如果用Python3.x版本运行代码,由于没有urllib2模块,解释器就会触发ImportError,因此from urllib.request import urlopen代码就会执行,总之,我们确定都会将urlopen函数导入。

然后导入模块json,以便之后能够正确地加载文件中的数据。我们的btc_close_2017.json文件在github上,因此,如果我们在pycharm上报错了,有可能不是我们代码问题,是我们的网址本来就在百度中打不开,因此,很正常的在爬虫中拉不下来数据。urlopen(json_url)是将json_url网址传入到urlopen函数。这些代码执行后,Python就会向github的服务器发送请求。github服务器响应请求后把这个文件数据保存到我们指定的文件夹中。最后我们用函数json.load()将文件内容转换为Python能够处理的格式,与前面直接下载的文件内容一致。

函数urlopen的代码稍微复杂一些,第三方模块requests封装了许多常用的方法,让数据下载和读取方式变得非常简单,具体实现如下:

import requests json_url = 'https://raw.githubusercontent.com/muxuezi/btc/master/btc_close_2017.json' req = requests.get(json_url) # 将数据写入文件 with open('btc_close_2017_requests.json', 'wb') as f: f.write(req.txt) # 加载json格式 file_requests = req.json() print(file_requests)

requests通过get方法向GitHub服务器发送请求。github服务器响应请求后,返回的结果存储在req变量中。req.txt属性可以直接读取文件数据,返回格式是字符串,可以和与前面的文件内容是一致的,虽然,这次也是不出意外的报错了,但是我们有本地的数据,这个代码一定是没有问题的。

2、提取相关的数据

我们将数据下载到本地后,也了解了文件的内容以及相应的格式,接下来我们需要做的就是通过代码将btc_close_2017.json文件中的相关信息提取出来,具体实现如下:

import json # 将数据加载到一个列表中 filename = 'btc_close_2017.json' with open(filename) as f: btc_data = json.load(f) # 打印每一天信息 for btc_dict in btc_data: date = btc_dict['date'] month = btc_dict['month'] week = btc_dict['week'] weekday = btc_dict['weekday'] close = btc_dict['close'] print("{} is month{} week {}, {}, the close price is {} RMB".format(date, month, week, weekday, close))

首先导入模块json,然后将数据存储在btc_data中,另外,我们遍历了btc_date中的每个元素。每一个元素都是字典,并且这个字典包含了五个键值对,btc_dict就用来存储字典中每个键值对。之后就可以取出所有键的值,并将日期、月份、周数、周几和收盘价相关联的值分别到date、month、weekday与close中。接下来,打印每一天的日期、月份、周数、周几和收盘价。具体的输出结果如下:

现在,我们已经掌握了json读取数据的方法。下面,让我们将数据转换为Pygal能够处理的格式。

3、将字符串转换为数字值

btc_close_2017.json中的每个键和值都是字符串。为了能在后面的内容中对交易数据进行计算,需要先将表示周数和收盘价的字符串转换为数值。因此,我们使用函数int(),具体的实现如下:

import json # 将数据加载到一个列表中 filename = 'btc_close_2017.json' with open(filename) as f: btc_data = json.load(f) # 打印每一天信息 for btc_dict in btc_data: date = btc_dict['date'] month = int(btc_dict['month']) week = int(btc_dict['week']) weekday = btc_dict['weekday'] close = int(btc_dict['close']) print("{} is month{} week {}, {}, the close price is {} RMB".format(date, month, week, weekday, close))

我们将week的数值转换成了整数格式。将收盘价close转换为整数时,出现了ValueError异常,具体结果如下:

我们在实际的工作中,原始数据的格式是不统一的,此类数值类型转换造成的ValueError异常十分普遍的错误。主要出错的原因在于Python不能直接将在包含小数点的字符串‘6928.6492’转换为整数。为了消除这种错误,需要先将字符串转换为’浮点数(float)’,再将浮点数转换为整数(int),具体实现如下:

import json # 将数据加载到一个列表中 filename = 'btc_close_2017.json' with open(filename) as f: btc_data = json.load(f) # 打印每一天信息 for btc_dict in btc_data: date = btc_dict['date'] month = int(btc_dict['month']) week = int(btc_dict['week']) weekday = btc_dict['weekday'] close = int(float(btc_dict['close'])) print("{} is month{} week {}, {}, the close price is {} RMB".format(date, month, week, weekday, close))

我们首先用函数float()将字符串转换为小数,然后再用函数int()去掉小数部分(截尾取整),返回整数部分。现在,再次运行代码,就不会出现异常了。打印出的收盘价信息如下:

现在,收盘价都已经成功地从字符串转换成浮点数,再从浮点数转换成了整数。另外,我们还发现,月份中原来1~9月份前面的数字0在转换成整数之后就消失了,周数的数据也根据我们的需求转换成了整数。有了这些整数之后,可以结合Pygal的可视化功能来探索一些有趣的信息。

4、绘制收盘价折线图

在前面的文章我们曾经介绍过用pygal绘制条形图(bar chart)d的方法,也介绍了用matplotlib绘制折线图(line chart)的方法。接下来,我们介绍用pygal来绘制收盘价的折线图。 在绘制折线图之前,需获取x轴与y轴数据,因此,我们创建了几个列表来存储数据。遍历btc_data,将转换为适当格式的数据存储到对应的列表中。我们需要对前面的代码进行一些微调,具体实现如下:

import json import pygal # 将数据加载到一个列表中 filename = 'btc_close_2017.json' with open(filename) as f: btc_data = json.load(f) # 创建5个列表,分别在存储日期和收盘价 dates = [] months = [] weeks = [] weekdays = [] close = [] # 打印每一天信息 for btc_dict in btc_data: dates.append(btc_dict['date']) months.append(int(btc_dict['month'])) weeks.append(int(btc_dict['week'])) weekdays.append(btc_dict['weekday']) close.append(int(float(btc_dict['close']))) line_chart = pygal.Line(x_label_rotation=20, show_minor_x_labels=False) line_chart.title = '收盘价(¥)' line_chart.x_labels = dates N = 20 # x轴坐标每隔20天显示一次 line_chart._x_labels_major = dates[::N] line_chart.add('收盘价', close) line_chart.render_to_file('收盘价折线图(¥).svg')

首先我们先是用代码实现了对x轴和y轴的数据,就可以绘制折线图。考虑到该文件的数据是比较多的,x轴要显示346个日期,在有限的屏幕下会显得十分拥挤。因此,我们需要利用pygal的配置参数,对图形进行了适当的调整。我们首先就是导入了pygal模块,然后在创建了Line实例,并且分别设置了x_label_rotation与show_minor_x_labels作为初始化参数。x_label_rotation=20让x轴上的日期标签顺时针旋转20°。show_minor_x_labels=False则告诉图形不用显示所有的x轴标签。设置了图形的标签和x轴标签之后,我们配置了x_labels_major属性,让x轴坐标每隔20天显示一次,这样x轴就不会显得非常拥挤了,最终运行的结果如下:

我们从图中可以看出,价格从2017年11月12日到2017年12月12日快速增长,平均每天增值约2500元人民币,图中折线简直就像火箭发射一般,垂直升空。接下来,我们对价格做一些简单的探讨;

5、时间序列特征初探

进行时间序列分析总是期望发现趋势(trend)、周期性(seasonality)、和噪声(noise),从而能够进行描述事实、预测未来、做出决策。从收盘价的折线图可以看出,2017年的总体趋势是非线性的,而且增长幅度不断增大,似乎呈指数分布。但是我们发现,在每个季度末(3月、6月和9月)似乎有一些相似的波动。尽管这些波动被增长的趋势掩盖了,不过其中也许有周期性。为了验证周期性的假设,需要首先将非线性的趋势消除。对数变换是常用的处理方法之一。让我们用Python标准库的数学模块math来解决这个问题。math里面有很多常用的数学函数,这里用以10为底的对数函数math.log10计算收盘价,日期仍然保持不变。这种方法称为半对数变换,具体实现如下:

import json import pygal import math # 将数据加载到一个列表中 filename = 'btc_close_2017.json' with open(filename) as f: btc_data = json.load(f) # 创建5个列表,分别在存储日期和收盘价 dates = [] months = [] weeks = [] weekdays = [] close = [] # 打印每一天信息 for btc_dict in btc_data: dates.append(btc_dict['date']) months.append(int(btc_dict['month'])) weeks.append(int(btc_dict['week'])) weekdays.append(btc_dict['weekday']) close.append(int(float(btc_dict['close']))) line_chart = pygal.Line(x_label_rotation=20, show_minor_x_labels=False) line_chart.title = '收盘价对数变换(¥)' line_chart.x_labels = dates N = 20 # x轴坐标每隔20天显示一次 line_chart._x_labels_major = dates[::N] close_log = [math.log10(_)for _ in close] line_chart.add('log收盘价', close_log) line_chart.render_to_file('收盘价折线图(¥).svg')

现在,用对数变换剔除非线性趋势之后,整体上涨的趋势更接近线性增长。从上图中可以清晰地看出,收盘价在每个季度末似乎有显著的周期性——3月、6月、9月都出现了剧烈的波动。那么12月份是不是会出现这一场景呢?下面是再看看收盘价的月日均值与周日均值的表现:

6、收盘价均值

下面在利用btc_close_2017.json文件中的数据,绘制2017年前11个月的日均值、前49周(2017-01-02~2017-12-10)的日均值,以及每周中各天的日均值。虽然这些日均值的数值不同,但是都是一段时间的均值,计算方法是一样的。因此,可以将之前的绘图代码封装成函数,以便重复使用。具体实现如下:

import json import pygal import math # 将数据加载到一个列表中 filename = 'btc_close_2017.json' with open(filename) as f: btc_data = json.load(f) # 创建5个列表,分别在存储日期和收盘价 dates = [] months = [] weeks = [] weekdays = [] close = [] # 打印每一天信息 for btc_dict in btc_data: dates.append(btc_dict['date']) months.append(int(btc_dict['month'])) weeks.append(int(btc_dict['week'])) weekdays.append(btc_dict['weekday']) close.append(int(float(btc_dict['close']))) line_chart = pygal.Line(x_label_rotation=20, show_minor_x_labels=False) line_chart.title = '收盘价对数变换(¥)' line_chart.x_labels = dates N = 20 # x轴坐标每隔20天显示一次 line_chart.x_labels_major = dates[::N] close_log = [math.log10(_) for _ in close] # ① line_chart.add('log收盘价', close_log) line_chart.render_to_file('收盘价对数变换折线图(¥).svg') from itertools import groupby def draw_line(x_data, y_data, title, y_legend): xy_map = [] for x, y in groupby(sorted(zip(x_data, y_data)), key=lambda _:_[0]): y_list = [v for _, v in y] xy_map.append([x, sum(y_list) / len(y_list)]) x_unique, y_mean = [*zip(*xy_map)] line_chart = pygal.Line() line_chart.title = title line_chart.x_labels = x_unique line_chart.add(y_legend, y_mean) line_chart.render_to_file(title + '.svg') return line_chart idx_month = dates.index('2017-12-01') line_chart_month = draw_line(months[:idx_month], close[:idx_month], '收盘价月日均值(¥)', '月日均值') line_chart_month

由于需要将数据按月份、周数、周几分组,再计算每组的均值,因此我们导入Python的标准库中模块itertools函数groupby。然后将x轴与y轴的数据合并、排序,然后在用函数groupby分组。分组之后,求出每组的均值,存储到xy_map变量中。最后,将xxy_map中存储的x轴与y轴数据分离,就可以像之前那样用pygal画图了。接着,我们画出收盘价月日均值。由于2017年12月的数据并不完整。我们只取2017年1月到11月的数据。通过datas查找2017-12-01的索引位置,确定周数和收盘价的取数范围,具体执行的结果如下:

从图示可以看出,除了7月相比上个月有所下降,其他个月都是增长的。11月相比10月的增幅非常惊人,月日增长了45%。

下面来绘制前49周(2017-01-02~2017-12-10)的日均值。2017年1月1日是周日。归属为2016年第52周,因此,2017年的第一周从2017年1月2日开始,取数时需要将第一天去掉。另外,2017年第49周周日是2017年12月10日,因此,我们通过dates查找2017-12-11的索引位置,确定周数和收盘价的取数范围,具体实现如下:

import json import pygal import math # 将数据加载到一个列表中 filename = 'btc_close_2017.json' with open(filename) as f: btc_data = json.load(f) # 创建5个列表,分别在存储日期和收盘价 dates = [] months = [] weeks = [] weekdays = [] close = [] # 打印每一天信息 for btc_dict in btc_data: dates.append(btc_dict['date']) months.append(int(btc_dict['month'])) weeks.append(int(btc_dict['week'])) weekdays.append(btc_dict['weekday']) close.append(int(float(btc_dict['close']))) line_chart = pygal.Line(x_label_rotation=20, show_minor_x_labels=False) line_chart.title = '收盘价对数变换(¥)' line_chart.x_labels = dates N = 20 # x轴坐标每隔20天显示一次 line_chart.x_labels_major = dates[::N] close_log = [math.log10(_) for _ in close] # ① line_chart.add('log收盘价', close_log) line_chart.render_to_file('收盘价对数变换折线图(¥).svg') from itertools import groupby def draw_line(x_data, y_data, title, y_legend): xy_map = [] for x, y in groupby(sorted(zip(x_data, y_data)), key=lambda _:_[0]): y_list = [v for _, v in y] xy_map.append([x, sum(y_list) / len(y_list)]) x_unique, y_mean = [*zip(*xy_map)] line_chart = pygal.Line() line_chart.title = title line_chart.x_labels = x_unique line_chart.add(y_legend, y_mean) line_chart.render_to_file(title + '.svg') return line_chart idx_week = dates.index('2017-12-11') line_chart_week = draw_line(weeks[1:idx_week], close[:idx_week], '收盘价周日均值(¥)', '周日均值') line_chart_week

收盘价周日运行结果如下所示:

从上图可以看出,价格与节假日无关。在2017年的各个节假日都没有出现价格低点,包括春节(第四周)、清明节(第14周)、劳动节(第18周)、端午节(第22周)、国庆节(第40周)。最后绘制了每周中各天的均值。为了使用完整的时间段,还像前面那样取前49周(2017-01-02~2017-12-10)的数据,同样通过dates查找2017-12-11的索引位置,确定周数和收盘价的取数范围。但是由于这里的周几是字符串,按周一到周日的顺序排列,而不是按单词首字母的顺序,绘图时x轴标签的顺序不会有问题。另外,原来的周几都是英文单词,还可以将其调整为中文,因此,需要对前面的程序做一些特殊处理,具体实现如下:

import json import pygal import math # 将数据加载到一个列表中 filename = 'btc_close_2017.json' with open(filename) as f: btc_data = json.load(f) # 创建5个列表,分别在存储日期和收盘价 dates = [] months = [] weeks = [] weekdays = [] close = [] # 打印每一天信息 for btc_dict in btc_data: dates.append(btc_dict['date']) months.append(int(btc_dict['month'])) weeks.append(int(btc_dict['week'])) weekdays.append(btc_dict['weekday']) close.append(int(float(btc_dict['close']))) line_chart = pygal.Line(x_label_rotation=20, show_minor_x_labels=False) line_chart.title = '收盘价对数变换(¥)' line_chart.x_labels = dates N = 20 # x轴坐标每隔20天显示一次 line_chart.x_labels_major = dates[::N] close_log = [math.log10(_) for _ in close] # ① line_chart.add('log收盘价', close_log) line_chart.render_to_file('收盘价对数变换折线图(¥).svg') from itertools import groupby def draw_line(x_data, y_data, title, y_legend): xy_map = [] for x, y in groupby(sorted(zip(x_data, y_data)), key=lambda _:_[0]): y_list = [v for _, v in y] xy_map.append([x, sum(y_list) / len(y_list)]) x_unique, y_mean = [*zip(*xy_map)] line_chart = pygal.Line() line_chart.title = title line_chart.x_labels = x_unique line_chart.add(y_legend, y_mean) line_chart.render_to_file(title + '.svg') return line_chart idx_week = dates.index('2017-12-11') wd = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] weekdays_int = [wd.index(w) + 1 for w in weekdays[1:idx_week]] line_chart_weekday = draw_line(weekdays_int, close[1:idx_week], '收盘价星期均值(¥)', '星期均值') line_chart_weekday.x_labels = ['周一','周二','周三','周四','周五','周六','周日'] line_chart_weekday.render_to_file('收盘价星期均值(¥).svg')

首先,我们列出一周七天的英文单词,然后将weekdays的内容替换成1~7的整数。这样函数draw_line在处理数据时按周几的顺序排列,就会将周一放在列表的第一位,周日放在列表的第七位。图形生成之后,再将图形的x轴标签替换成中文,最终输出的图形如下:

通过上图我们可以看出,比特币收盘价在周一最低,周日最高。周一到周四快速提升,周四是拐点,周五和周四基本持平(其实略低于周四),之后增速放慢。

7、收盘价数据仪表盘

前面已经为交易收盘价绘制了五福图,分别是收盘价对数变换、收盘价月日均值、收盘价周日均值、收盘价星期均值。每个SVG文件打开之后都是独立的页面。如果能够将它们整合在一起,就可以很方便地进行长期管理、监测分析。另外,新的图表也可以十分方便地加入进来,这样就形成了一个数据仪表盘。下面将前面绘制的图整合起来,做一个收盘价数据仪表盘,具体实现如下:

import json import pygal import math # 将数据加载到一个列表中 filename = 'btc_close_2017.json' with open(filename) as f: btc_data = json.load(f) # 创建5个列表,分别在存储日期和收盘价 dates = [] months = [] weeks = [] weekdays = [] close = [] # 打印每一天信息 for btc_dict in btc_data: dates.append(btc_dict['date']) months.append(int(btc_dict['month'])) weeks.append(int(btc_dict['week'])) weekdays.append(btc_dict['weekday']) close.append(int(float(btc_dict['close']))) line_chart = pygal.Line(x_label_rotation=20, show_minor_x_labels=False) line_chart.title = '收盘价对数变换(¥)' line_chart.x_labels = dates N = 20 # x轴坐标每隔20天显示一次 line_chart.x_labels_major = dates[::N] close_log = [math.log10(_) for _ in close] # ① line_chart.add('log收盘价', close_log) line_chart.render_to_file('收盘价对数变换折线图(¥).svg') from itertools import groupby def draw_line(x_data, y_data, title, y_legend): xy_map = [] for x, y in groupby(sorted(zip(x_data, y_data)), key=lambda _:_[0]): y_list = [v for _, v in y] xy_map.append([x, sum(y_list) / len(y_list)]) x_unique, y_mean = [*zip(*xy_map)] line_chart = pygal.Line() line_chart.title = title line_chart.x_labels = x_unique line_chart.add(y_legend, y_mean) line_chart.render_to_file(title + '.svg') return line_chart idx_week = dates.index('2017-12-11') wd = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] weekdays_int = [wd.index(w) + 1 for w in weekdays[1:idx_week]] line_chart_weekday = draw_line(weekdays_int, close[1:idx_week], '收盘价星期均值(¥)', '星期均值') line_chart_weekday.x_labels = ['周一','周二','周三','周四','周五','周六','周日'] line_chart_weekday.render_to_file('收盘价星期均值(¥).svg') line_chart_weekday with open('收盘价Dashboard.html', 'w', encoding='utf8') as html_file: html_file.write( '收盘价Dashboard\n') for svg in [ '收盘价折线图(¥).svg', '收盘价对数变换折线图(¥).svg', '收盘价月日均值(¥).svg', '收盘价周日均值(¥).svg', '收盘价星期均值(¥).svg' ]: html_file.write( ' \n'.format(svg)) # 1 html_file.write('')

与常见网络应用的数据仪表盘一样,我们的数据仪表也是一个完整的网页(HTML文件)。首先创建了一个名为收盘价Dashboard.html网页文件,然后将每幅图都添加到页面中。这里设置SVG图形的默认高度为500像素,由于SVG是矢量图,可以任意缩放且不失真,因此可以通过放大或缩小网页来调整视觉效果,最终的运行结果如下:

关于交易收盘价的分析就介绍到这里,内容非常粗糙,极不严谨,仅作为Python处理JSON文件格式的示例使用。数据背后的故事往往是非常复杂的,即精通数据分析的技巧,也未必能预见未来。在数据分析过程中,这些修炼都是必不可少的。

总结

上篇文章主要给大家介绍了从网上下载的CSV数据,主要包括CSV文件在Python中的相关分析、读取数据、绘制相应的图表、以及在图表中加入日期、给绘图表区域着色以及相应缺失数据的处理。本文给大家介绍了处理数据的另一种形式——json格式的处理,主要包括数据的下载、提取相应的数据、将数据转换成相应的格式、绘制收盘分析折线图、以及进一步对我们的数据进行相应的分析,最后通过收盘价数据仪表盘。Python是一门注重实际操作的语言,它是众多编程语言中最简单,也是最好入门的。当你把这门语言学会了,再去学习java、go以及C语言就比较简单了。当然,Python也是一门热门语言,对于人工智能的实现有着很大的帮助,因此,值得大家花时间去学习。生命不息,奋斗不止,我们每天努力,好好学习,不断提高自己的能力,相信自己一定会学有所获。加油!!!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有