我的Python心路历程 第十二期 (12.6 指数实战可视化之两只产品类比时日期等数据合并、对齐显示问题的解决)

我的Python心路历程 第十二期 (12.6 指数实战可视化之两只产品类比时日期等数据合并、对齐显示问题的解决)

背景

当前,直接取条目多的日期做图后,效果对比截图如下所示:
在这里插入图片描述

很明显,从左侧两个图的x坐标可以看出来日期不一致,所以导致右图类比显示时后半部分一只产品图断了,但按理说应该是前面断裂而不是后面断裂,这里就涉及到数据治理的事情了,校正数据对其是业务层需求。

那么,接下来要解决的问题就是数据治理,将数据缺失在对的地方。最原始的方法就是做个算法将缺失数据补位为Nan;但是可以优先看看pandas自身的方法merge,研究了一下其函数原版定义。

分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

从参数说明来看,on是这里特别关注的,看看官网例子:

在这里插入图片描述

方案

结合业务实质调试ok后的代码为:

    # 基金名称及代码
    name1 = jsContent1.eval('fS_name')
    code1 = jsContent1.eval('fS_code')
    # 累计净值走势=单位净值+累计分红
    ACWorthTrendData1 = jsContent1.eval('Data_ACWorthTrend')
    ACWorthTrend1 = [v[1] for v in ACWorthTrendData1]

    # 基金名称及代码
    name2 = jsContent2.eval('fS_name')
    code2 = jsContent2.eval('fS_code')
    # 累计净值走势=单位净值+累计分红
    ACWorthTrendData2 = jsContent2.eval('Data_ACWorthTrend')
    ACWorthTrend2 = [v[1] for v in ACWorthTrendData2]

    # x轴:日期。因为系统是毫秒级timeStamp故此需要除以1000取秒级timeStamp,否则转换后的日期不对
    # vtimeStamp = [int(v[0] / 1000) for v in ACWorthTrendData1]  # // 算法符号的结果可以直接取整
    # xs = pd.to_datetime(vtimeStamp, unit='s')  # , 看源码设定对应的unit,'s'类同format='%Y-%m-%dT%H:%M:%S'但其结果会出人意料的差
    # x轴:日期。获取年月日需要除以(1000 *24*3600),因为系统是毫秒级timeStamp。
    vtimeStamp = [int(v[0] / (1000 *24*3600)) for v in ACWorthTrendData1]  # // 算法符号的结果可以直接取整
    xs1 = pd.to_datetime(vtimeStamp, unit='D')  # , 看源码设定对应的unit,'s'类同format='%Y-%m-%dT%H:%M:%S'但其结果会出人意料的差
    # x轴:日期。获取年月日需要除以(1000 *24*3600),因为系统是毫秒级timeStamp。
    vtimeStamp = [int(v[0] / (1000 * 24 * 3600)) for v in ACWorthTrendData2]  # // 算法符号的结果可以直接取整
    xs2 = pd.to_datetime(vtimeStamp, unit='D')  # , 看源码设定对应的unit,'s'类同format='%Y-%m-%dT%H:%M:%S'但其结果会出人意料的差

    # 定义字段名
    colSet = ['Date', 'ACWorth']

    # 提取x、y1、y2轴数据并整合, pd.merge适用于Series数据类型
    # 设置y轴数据
    sACWorthTrend1 = pd.Series(ACWorthTrend1, name=colSet[1])
    sACWorthTrend2 = pd.Series(ACWorthTrend2, name=colSet[1])
    # 设置x轴数据
    stimeStamp = pd.Series(xs1, name=colSet[0])
    pdACWorthTrend1 = pd.merge(stimeStamp, sACWorthTrend1, left_index=True, right_index=True)
    # 设置x轴数据
    stimeStamp = pd.Series(xs2, name=colSet[0])
    pdACWorthTrend2 = pd.merge(stimeStamp, sACWorthTrend2, left_index=True, right_index=True)
    
    # 合并两个pandas数据
    tech_df = pd.merge(pdACWorthTrend1, pdACWorthTrend2, how='outer', on=colSet[0], suffixes=('_'+code1, '_'+code2))

merge操作完成后查看数据的确已经合并完成,跟预想一致,左右双方缺失数据补位为nan。调试截图如下所示:
在这里插入图片描述

但是,接下来又出现日期作为y轴列值被图表化显示。
代码为:

    # tech_df.reset_index()
    print(tech_df.head())
    tech_df.set_index(colSet[0])
    print(tech_df.head())

运行效果如下图所示:
在这里插入图片描述

效果

数据打印效果如下图所示:
在这里插入图片描述
定睛一看,设置index前后打印数据一样,看来是日期设置index未生效导致的。

这个图肯定也不是我想要的,日期作为x轴且仅作为x轴才是想要的最终效果。

经过查阅大量资料,研究pandas在日期方面的索引机制。
优化后代码为:

    # tech_df.reset_index()
    print(tech_df.head())
    # tech_df.set_index(colSet[0])
    # 把 date 用作索引时,类型需要是 DatetimeIndex。这就是为啥此处将Date直接设置为index未生效的根本原因所在
    tech_df.set_index(colSet[0], inplace=True)
    tech_df.index = pd.DatetimeIndex(tech_df.index)

    print(tech_df.head())

最终预想效果如下图所示:

在这里插入图片描述

设置索引有效后数据打印效果如下图所示:
在这里插入图片描述

