今天处理JSON数据格式的文件
学习书籍:《python编程 从入门到实践》
内容:下载JSON格式的交易收盘价数据,使用json模块处理。
使用Pygal模块进行对数据的可视化,探索价格变化的周期性。
1.下载数据
数据文件位于
https://raw.githubusercontent.com/muxuezi/btc/master/btc_close_2017.json
方式一:可自行下载。
方式二:使用第三方 requests模块
import requests
# 1.下载收盘价数据
json_url = 'https://raw.githubusercontent.com/muxuezi/btc/master/btc_close_2017.json'
req = requests.get(json_url)
# 将数据写入文件
with open('btc_close_2017_request.json', 'w') as f:
f.write(req.text)
file = req.json()
print(file)
说明:request模块的get()方法向GitHub服务器发送请求,GitHub服务器相应请求后,返回的结果存在req变量中。
req.text返回的是字符串。用json()方法就可以将数据转换为python列表。
json数据文件(部分):
说明:
整个是一个列表,包含很多字典。其中close表示收盘价。
2.提取数据
import json
# 获得x轴和y轴的值(提取数据)
# 将数据加载到列表中 json.load()将文件中的数据读到内存中
filename = 'btc_close_2017_request.json'
with open(filename) as f:
btc_data = json.load(f)
# 存储日期和收盘价
dates = []
months = []
weeks = []
weekdays = []
closes = []
# btc_data是列表,其中每个元素为字典 注意数据类型转换
for dict_item in btc_data:
dates.append(dict_item['date'])
months.append(int(dict_item['month']))
weeks.append(int(dict_item['week']))
weekdays.append(dict_item['weekday'])
closes.append(int(float(dict_item['close'])))
3.数据可视化1(绘制收盘价折线图)
import pygal
# 绘制交易收盘价折线图(line_chart)
# x_label_rotation=20 表示x轴上的日期标签顺时针旋转20°
# show_minor_x_labels=False 表示不用显示x轴上所有的标签(避免太拥挤)
line_chart = pygal.Line(x_label_rotation=20, show_minor_x_labels=False)
line_chart.title = '收盘价(¥)'
line_chart.x_labels = dates
line_chart.x_labels_major = dates[::20] # x轴日期每隔20天显示一次
line_chart.add('收盘价', closes)
line_chart.render_to_file('收盘价折线图.svg')
浏览器中查看结果:
时间序列分析初探
进行时间序列分析总是期望发现趋势(trend)、周期性(seasonality)和噪声(noise),从而描述事实、预测未来、做出决策。
2017年每个季度末(3月、6月、9月)似乎有一些相似的波动。也许有周期性。为了验证周期性的假设,首先将非线性的趋势消除。用到对数变换。
# 绘制收盘价对数变换折线图
import math
import pygal
line_chart = pygal.Line(x_label_rotation=20, show_minor_x_labels=False)
line_chart.title = '收盘价对数变换(¥)'
line_chart.x_labels = dates
line_chart.x_labels_major = dates[::20] # x轴日期每隔20天显示一次
# 半对数变换 消除非线性的趋势
closes_log = [math.log10(value) for value in closes]
line_chart.add('log收盘价', closes_log)
line_chart.render_to_file('收盘价对数变换折线图.svg')
从上图可以看出,收盘价似乎在每个季度表现出显著的周期性——3月、6月、9月都出现了剧烈的波动。那么12月是否会再现这一场景呢?
4.数据可视化2(绘制收盘价均值折线图)
储备知识:
1.zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同。
利用 * 号操作符,可以将元组解压为列表。
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> zipped = zip(a,b)
>>> print(zipped)
<zip object at 0x00000197DD009388>
>>> print(list(zipped))
[(1, 4), (2, 5), (3, 6)]
>>> zip(*zipped)
<zip object at 0x00000197DD052588>
>>> list(zip(*zipped))
[(1, 2, 3), (4, 5, 6)]
2.模块itertools中的groupby()函数:
3.lambda匿名函数的格式:冒号前是参数,可以有多个,用逗号隔开,冒号右边的为表达式。返回值是一个函数的地址,也就是函数对象。
>>> p = lambda x,y : x+y
>>> p
<function <lambda> at 0x00000197DD099AF8>
>>> p(2,3)
5
将绘图代码部分封装为函数draw_line():
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
绘制2017年前11个月的日均值:
'''绘制月日均值'''
# 2017年12月的数据不完整 因此只取2017年1月到11月的数据
idx_month = dates.index('2017-12-01') # 查找2017-12-01的索引位置
# 调用函数
draw_line(months[:idx_month], closes[:idx_month], '收盘价月平均值(¥)', '月日均值')
由图看出7月相比上月日均值有所下降,其他各月的日均值都是增长的。
绘制前49周(2017-01-02~2017-12-10)的日均值:
'''绘制周日均值'''
# 绘制周日均值 2017-01-02~2017-12-10
# 第一周从1月2日开始,取数时将第一天去掉
idx_week = dates.index('2017-12-11')
draw_line(weeks[1:idx_week], closes[1:idx_week], '收盘价周日均值(¥)', '周日均值')
价格与节假日无关。在各个节假日都没有出现价格低点,包括春节(第4周)、端午节(第22周)、国庆节(第40周)等。