利用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 做的动态展示效果见视频号:
总结
越深入了解 pandas 库,就会遇到越来越多的惊喜。 在使用 pandas 的过程中,我最深的体会是,要用整体的视角来处理数据,通过操作数据的索引和列来完成数据的变换和计算。
要抛弃写代码的思路,不要想着去解析每行数据,得到每个单元格中的数据,然后再循环处理之类的。
这似乎还有点类似于写 SQL 查数据库的感觉,不过,pandas 的 DataFrame 结构比数据库中 table 结构要强大的多。
从上面的使用还可以看出,pandas 库虽然是处理表格类的数据,但是可以通过创建多级索引来处理二维以上的数据。
通过索引,能够让数据表现出更多的层次。