手把手教你学python基础课系列快速回顾:
1、“零基础包学会” 手把手教你学python一:如何快速找到学习资源?
2、手把手教你学python第二课:如何迅速上手马上能run
3、手把手教你学python第三课:数据分析,学会使用pandas大杀器
5、手把手教你学python第五课:各种渠道获取数据,快速学会windpy和网络爬虫
6、手把手教你学python第六课:技术分析入门-talib
手把手教你学python第六课:技术分析入门-talib-成交量及曲线形态
手把手教你学python第六课:技术分析入门-talib-安装及动量指标
手把手教你学python进阶系列快速回顾:
2023
手把手教你学python系列进阶版
写在最初
在新的一年与尔岩说将继续之前的手把手教你学python专栏(停更的原因一部分是因为大家说之前的需要时间消化,所以停了一段时间,另一部分原因是想邀请比我更专业而且实用性更强的王者们来上进阶课程),主笔加入了我的两个非常好的两个朋友(笔名十月和木矛木心),下面是十月写在最初的话:
这里会定期更新一些实际案例和具体用法,如果你和我一样热爱用科技提高工作效率,并想要一起研究一些有意思的事情,欢迎一起来进阶!!
数据处理和展示操作是在日常高频使用的代码,且可复用性很强。(蓬蓬说:这部分用好了事半功倍,好的展示能力和挖掘能力是非常重要的,十月还是用了日常中需求很多的例子来教学的,亲自尝试一定有收获!!)
# 导入数据分析需要使用的Python模块
import pandas as pd
import os
import re
# 用于显示循环进度条
from tqdm import tqdm
# 导入绘图所需模块
# 考虑到更好的交互性,本案例中优先采用Plotly
# 使用Plotly保存图片需用到Kaleido模块,可通过"pip install kaleido"进行安装
import plotly.express as px
# 在jupyter notebook中使用Plotly需进行初始化
from plotly.offline import init_notebook_mode
init_notebook_mode(connected=True)
# 注意新建的Notebook与案例二保持在同一文件夹
PATH_BASE = os.path.abspath("./")
PATH_DATA = os.path.join(PATH_BASE, "Data")
PATH_PLOT = os.path.join(PATH_BASE, "Plot")
# 利用os模块,在Notebook的相同目录下新建Plot文件夹,用于存放图片
# 判断Plot文件夹是否存在,若不存在则创建
if not os.path.exists(PATH_PLOT):
os.mkdir(PATH_PLOT)
# 创建一个DataFrame用于保存沪深交易所现券交易月报文件信息
data_bond_trade_file = pd.DataFrame(columns=["market", "report_date", "file_path"])
# 查找数据目录下沪深交易所现券交易月报文件
pbar = tqdm(os.listdir(PATH_DATA))
for loop_file in pbar:
pbar.set_description(loop_file)
loop_file_path = os.path.join(PATH_DATA, loop_file)
if os.path.isfile(loop_file_path):
# 利用正则表达式匹配文件名,判断是否为现券交易月报文件
# Python正则表达式中用于多个可能单词的匹配时,可使用(?:单词1|单词2|...|单词n)的形式
# 日期的正则匹配可结合具体情况,本案例中为连续8个数字,即\d{8}
# 正则表达式中匹配字符串开头和结尾,分别使用"^"和"$"
loop_file_info = re.findall("^bond_trade_((?:sse|szse))_(\d{8}).csv$", loop_file)
if loop_file_info:
data_bond_trade_file.loc[loop_file] = (*loop_file_info[0], loop_file_path)
# 由于沪深交易所现券交易月报数据结构存在一定差异,分别读取22年初至23年2月的数据
# 利用pandas读取上交所现券交易月报数据,并使用 pandas.cancat 将不同月份的数据拼接到一个DataFrame中
data_bond_trade_sse = pd.concat([
# 注意案例二中抓取数据保存为csv文件时所指定的字符编码为GB18030
# 通过 index_col 参数,指定将投资者类别和报告期设置为索引
# 通过 parse_dates 参数,指定哪些列为日期格式
pd.read_csv(loop_file_path, encoding="GB18030", index_col=["投资者类别", "报告期"], parse_dates=["报告期"])
# 通过 pandas.DataFrame.query 可以快速查找所需数据文件的范围
for loop_file_path in data_bond_trade_file.query(
"market == 'sse' and report_date >= '20220101' and report_date <= '20230228'"
)["file_path"]
])
# 以类似的方法读取深交所现券交易月报数据
data_bond_trade_szse = pd.concat([
pd.read_csv(loop_file_path, encoding="GB18030", index_col=["投资者类别", "报告期"], parse_dates=["报告期"])
for loop_file_path in data_bond_trade_file.query(
"market == 'szse' and report_date >= '20220101' and report_date <= '20230228'"
)["file_path"]
])
# 上交所现券交易月报投资者类别
print(data_bond_trade_sse.index.levels[0])
# 深交所现券交易月报投资者类别
print(data_bond_trade_szse.index.levels[0])
# 上交所现券交易月报债券类型
print(data_bond_trade_sse.columns)
# 深交所现券交易月报债券类型
print(data_bond_trade_szse.columns)
# 利用字典调整沪深交易所数据口径
# 找到沪深交易所现券交易月报中需要归并整合的投资者类别,并进行统一映射
MAP_INVESTOR_TYPE = {
'QFII': "外资",
'QFII、RQFII': "外资",
'RQFII': "外资",
'沪股通投资者': "外资",
'保险机构': "保险",
'信托机构': "信托",
'证券公司自营': "券商",
'券商自营': "券商",
'券商集合理财': "券商",
'证券公司资管': "券商",
'公募基金': "公募",
'基金': "公募",
'基金管理公司资产管理计划': "公募",
'基金专户': "公募",
'企业年金': "年金",
'社会保障基金': "社保",
'社保基金': "社保",
'银行理财': "其他专业机构",
'银行自营': "其他专业机构",
'私募基金': "其他专业机构",
'财务公司': "其他专业机构",
'其他金融机构': "其他专业机构",
'其他专业机构': "其他专业机构",
'一般机构': "一般机构",
'自然人': "自然人",
'自然人投资者': "自然人",
}
# 找到沪深交易所现券交易月报中需要归并整合的债券类型,并进行统一映射
MAP_BOND_TYPE = {
'记账式国债': "国债",
'国债': "国债",
'地方政府债券': "地方债",
'地方政府债': "地方债",
'政策性金融债': "金融债",
'普通金融债': "金融债",
'企业债券': "企业债",
'公司债券': "公司债",
'可转换公司债券': "可转债",
'可转换债券': "可转债",
'分离交易的可转换公司债券': "可转债",
'可交换公司债券': "可交债",
'中小企业私募债券': "其他债券",
'非公开发行公司债券': "其他债券",
'企业资产支持证券': "其他债券",
'信贷资产支持证券': "其他债券",
'政府支持债券': "其他债券",
'非公开发行公司债券': "其他债券",
'非公开发行可交换公司债券': "其他债券",
'创新创业可转换债券': "其他债券",
'证券公司次级债券': "其他债券",
'证券公司短期债券': "其他债券",
'不动产投资信托': "其他债券",
'其他债券': "其他债券",
}
# 利用 pandas.DataFrame.drop 去除不需要的行和列
# 利用 pandas.DataFrame.rename 调整投资者类别和债券类型
# 利用 pandas.DataFrame.groupby.sum 将口径调整后的数据进行归并汇总
data_bond_trade_sse_adj = (
data_bond_trade_sse
.drop("合计占比", axis=1)
.rename(MAP_INVESTOR_TYPE, axis=0, level=0)
.groupby(["投资者类别", "报告期"]).sum()
.rename(MAP_BOND_TYPE, axis=1)
.groupby(level=0, axis=1).sum()
)
data_bond_trade_szse_adj = (
data_bond_trade_szse
.drop("汇总", axis=0, level=0)
.drop("合计占比", axis=1)
.rename(MAP_INVESTOR_TYPE, axis=0, level=0)
.groupby(["投资者类别", "报告期"]).sum()
.rename(MAP_BOND_TYPE, axis=1)
.groupby(level=0, axis=1).sum()
)
data_bond_trade = data_bond_trade_sse_adj + data_bond_trade_szse_adj
# 利用 pandas.DataFrame.unstack 将数据转换为列为投资者类别、行为报告期的结构
# 利用 pandas.DataFrame.rename 将报告期格式调整为"年-月"的字符串形式,便于后续绘图;非必须,视情况使用
data_cb = data_bond_trade["可转债"].unstack("投资者类别")
data_cb.rename(lambda x: x.strftime("%Y-%m"), inplace=True)
描述性统计的日常使用频率很高,用 pandas.DataFrame.describe 可以很方便的实现,输出结果中包含了计数、均值、标准差、最小值、最大值、分位值等常用信息。我们将描述性统计结果保存到Data文件夹中,便于下一个案例中使用,注意指定字符串编码。
# 描述性统计
# 利用 pandas.DataFrame.describe 进行描述性统计分析,包括计数、均值、标准差、最小值、最大值、分位值
# 通过 percentiles 参数调整所需分位值
data_cb_describe = data_cb.describe(percentiles=[0.1, 0.25, 0.5, 0.75, 0.9])
# 通过 pandas.DataFrame.to_csv 保存数据为csv文件
# 通过 enconding 参数指定字符编码格式
data_cb_describe.to_csv(os.path.join(PATH_DATA, "data_cb_describe.csv"), encoding="GB18030")
不同投资者类别之间可转债交易金额的相关性分析,用 pandas.DataFrame.corr 即可实现,输出结果为N*N的相关性矩阵。同样将相关性分析数据保存到Data文件夹中,便于下一个案例中使用,注意指定字符串编码。
# 相关性矩阵
# 利用 pandas.DataFrame.corr 进行相关性分析
# 通过 method 参数指定相关性方法,包括 pearson、kendall、spearman 三类
data_cb_corr = data_cb.corr(method="pearson")
# 通过 pandas.DataFrame.to_csv 保存数据为csv文件
# 通过 enconding 参数指定字符编码格式
data_cb_corr.to_csv(os.path.join(PATH_DATA, "data_cb_corr.csv"), encoding="GB18030")
# 折线图:可用于观察代表性投资者转债交易金额的时间序列变化情况
# 使用 plotly.express.line 进行绘制
# 通过 data_frame 参数指定绘图数据
# 通过 height、width 参数指定图表的高度和宽度,单位为PX
# https://plotly.com/python-api-reference/generated/plotly.express.line
fig_line = px.line(
data_frame=data_cb[["公募", "券商", "保险", "社保"]],
height=400,
width=900,
)
# 通过 fig.update_layout 调整图表布局
# 本案例调整了标题、标题字体大小和图例字体大小
# https://plotly.com/python/reference/layout/
fig_line.update_layout(
title=dict(
text="可转债交易金额统计",
font=dict(
size=18,
)
),
legend=dict(
font=dict(
size=14,
)
),
)
# 通过 fig.update_yaxes 调整图表纵坐标布局
# 本案例调整了纵坐标标题、标题字体大小
# https://plotly.com/python/reference/layout/yaxis/
fig_line.update_yaxes(
title=dict(
text="交易金额(亿元)",
font=dict(
size=14,
)
),
)
# 通过 fig.update_xaxes 调整图表横坐标布局
# 本案例调整了横坐标标题、标题字体大小和横坐标刻度标签数据格式
# https://plotly.com/python/reference/layout/xaxis/
fig_line.update_xaxes(
title=dict(
text="报告期",
font=dict(
size=14,
)
),
tickformat="%Y-%m",
)
# 通过 fig.write_image 保存图片
fig_line.write_image(
os.path.join(PATH_PLOT, "折线图.png"),
)
# 通过 fig.show 显示图表
fig_line.show()
# 箱型图:可用于观察不同投资者转债历史交易金额的分布特征情况
# 使用 plotly.express.box 进行绘制
# 通过 data_frame 参数指定绘图数据
# 由于不同投资者类别的交易金额存在数量级差异,通过 log_y 参数将纵坐标调整为对数坐标轴
# 通过 points 参数在箱型图边上显示数据散点
# 通过 height、width 参数指定图表的高度和宽度,单位为PX
# https://plotly.com/python-api-reference/generated/plotly.express.box
fig_box = px.box(
data_frame=data_cb,
log_y=True,
points="all",
height=400,
width=900,
)
# 通过 fig.update_layout 调整图表布局
# 本案例调整了标题、标题字体大小
# https://plotly.com/python/reference/layout/
fig_box.update_layout(
title=dict(
text="可转债交易金额分布特征",
font=dict(
size=18,
)
),
)
# 通过 fig.update_yaxes 调整图表纵坐标布局
# 本案例调整了纵坐标标题、标题字体大小
# https://plotly.com/python/reference/layout/yaxis/
fig_box.update_yaxes(
title=dict(
text="交易金额(亿元)",
font=dict(
size=14,
)
),
)
# 通过 fig.update_xaxes 调整图表横坐标布局
# 本案例调整了横坐标标题、标题字体大小
# https://plotly.com/python/reference/layout/xaxis/
fig_box.update_xaxes(
title=dict(
text="投资者类别",
font=dict(
size=14,
)
),
)
# 通过 fig.write_image 保存图片
fig_box.write_image(
os.path.join(PATH_PLOT, "箱型图.png"),
)
# 通过 fig.show 显示图表
fig_box.show()
柱状图
# 柱状图:可用于观察不同投资者之间转债历史交易金额的差异情况
# 使用 plotly.express.bar 进行绘制
# 通过 data_frame 参数指定绘图数据
# 通过 barmode 参数指定柱状图模式为按投资者分组
# https://plotly.com/python-api-reference/generated/plotly.express.bar
fig_bar = px.bar(
data_frame=data_cb.loc["2022-12":"2023-02"].T,
barmode="group",
height=400,
width=900,
)
# 通过 fig.update_layout 调整图表布局
# 本案例调整了标题、标题字体大小和图例字体大小
# https://plotly.com/python/reference/layout/
fig_bar.update_layout(
title=dict(
text="可转债交易金额统计",
font=dict(
size=18,
)
),
legend=dict(
font=dict(
size=14,
)
),
)
# 通过 fig.update_yaxes 调整图表纵坐标布局
# 本案例调整了纵坐标标题、标题字体大小
# https://plotly.com/python/reference/layout/yaxis/
fig_bar.update_yaxes(
title=dict(
text="交易金额(亿元)",
font=dict(
size=14,
)
),
)
# 通过 fig.update_xaxes 调整图表横坐标布局
# 本案例调整了横坐标标题、标题字体大小
# https://plotly.com/python/reference/layout/xaxis/
fig_bar.update_xaxes(
title=dict(
text="报告期",
font=dict(
size=14,
)
),
)
# 通过 fig.write_image 保存图片
fig_bar.write_image(
os.path.join(PATH_PLOT, "柱状图.png"),
)
# 通过 fig.show 显示图表
fig_bar.show()
# 利用 pandas.DataFrame.stack 对相关性数据格式进行调整,便于后续绘图
data_cb_corr_stack = data_cb_corr.stack()
# 散点图:可用于观察不同投资者之间转债历史交易金额的相关性情况
# 使用 plotly.express.scatter 进行绘制
# 通过 x、y 参数指定横纵坐标轴数据
# 通过 color、size 参数指定设置散点颜色和大小的参考数据
# 通过 size_max 参数指定散点最大尺寸
# 通过 text 参数指定散点处显示的文字
# 通过 color_continuous_scale 指定使用的颜色范围
# 通过 opacity 参数指定散点透明度
# 通过 height、width 参数指定图表的高度和宽度,单位为PX
# https://plotly.com/python-api-reference/generated/plotly.express.scatter
fig_scatter = px.scatter(
x=data_cb_corr_stack.index.get_level_values(1),
y=data_cb_corr_stack.index.get_level_values(0),
color=data_cb_corr_stack,
size=data_cb_corr_stack,
size_max=45,
text=data_cb_corr_stack.round(2),
color_continuous_scale=px.colors.sequential.Rainbow,
opacity=0.5,
height=800,
width=900,
)
# 通过 fig.update_layout 调整图表布局
# 本案例调整了标题、标题字体大小、标题位置和绘图区边距
# https://plotly.com/python/reference/layout/
fig_scatter.update_layout(
margin=dict(
r=40,
b=20
),
title=dict(
text="可转债交易金额相关性矩阵",
font=dict(
size=18
),
xanchor="center",
x=0.5
),
)
# 通过 fig.update_yaxes 调整图表色阶条
# 通过 showscale 参数隐藏默认显示的色阶条
# https://plotly.com/python/reference/layout/coloraxis/
fig_scatter.update_coloraxes(showscale=False)
# 通过 fig.update_yaxes 调整图表纵坐标布局
# 本案例调整了纵坐标标题、标签字体大小
# 通过 autorange 参数将纵坐标顺序反转
# https://plotly.com/python/reference/layout/yaxis/
fig_scatter.update_yaxes(
title=dict(
text=""
),
autorange="reversed",
tickfont=dict(
size=14
),
)
# 通过 fig.update_xaxes 调整图表横坐标布局
# 本案例调整了横坐标标题、标签位置、标签字体大小
# 通过 scaleanchor 参数指定与纵坐标保持相同缩放量级
# https://plotly.com/python/reference/layout/xaxis/
fig_scatter.update_xaxes(
scaleanchor="y",
title=dict(
text=""
),
side="top",
tickfont=dict(
size=14
),
)
# 通过 fig.write_image 保存图片
fig_scatter.write_image(
os.path.join(PATH_PLOT, "散点图.png"),
)
# 通过 fig.show 显示图表
fig_scatter.show()
——文 by 十月