《python编程从入门到实践》的第16章的16.2.6 收盘价均值有一些错误,而且不像之前一样有详细明了的讲解,根据自己的学习情况,跟大家分享一下我对这个程序的理解。
先上代码:
import pygal
import json
import math
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
filename = 'btc_close_2017_request.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))
dates, months, weeks, weekdays, closes = [], [], [], [], []
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'])
closes.append(int(float(btc_dict['close'])))
idx_month = dates.index('2017-12-01')
line_chart_month = draw_line(months[:idx_month], closes[:idx_month], '收盘价月日均值', '月日均值')
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 closes]
line_chart.add('log收盘价', close_log)
line_chart.render_to_file('收盘对数变换价折线图¥.svg')
这是制作交易收盘价走势图:JSON格式这一节 16.2.6以前所有的代码,由于之前的代码较为简单,而且作者讲解详细,所以我这里就只跟大家说一下平均值这里的代码。
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], closes[:idx_month], '收盘价月日均值', '月日均值')
首先让集合了所有日期的列表dates用index方法取2017-12-01这一天的索引,并将其赋给idx_month,之后months[:idx_month], closes[:idx_month]表示分别对日期列表mongths,收盘价列表closes进行切片处理,取到了索引从0到idx_months的所有值,也就是2017-12-01这一天之前的所有日期,以及对应的收盘价,并将其和另外两个实参传递到函数draw_line中。
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)])
1.调用函数后,首先定义一个空列表勇于储存,for循环条件中,zip(x_data, y_data)表示将传入的日期列表months和收盘价列表closes,分别按顺序各取一个元素打包成元组列表组合成一个新的迭代器——zip类,即[(1,6928), (1,7070) …… (11,65583)],紧接着第二层的sorted函数对元组列表进行排序,得到了按照月份从小到大,同一月份的收盘价从小到大排序的元组列表[(1, 5383), (1,5566) …… (1,6928), (1,7070) …… (11,65583)]。第三层的groupby函数,是一个分组聚合函数,key=lambda _: _[0]是用匿名函数Lambda(Lambda表达式基于数学中的λ演算得名)表示的条件。
lambda函数:
语法为
lambda argument_list: expression
表示将传入的参数列表argument_list按照表达式expression进行运算,并将结果返回
其中,argument_list是参数列表,其形式多样,可以传递一个参数,也可以传递两个参数,还可以不传递参数;expression是一个表达式,表达式中出现的参数需要在argument_list中有定义,而且必须是单行。
因此,key=lambda _: _[0]就表示取列表中索引为[0]的值,并将返回值赋给key(下划线表示临时变量,仅用一次之后销毁,这里指代),key这个表达式表示groupby分组的依据,意味着按照元组列表的第一个元素进行分类。每循环一次,得到一组数据,x就是分类的key值。最后循环十一次,x=1~11,y则是对应的元组列表,得到:
1 [(1,5383), (1,5566) …… (1,7835)]
2 [(2,6793), (2,6811) …… (2,8206)]
……
2.y_list = [v for _, v in y]
用列表生成式的方式将元组列表中的值一一取出,形成新的列表赋给y_list,sum(y_list)/len(y_list)则计算出每个月的平均收盘价,与x一起添加到xy_map中,最后得到xy_map=[[1, 6285.870967741936], [2, 7315.714285714285], [3, 7789.032258064516], [4, 8390.466666666667], [5, 12963.935483870968], [6, 18092.166666666668], [7, 17146.16129032258], [8, 26092.645161290322], [9, 26865.633333333335], [10, 35460.67741935484], [11, 51436.166666666664]]
3.x_unique, y_mean = [*zip(*xy_map)]
**zip(iterable)函数是zip函数的逆过程,可将zip函数处理后的结果恢复为之前的样子,所以它将xy_map中每个元组中的第一个元素全部取出,赋给x_unique,得到x_unique=(1,2,3,4,5,6,7,8,9,10,11),第二个元素全部取出,赋给y_mean,得到y_mean=(6285.870967741936, 7315.714285714285, 7789.032258064516, 8390.466666666667, 12963.935483870968, 18092.166666666668, 17146.16129032258, 26092.645161290322, 26865.633333333335, 35460.67741935484, 51436.166666666664)。
4.line_chart.render_to_file(title+’.svg’)
字符串之间连接需要用‘+’。
到这里,这个代码就比较清晰了。最后执行的效果就是这样: