zoukankan      html  css  js  c++  java
  • 利用pandas分析交易数据

    概要

    最近在用 pandas 库分析交易数据时,对数据的行列转换有了进一步的认识。

    在做一些纵向的比较分析的时候,数据的行列转换应该是一个常规的操作, 而 pandas 库提供的方法可以从整体上对数据进行操作,极大的减少代码的编写。

    实战过程

    通过分析虚拟币的实际交易数据,掌握 pandas 库的行列转换。 虚拟币的交易数据通过 火币网 的官方 API 采集而来,定期采集的,对于交易量特别大的币,可能会有部分的遗漏。

    虚拟币的交易数据量比较大,这里只选取了 1 周的数据。

    原始数据格式

    根据 API 采集来的数据格式主要包含如下字段,每一行是一次交易:

    交易ID,交易数量,价格,交易时间戳,交易方向,币种
    100003775833,4000.56,0.014146,1621148710076,sell,creusdt
    ......
    

    目前火币上和 USDT 交易的币种大约 200 多种,这些币种一周的所有交易次数大致在 1~2 亿之间。
    仅仅一周的数据其实也是很庞大的,需要根据实际分析内容进行一些预处理。

    涨跌幅分析

    对于交易数据数据,最常见的分析就是每天的涨跌幅。
    涨跌幅的计算方法就是:

    (当天收盘价 - 上一日收盘价) / 上一日收盘价 * 100%
    

    结果为正就是涨,反之就是跌。

    所以第一步就是收集每个币种每天的收盘价,这样每天就 200 多条数据,一周的数据也就 2000 不到。
    这一步不是用 pandas 做的,暂时略过,整理后的数据格式如下:

    交易日,币种,最高价,最低价,收盘价
    2021-05-09,1inchusdt,7.704231,6.72144,7.049687
    2021-05-09,aacusdt,0.015569,0.0137,0.014916
    2021-05-09,aaveusdt,475.2571,440.6347,456.919
    ... ...
    

    为了简化后面的分析,我将数据精简了,只保留 3 个币种的数据。(全部数据也是一样的分析)

    分析步骤 01:去除多余的列

    我们的目的是分析每个币种每天的涨跌幅,只需要收盘价信息,
    所以,第一步,去除最高价和最低价的列。

    首先,进入 Ipython,导入 pandas 库。

    In [1]: import pandas as pd
    In [2]: f_data = pd.read_csv("./data.csv")
    In [3]: f_data
    Out[3]:
               交易日         币种       最高价       最低价       收盘价
    0   2021-05-09  1inchusdt  7.704231  6.721440  7.049687
    1   2021-05-09    aacusdt  0.015569  0.013700  0.014916
    2   2021-05-09    zrxusdt  1.985400  1.837000  1.949000
    3   2021-05-10  1inchusdt  7.205859  6.488946  6.693635
    4   2021-05-10    aacusdt  0.016108  0.014216  0.016097
    5   2021-05-10    zrxusdt  2.020500  1.870900  1.936400
    6   2021-05-11  1inchusdt  6.706469  5.588000  6.330097
    7   2021-05-11    aacusdt  0.023999  0.014787  0.017725
    8   2021-05-11    zrxusdt  1.938000  1.638800  1.835800
    9   2021-05-12  1inchusdt  6.914203  6.247467  6.478842
    10  2021-05-12    aacusdt  0.019471  0.015502  0.016901
    11  2021-05-12    zrxusdt  2.037200  1.799600  1.882900
    12  2021-05-13  1inchusdt  6.523776  5.266794  5.377795
    13  2021-05-13    aacusdt  0.017724  0.013801  0.014344
    14  2021-05-13    zrxusdt  1.941800  1.542800  1.625700
    15  2021-05-14  1inchusdt  5.939128  5.291762  5.868618
    16  2021-05-14    aacusdt  0.015567  0.013966  0.015385
    17  2021-05-14    zrxusdt  1.760300  1.543100  1.744100
    18  2021-05-15  1inchusdt  6.047498  5.499000  5.646441
    19  2021-05-15    aacusdt  0.016356  0.014308  0.015849
    20  2021-05-15    zrxusdt  1.767000  1.570000  1.631500
    21  2021-05-16  1inchusdt  5.645512  5.193545  5.273476
    22  2021-05-16    aacusdt  0.015847  0.014411  0.015002
    23  2021-05-16    zrxusdt  1.700000  1.533400  1.616500
    24  2021-05-17  1inchusdt  5.339175  4.441147  4.701934
    25  2021-05-17    aacusdt  0.018000  0.014000  0.016289
    26  2021-05-17    zrxusdt  1.638000  1.391900  1.468800
    27  2021-05-18  1inchusdt  4.884853  4.528847  4.855229
    28  2021-05-18    aacusdt  0.016356  0.015042  0.015705
    29  2021-05-18    zrxusdt  1.524300  1.405600  1.506800
    

    这里显示所有用来实验的数据。
    去除最高价和最低价的列只要一行代码:

    In [4]: f_data = f_data[["交易日", "币种", "收盘价"]]
    
    In [5]: f_data
    Out[5]:
               交易日         币种       收盘价
    0   2021-05-09  1inchusdt  7.049687
    1   2021-05-09    aacusdt  0.014916
    2   2021-05-09    zrxusdt  1.949000
    3   2021-05-10  1inchusdt  6.693635
    4   2021-05-10    aacusdt  0.016097
    5   2021-05-10    zrxusdt  1.936400
    6   2021-05-11  1inchusdt  6.330097
    7   2021-05-11    aacusdt  0.017725
    8   2021-05-11    zrxusdt  1.835800
    9   2021-05-12  1inchusdt  6.478842
    10  2021-05-12    aacusdt  0.016901
    11  2021-05-12    zrxusdt  1.882900
    12  2021-05-13  1inchusdt  5.377795
    13  2021-05-13    aacusdt  0.014344
    14  2021-05-13    zrxusdt  1.625700
    15  2021-05-14  1inchusdt  5.868618
    16  2021-05-14    aacusdt  0.015385
    17  2021-05-14    zrxusdt  1.744100
    18  2021-05-15  1inchusdt  5.646441
    19  2021-05-15    aacusdt  0.015849
    20  2021-05-15    zrxusdt  1.631500
    21  2021-05-16  1inchusdt  5.273476
    22  2021-05-16    aacusdt  0.015002
    23  2021-05-16    zrxusdt  1.616500
    24  2021-05-17  1inchusdt  4.701934
    25  2021-05-17    aacusdt  0.016289
    26  2021-05-17    zrxusdt  1.468800
    27  2021-05-18  1inchusdt  4.855229
    28  2021-05-18    aacusdt  0.015705
    29  2021-05-18    zrxusdt  1.506800
    

    分析步骤 02:币种列转为行,每个交易日一行数据

    为了分析每个币种每天的变化,按照交易日顺序,排列每个币种的收盘价。
    要将币种转成行,先将交易日设置成 1 级索引,币种作为 2 级索引,然后将 2 级索引转成列

    In [6]: f_data = f_data.set_index(["交易日", "币种"])["收盘价"]
    
    In [7]: f_data = f_data.unstack()
    
    In [8]: f_data
    Out[8]:
    币种          1inchusdt   aacusdt  zrxusdt
    交易日
    2021-05-09   7.049687  0.014916   1.9490
    2021-05-10   6.693635  0.016097   1.9364
    2021-05-11   6.330097  0.017725   1.8358
    2021-05-12   6.478842  0.016901   1.8829
    2021-05-13   5.377795  0.014344   1.6257
    2021-05-14   5.868618  0.015385   1.7441
    2021-05-15   5.646441  0.015849   1.6315
    2021-05-16   5.273476  0.015002   1.6165
    2021-05-17   4.701934  0.016289   1.4688
    2021-05-18   4.855229  0.015705   1.5068
    

    通过上面可以看出,column 的 name 是 币种 index 的 name 是 交易日 column 的 name 不需要,可以用下面的代码去除 column 的 name

    In [9]: f_data = f_data.rename_axis(columns=None)
    
    In [10]: f_data
    Out[10]:
                1inchusdt   aacusdt  zrxusdt
    交易日
    2021-05-09   7.049687  0.014916   1.9490
    2021-05-10   6.693635  0.016097   1.9364
    2021-05-11   6.330097  0.017725   1.8358
    2021-05-12   6.478842  0.016901   1.8829
    2021-05-13   5.377795  0.014344   1.6257
    2021-05-14   5.868618  0.015385   1.7441
    2021-05-15   5.646441  0.015849   1.6315
    2021-05-16   5.273476  0.015002   1.6165
    2021-05-17   4.701934  0.016289   1.4688
    2021-05-18   4.855229  0.015705   1.5068
    

    分析步骤 03:就是每天的涨跌幅

    数据变成上面格式之后,计算涨跌幅只需一行代码。

    In [11]: f_data = f_data.pct_change()
    
    In [12]: f_data
    Out[12]:
                1inchusdt   aacusdt   zrxusdt
    交易日
    2021-05-09        NaN       NaN       NaN
    2021-05-10  -0.050506  0.079177 -0.006465
    2021-05-11  -0.054311  0.101137 -0.051952
    2021-05-12   0.023498 -0.046488  0.025656
    2021-05-13  -0.169945 -0.151293 -0.136598
    2021-05-14   0.091268  0.072574  0.072830
    2021-05-15  -0.037858  0.030159 -0.064561
    2021-05-16  -0.066053 -0.053442 -0.009194
    2021-05-17  -0.108381  0.085789 -0.091370
    2021-05-18   0.032603 -0.035852  0.025871
    

    第一条数据由于没有上一日的数据,所以没有涨跌幅。

    分析步骤 04:删除掉第一天的无效数据

    In [13]: f_data = f_data.drop(index=["2021-05-09"])
    
    In [14]: f_data
    Out[14]:
                1inchusdt   aacusdt   zrxusdt
    交易日
    2021-05-10  -0.050506  0.079177 -0.006465
    2021-05-11  -0.054311  0.101137 -0.051952
    2021-05-12   0.023498 -0.046488  0.025656
    2021-05-13  -0.169945 -0.151293 -0.136598
    2021-05-14   0.091268  0.072574  0.072830
    2021-05-15  -0.037858  0.030159 -0.064561
    2021-05-16  -0.066053 -0.053442 -0.009194
    2021-05-17  -0.108381  0.085789 -0.091370
    2021-05-18   0.032603 -0.035852  0.025871
    

    分析步骤 05:币种行转列,方便按照涨跌幅排序

    再转回原来的格式,方便进行涨跌幅排序。

    行列转回去之后,需要重置 index,将 交易日 作为数据的一列,而不是 index.
    现在 交易日 是作为数据的 index 的。

    In [16]: f_data = f_data.stack()
    In [17]: f_data = f_data.reset_index()
    Out[17]:
               交易日    level_1         0
    0   2021-05-10  1inchusdt -0.050506
    1   2021-05-10    aacusdt  0.079177
    2   2021-05-10    zrxusdt -0.006465
    3   2021-05-11  1inchusdt -0.054311
    4   2021-05-11    aacusdt  0.101137
    5   2021-05-11    zrxusdt -0.051952
    6   2021-05-12  1inchusdt  0.023498
    7   2021-05-12    aacusdt -0.046488
    8   2021-05-12    zrxusdt  0.025656
    9   2021-05-13  1inchusdt -0.169945
    10  2021-05-13    aacusdt -0.151293
    11  2021-05-13    zrxusdt -0.136598
    12  2021-05-14  1inchusdt  0.091268
    13  2021-05-14    aacusdt  0.072574
    14  2021-05-14    zrxusdt  0.072830
    15  2021-05-15  1inchusdt -0.037858
    16  2021-05-15    aacusdt  0.030159
    17  2021-05-15    zrxusdt -0.064561
    18  2021-05-16  1inchusdt -0.066053
    19  2021-05-16    aacusdt -0.053442
    20  2021-05-16    zrxusdt -0.009194
    21  2021-05-17  1inchusdt -0.108381
    22  2021-05-17    aacusdt  0.085789
    23  2021-05-17    zrxusdt -0.091370
    24  2021-05-18  1inchusdt  0.032603
    25  2021-05-18    aacusdt -0.035852
    26  2021-05-18    zrxusdt  0.025871
    

    重命名列的名称 level_1 -> 币种,0 -> 涨跌幅。

    In [20]: f_data = f_data.rename(columns={"level_1": "币种", 0: "涨跌幅"})
    
    In [21]: f_data
    Out[21]:
               交易日         币种       涨跌幅
    0   2021-05-10  1inchusdt -0.050506
    1   2021-05-10    aacusdt  0.079177
    2   2021-05-10    zrxusdt -0.006465
    3   2021-05-11  1inchusdt -0.054311
    4   2021-05-11    aacusdt  0.101137
    5   2021-05-11    zrxusdt -0.051952
    6   2021-05-12  1inchusdt  0.023498
    7   2021-05-12    aacusdt -0.046488
    8   2021-05-12    zrxusdt  0.025656
    9   2021-05-13  1inchusdt -0.169945
    10  2021-05-13    aacusdt -0.151293
    11  2021-05-13    zrxusdt -0.136598
    12  2021-05-14  1inchusdt  0.091268
    13  2021-05-14    aacusdt  0.072574
    14  2021-05-14    zrxusdt  0.072830
    15  2021-05-15  1inchusdt -0.037858
    16  2021-05-15    aacusdt  0.030159
    17  2021-05-15    zrxusdt -0.064561
    18  2021-05-16  1inchusdt -0.066053
    19  2021-05-16    aacusdt -0.053442
    20  2021-05-16    zrxusdt -0.009194
    21  2021-05-17  1inchusdt -0.108381
    22  2021-05-17    aacusdt  0.085789
    23  2021-05-17    zrxusdt -0.091370
    24  2021-05-18  1inchusdt  0.032603
    25  2021-05-18    aacusdt -0.035852
    26  2021-05-18    zrxusdt  0.025871
    

    每天各币种的涨跌幅按照从小到大排序。

    In [22]: f_data = f_data.sort_values(by=["涨跌幅"])
    
    In [23]: f_data
    Out[23]:
               交易日         币种       涨跌幅
    9   2021-05-13  1inchusdt -0.169945
    10  2021-05-13    aacusdt -0.151293
    11  2021-05-13    zrxusdt -0.136598
    21  2021-05-17  1inchusdt -0.108381
    23  2021-05-17    zrxusdt -0.091370
    18  2021-05-16  1inchusdt -0.066053
    17  2021-05-15    zrxusdt -0.064561
    3   2021-05-11  1inchusdt -0.054311
    19  2021-05-16    aacusdt -0.053442
    5   2021-05-11    zrxusdt -0.051952
    0   2021-05-10  1inchusdt -0.050506
    7   2021-05-12    aacusdt -0.046488
    15  2021-05-15  1inchusdt -0.037858
    25  2021-05-18    aacusdt -0.035852
    20  2021-05-16    zrxusdt -0.009194
    2   2021-05-10    zrxusdt -0.006465
    6   2021-05-12  1inchusdt  0.023498
    8   2021-05-12    zrxusdt  0.025656
    26  2021-05-18    zrxusdt  0.025871
    16  2021-05-15    aacusdt  0.030159
    24  2021-05-18  1inchusdt  0.032603
    13  2021-05-14    aacusdt  0.072574
    14  2021-05-14    zrxusdt  0.072830
    1   2021-05-10    aacusdt  0.079177
    22  2021-05-17    aacusdt  0.085789
    12  2021-05-14  1inchusdt  0.091268
    4   2021-05-11    aacusdt  0.101137
    

    可以看出,排序之后,index 顺序乱了。不过没什么关系,我们最后只要导出数据,不用导出 index。

    分析步骤 06:导出数据

    In [24]: f_data.to_csv("./data-result.csv", index=False)
    
    In [25]: cat ./data-result.csv
    交易日,币种,涨跌幅
    2021-05-13,1inchusdt,-0.16994503030016783
    2021-05-13,aacusdt,-0.15129282290988688
    2021-05-13,zrxusdt,-0.13659780126400767
    2021-05-17,1inchusdt,-0.10838050651979836
    2021-05-17,zrxusdt,-0.09137024435508811
    2021-05-16,1inchusdt,-0.0660531120399559
    2021-05-15,zrxusdt,-0.06456051831890375
    2021-05-11,1inchusdt,-0.054310998433586444
    2021-05-16,aacusdt,-0.053441857530443504
    2021-05-11,zrxusdt,-0.051952076017351634
    2021-05-10,1inchusdt,-0.05050607211355629
    2021-05-12,aacusdt,-0.046488011283498
    2021-05-15,1inchusdt,-0.03785848729632757
    2021-05-18,aacusdt,-0.035852415740683985
    2021-05-16,zrxusdt,-0.009193993257738176
    2021-05-10,zrxusdt,-0.006464853771164791
    2021-05-12,1inchusdt,0.023498060140310528
    2021-05-12,zrxusdt,0.025656389584922
    2021-05-18,zrxusdt,0.02587145969498894
    2021-05-15,aacusdt,0.03015924601884956
    2021-05-18,1inchusdt,0.03260254184767364
    2021-05-14,aacusdt,0.07257389849414375
    2021-05-14,zrxusdt,0.07283016546718346
    2021-05-10,aacusdt,0.0791767229820326
    2021-05-17,aacusdt,0.08578856152513015
    2021-05-14,1inchusdt,0.09126844738410433
    2021-05-11,aacusdt,0.10113685779959014
    

    可视化

    到这里基本分析结束,可以用导出的数据去做可视化展示了,使用 antd 做的动态展示效果见视频号:
    databook 视频号

    总结

    越深入了解 pandas 库,就会遇到越来越多的惊喜。 在使用 pandas 的过程中,我最深的体会是,要用整体的视角来处理数据,通过操作数据的索引和列来完成数据的变换和计算。
    要抛弃写代码的思路,不要想着去解析每行数据,得到每个单元格中的数据,然后再循环处理之类的。
    这似乎还有点类似于写 SQL 查数据库的感觉,不过,pandas 的 DataFrame 结构比数据库中 table 结构要强大的多。

    从上面的使用还可以看出,pandas 库虽然是处理表格类的数据,但是可以通过创建多级索引来处理二维以上的数据。
    通过索引,能够让数据表现出更多的层次。

  • 相关阅读:
    2016 年青岛网络赛---Sort(k叉哈夫曼)
    Gym 100703G---Game of numbers(DP)
    棋盘覆盖(分治法)
    大整数乘法(分治法)
    博客编辑---数学公式
    《程序员代码面试指南》第八章 数组和矩阵问题 子数组的最大累加和问题
    《程序员代码面试指南》第八章 数组和矩阵问题 奇数下标都是奇数或者偶数下标都是偶数
    《程序员代码面试指南》第八章 数组和矩阵问题 自然数数组的排序
    《程序员代码面试指南》第八章 数组和矩阵问题 计算数组的小和
    《程序员代码面试指南》第八章 数组和矩阵问题 未排序数组中累加和小于或等于给定值的最长子数组长度
  • 原文地址:https://www.cnblogs.com/wang_yb/p/14814568.html
Copyright © 2011-2022 走看看