利用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 库虽然是处理表格类的数据,但是可以通过创建多级索引来处理二维以上的数据。
通过索引,能够让数据表现出更多的层次。

posted @ 2021-05-26 18:07  wang_yb  阅读(764)  评论(0编辑  收藏  举报