附(代码)

最后,照旧奉上所有代码:

# 比较两只基金趋势,日期不一样时有做优化整合
def compare2fs(fscode1, fscode2):
    # 获取绝对路径,funddata为当前文件夹
    curpath = os.path.join(os.path.dirname(__file__), 'funddata')
    fileName = fscode1 + 'content.js'
    file_object_path = os.path.join(curpath, fileName)

    f = open(file_object_path, 'r', encoding='utf-8')
    content = f.read()
    f.close()

    jsContent1 = execjs.compile(content)

    # 获取绝对路径,funddata为当前文件夹
    curpath = os.path.join(os.path.dirname(__file__), 'funddata')
    fileName = fscode2 + 'content.js'
    file_object_path = os.path.join(curpath, fileName)
    f = open(file_object_path, 'r', encoding='utf-8')
    content = f.read()
    f.close()

    jsContent2 = execjs.compile(content)

    # 基金名称及代码
    name1 = jsContent1.eval('fS_name')
    code1 = jsContent1.eval('fS_code')
    # 累计净值走势=单位净值+累计分红
    ACWorthTrendData1 = jsContent1.eval('Data_ACWorthTrend')
    ACWorthTrend1 = [v[1] for v in ACWorthTrendData1]

    # 基金名称及代码
    name2 = jsContent2.eval('fS_name')
    code2 = jsContent2.eval('fS_code')
    # 累计净值走势=单位净值+累计分红
    ACWorthTrendData2 = jsContent2.eval('Data_ACWorthTrend')
    ACWorthTrend2 = [v[1] for v in ACWorthTrendData2]

    # x轴:日期。因为系统是毫秒级timeStamp故此需要除以1000取秒级timeStamp,否则转换后的日期不对
    # vtimeStamp = [int(v[0] / 1000) for v in ACWorthTrendData1]  # // 算法符号的结果可以直接取整
    # xs = pd.to_datetime(vtimeStamp, unit='s')  # , 看源码设定对应的unit,'s'类同format='%Y-%m-%dT%H:%M:%S'但其结果会出人意料的差
    # x轴:日期。获取年月日需要除以(1000 *24*3600),因为系统是毫秒级timeStamp。
    vtimeStamp = [int(v[0] / (1000 *24*3600)) for v in ACWorthTrendData1]  # // 算法符号的结果可以直接取整
    xs1 = pd.to_datetime(vtimeStamp, unit='D')  # , 看源码设定对应的unit,'s'类同format='%Y-%m-%dT%H:%M:%S'但其结果会出人意料的差
    # x轴:日期。获取年月日需要除以(1000 *24*3600),因为系统是毫秒级timeStamp。
    vtimeStamp = [int(v[0] / (1000 * 24 * 3600)) for v in ACWorthTrendData2]  # // 算法符号的结果可以直接取整
    xs2 = pd.to_datetime(vtimeStamp, unit='D')  # , 看源码设定对应的unit,'s'类同format='%Y-%m-%dT%H:%M:%S'但其结果会出人意料的差

    # 定义字段名
    colSet = ['Date', 'ACWorth']

    # 提取x、y1、y2轴数据并整合, pd.merge适用于Series数据类型
    # 设置y轴数据
    sACWorthTrend1 = pd.Series(ACWorthTrend1, name=colSet[1])
    sACWorthTrend2 = pd.Series(ACWorthTrend2, name=colSet[1])
    # 设置x轴数据
    stimeStamp = pd.Series(xs1, name=colSet[0])
    pdACWorthTrend1 = pd.merge(stimeStamp, sACWorthTrend1, left_index=True, right_index=True)
    # 设置x轴数据
    stimeStamp = pd.Series(xs2, name=colSet[0])
    pdACWorthTrend2 = pd.merge(stimeStamp, sACWorthTrend2, left_index=True, right_index=True)

    # 合并两个pandas数据
    tech_df = pd.merge(pdACWorthTrend1, pdACWorthTrend2, how='outer', on=colSet[0], suffixes=('_'+code1, '_'+code2))

    # tech_df.reset_index()
    print(tech_df.head())
    # tech_df.set_index(colSet[0])
    # 把 date 用作索引时,类型需要是 DatetimeIndex。这就是为啥此处将Date直接设置为index未生效的根本原因所在
    tech_df.set_index(colSet[0], inplace=True)
    # tech_df.index = pd.DatetimeIndex(tech_df.index)

    print(tech_df.head())

    # 主次轴差异化显示
    # tech_df.plot(secondary_y=colSet[2], grid=True)
    # 主轴显示
    tech_df.plot()
    ax = plt.gca()  # 表明设置图片的各个轴,plt.gcf()表示图片本身
    ax.xaxis.set_major_formatter(mdate.DateFormatter(
        '%Y-%m-%d'))  # 横坐标标签显示的日期格式;注意,如果不加语句plt.gca().xaxis.set_major_formatter(mdate.DateFormatter('%Y-%m-%d')),则横坐标只显示年份
    plt.xlabel(u'日期')
    plt.ylabel(u'累计净值')
    plt.title(name1 + ':' + code1 + ' vs ' + name2 + ':' + code2)
    # plt.text('2017-01-01', 0.65, showStr)

    plt.gcf().autofmt_xdate()  # 自动旋转日期标记
    # plt.tight_layout()

    plt.show()

    return

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值