目录
最后编辑于:2020.02.06 18:00
Pandas库 Pandas是基于NumPy 的一种工具,其出现是为了解决数据分析任务。(氦核:个人觉得更像是探索工具,没有模型,简单分析。) Pandas吸纳了大量库和一些标准的数据模型,提供了高效操作大型数据集所需的工具。 Pandas中的函数和方法能够使我们快速便捷地处理数据。 它是使Python成为强大而高效的数据分析环境的重要因素之一。
http://pandas.pydata.org/pandas-docs/stable/api.html
本文参考万旷网教程 。
1 2 3 import numpy as npimport pandas as pd
numpy详见上一篇文章。
一、序列Series 序列Series是一个一维数组结构,可以存入任一种Python数据类型(integers, strings, floating point numbers, Python objects, 等等)
序列Series由两部分构成,一个是index,另一个是对应的值,注意两者的长度必须一样。序列Series和数组array很类似,大多数numpy的函数都可以直接应用于序列Series
序列Series也像一个固定大小的字典dict,可以通过index来赋值或者取值
1 2 3 4 print('通过数组来生成序列Series' ) s_array = np.random.randn(5 ) s = pd.Series(s_array, index = ['a' ,'b' ,'c' ,'d' ,'e' ]) s
通过数组来生成序列Series
a -0.298058
b -1.095748
c 1.333607
d 1.119917
e 1.595123
dtype: float64
1 2 3 4 print('通过字典来生成序列Series' ) s_dict= {'a' :11 ,'b' :1000 ,'c' :123213 ,'d' :-1000 } s = pd.Series(s_dict) s
通过字典来生成序列Series
a 11
b 1000
c 123213
d -1000
dtype: int64
我们取一段金融时间序列给大家做更具体的分析:
1 2 3 4 5 from WindPy import *w.start() list1 = w.wsd("000001.SZ" , "close" , "2018-06-28" , "2018-07-11" , "" ) list1
Welcome to use Wind Quant API for Python (WindPy)!
COPYRIGHT (C) 2017 WIND INFORMATION CO., LTD. ALL RIGHTS RESERVED.
IN NO CIRCUMSTANCE SHALL WIND BE RESPONSIBLE FOR ANY DAMAGES OR LOSSES CAUSED BY USING WIND QUANT API FOR Python.
.ErrorCode=0
.Codes=[000001.SZ]
.Fields=[CLOSE]
.Times=[20180628,20180629,20180702,20180703,20180704,20180705,20180706,20180709,20180710,20180711]
.Data=[[8.92,9.09,8.61,8.67,8.61,8.6,8.66,9.03,8.98,8.78]]
1 2 3 ss = pd.Series(list1.Data[0 ], index = list1.Times) ss
2018-06-28 8.92
2018-06-29 9.09
2018-07-02 8.61
2018-07-03 8.67
2018-07-04 8.61
2018-07-05 8.60
2018-07-06 8.66
2018-07-09 9.03
2018-07-10 8.98
2018-07-11 8.78
dtype: float64
1 2 3 4 print('查看序列中index为:' ,ss.index) print() print('查看序列中index为a的元素:' ,ss[0 ])
查看序列中index为: Index([2018-06-28, 2018-06-29, 2018-07-02, 2018-07-03, 2018-07-04, 2018-07-05,
2018-07-06, 2018-07-09, 2018-07-10, 2018-07-11],
dtype='object')
查看序列中index为a的元素: 8.92
1 2 3 4 5 6 print('原序列:\n' ,ss) print() ss[0 ] = 11.4 print() print('修改后的序列:\n' ,ss)
原序列:
2018-06-28 8.92
2018-06-29 9.09
2018-07-02 8.61
2018-07-03 8.67
2018-07-04 8.61
2018-07-05 8.60
2018-07-06 8.66
2018-07-09 9.03
2018-07-10 8.98
2018-07-11 8.78
dtype: float64
修改后的序列:
2018-06-28 11.40
2018-06-29 9.09
2018-07-02 8.61
2018-07-03 8.67
2018-07-04 8.61
2018-07-05 8.60
2018-07-06 8.66
2018-07-09 9.03
2018-07-10 8.98
2018-07-11 8.78
dtype: float64
1 2 3 4 5 6 7 ss1 = pd.Series(np.random.randn(10 )) print('原序列:\n' ,ss) print() print('新序列:\n' ,ss1) print() print('序列相加:\n' ,pd.Series(ss.values+ss1.values,index=ss.index))
原序列:
2018-06-28 11.40
2018-06-29 9.09
2018-07-02 8.61
2018-07-03 8.67
2018-07-04 8.61
2018-07-05 8.60
2018-07-06 8.66
2018-07-09 9.03
2018-07-10 8.98
2018-07-11 8.78
dtype: float64
新序列:
0 -0.955700
1 0.391561
2 0.002435
3 -0.131621
4 -0.791321
5 0.841264
6 -0.058034
7 -0.486677
8 0.708875
9 1.841834
dtype: float64
序列相加:
2018-06-28 10.444300
2018-06-29 9.481561
2018-07-02 8.612435
2018-07-03 8.538379
2018-07-04 7.818679
2018-07-05 9.441264
2018-07-06 8.601966
2018-07-09 8.543323
2018-07-10 9.688875
2018-07-11 10.621834
dtype: float64
二、DataFrame DataFrame是一个二维数组结构,可以存入任一种Python数据类型(integers, strings, floating point numbers, Python objects, 等等)。 DataFrame由三部分 构成,一个是行索引index,一个是列名,另一个则是取值。
2.1 DataFrame的生成 1 2 3 4 5 6 print('由字典来产生数据框' ) data = {'state' : ['Ohio' , 'Ohio' , 'Ohio' , 'Nevada' , 'Nevada' ], 'year' : [2000 , 2001 , 2002 , 2001 , 2002 ], 'pop' : [1.5 , 1.7 , 3.6 , 2.4 , 2.9 ]} frame = pd.DataFrame(data) frame
由字典来产生数据框
state
year
pop
0
Ohio
2000
1.5
1
Ohio
2001
1.7
2
Ohio
2002
3.6
3
Nevada
2001
2.4
4
Nevada
2002
2.9
1 2 3 4 5 6 print('由列表来产生数据框' ) data = [['Ohio' , 'Ohio' , 'Ohio' , 'Nevada' , 'Nevada' ], [2000 , 2001 , 2002 , 2001 , 2002 ], [1.5 , 1.7 , 3.6 , 2.4 , 2.9 ]] frame = pd.DataFrame(data,index=['state' ,'year' ,'pop' ]).T frame
由列表来产生数据框
state
year
pop
0
Ohio
2000
1.5
1
Ohio
2001
1.7
2
Ohio
2002
3.6
3
Nevada
2001
2.4
4
Nevada
2002
2.9
2.2 DataFrame的基本性质 我们取一段金融时间序列给大家做更具体的分析:
1 2 list2 = w.wsd("000300.SH" , "open,high,low,close" , "2018-06-28" , "2018-07-10" , "" ) list2
.ErrorCode=0
.Codes=[000300.SH]
.Fields=[OPEN,HIGH,LOW,CLOSE]
.Times=[20180628,20180629,20180702,20180703,20180704,20180705,20180706,20180709,20180710]
.Data=[[3434.9441,3431.9619,3504.4571,3410.4767,3398.7788,3365.5547,3347.0624,3378.9056,3464.9064],[3477.0565,3512.3834,3506.8996,3422.0398,3418.3311,3398.4852,3396.2458,3459.3153,3474.1396],[3416.9476,3425.2159,3383.5006,3319.2889,3359.0861,3330.7113,3295.7296,3378.9056,3437.2706],[3423.5255,3510.9845,3407.9638,3409.2801,3363.7473,3342.4379,3365.1227,3459.1837,3467.5155]]
1 2 3 df = pd.DataFrame(list2.Data,columns=list2.Times,index=list2.Fields) df = df.T df
OPEN
HIGH
LOW
CLOSE
2018-06-28
3434.9441
3477.0565
3416.9476
3423.5255
2018-06-29
3431.9619
3512.3834
3425.2159
3510.9845
2018-07-02
3504.4571
3506.8996
3383.5006
3407.9638
2018-07-03
3410.4767
3422.0398
3319.2889
3409.2801
2018-07-04
3398.7788
3418.3311
3359.0861
3363.7473
2018-07-05
3365.5547
3398.4852
3330.7113
3342.4379
2018-07-06
3347.0624
3396.2458
3295.7296
3365.1227
2018-07-09
3378.9056
3459.3153
3378.9056
3459.1837
2018-07-10
3464.9064
3474.1396
3437.2706
3467.5155
1 2 3 4 5 6 7 8 9 10 print('首先查看数据框的形状' ,df.shape) print() print('查看数据框的头部:' ) print(df.head()) print() print('查看数据框的尾部:' ) print(df.tail()) print() print('查看数据框的索引index' ) print(df.index)
首先查看数据框的形状 (9, 4)
查看数据框的头部:
OPEN HIGH LOW CLOSE
2018-06-28 3434.9441 3477.0565 3416.9476 3423.5255
2018-06-29 3431.9619 3512.3834 3425.2159 3510.9845
2018-07-02 3504.4571 3506.8996 3383.5006 3407.9638
2018-07-03 3410.4767 3422.0398 3319.2889 3409.2801
2018-07-04 3398.7788 3418.3311 3359.0861 3363.7473
查看数据框的尾部:
OPEN HIGH LOW CLOSE
2018-07-04 3398.7788 3418.3311 3359.0861 3363.7473
2018-07-05 3365.5547 3398.4852 3330.7113 3342.4379
2018-07-06 3347.0624 3396.2458 3295.7296 3365.1227
2018-07-09 3378.9056 3459.3153 3378.9056 3459.1837
2018-07-10 3464.9064 3474.1396 3437.2706 3467.5155
查看数据框的索引index
Index([2018-06-28, 2018-06-29, 2018-07-02, 2018-07-03, 2018-07-04, 2018-07-05,
2018-07-06, 2018-07-09, 2018-07-10],
dtype='object')
1 2 3 4 5 6 7 8 print('查看数据框的列名' ) print(df.columns) print() print('查看数据框的值,其格式为数组array' ) print(df.values) print() print('查看数据框的基础描述性统计' ) print(df.describe())
查看数据框的列名
Index(['OPEN', 'HIGH', 'LOW', 'CLOSE'], dtype='object')
查看数据框的值,其格式为数组array
[[3434.9441 3477.0565 3416.9476 3423.5255]
[3431.9619 3512.3834 3425.2159 3510.9845]
[3504.4571 3506.8996 3383.5006 3407.9638]
[3410.4767 3422.0398 3319.2889 3409.2801]
[3398.7788 3418.3311 3359.0861 3363.7473]
[3365.5547 3398.4852 3330.7113 3342.4379]
[3347.0624 3396.2458 3295.7296 3365.1227]
[3378.9056 3459.3153 3378.9056 3459.1837]
[3464.9064 3474.1396 3437.2706 3467.5155]]
查看数据框的基础描述性统计
OPEN HIGH LOW CLOSE
count 9.000000 9.000000 9.000000 9.000000
mean 3415.227522 3451.655144 3371.850689 3416.640111
std 49.780741 44.488942 49.698315 55.264867
min 3347.062400 3396.245800 3295.729600 3342.437900
25% 3378.905600 3418.331100 3330.711300 3365.122700
50% 3410.476700 3459.315300 3378.905600 3409.280100
75% 3434.944100 3477.056500 3416.947600 3459.183700
max 3504.457100 3512.383400 3437.270600 3510.984500
1 2 3 df['名称' ] = ['HS300' ] * len(df) df
OPEN
HIGH
LOW
CLOSE
名称
2018-06-28
3434.9441
3477.0565
3416.9476
3423.5255
HS300
2018-06-29
3431.9619
3512.3834
3425.2159
3510.9845
HS300
2018-07-02
3504.4571
3506.8996
3383.5006
3407.9638
HS300
2018-07-03
3410.4767
3422.0398
3319.2889
3409.2801
HS300
2018-07-04
3398.7788
3418.3311
3359.0861
3363.7473
HS300
2018-07-05
3365.5547
3398.4852
3330.7113
3342.4379
HS300
2018-07-06
3347.0624
3396.2458
3295.7296
3365.1227
HS300
2018-07-09
3378.9056
3459.3153
3378.9056
3459.1837
HS300
2018-07-10
3464.9064
3474.1396
3437.2706
3467.5155
HS300
2018-06-28
2018-06-29
2018-07-02
2018-07-03
2018-07-04
2018-07-05
2018-07-06
2018-07-09
2018-07-10
OPEN
3434.94
3431.96
3504.46
3410.48
3398.78
3365.55
3347.06
3378.91
3464.91
HIGH
3477.06
3512.38
3506.9
3422.04
3418.33
3398.49
3396.25
3459.32
3474.14
LOW
3416.95
3425.22
3383.5
3319.29
3359.09
3330.71
3295.73
3378.91
3437.27
CLOSE
3423.53
3510.98
3407.96
3409.28
3363.75
3342.44
3365.12
3459.18
3467.52
名称
HS300
HS300
HS300
HS300
HS300
HS300
HS300
HS300
HS300
2.3 DataFrame截取 2.3.1 行截取 氦核:不推荐使用ix进行截取,因为ix既可以对名称截取,又可以索引截取。如果index是整数,会很迷惑。一般使用loc和iloc函数。
1 2 3 4 5 print('查看df索引为1的行——方法一' ) print(df.ix[1 ]) print() print('查看df前3行' ) print(df[:3 ])
查看df索引为1的行——方法一
OPEN 3431.96
HIGH 3512.38
LOW 3425.22
CLOSE 3510.98
名称 HS300
Name: 2018-06-29, dtype: object
查看df前3行
OPEN HIGH LOW CLOSE 名称
2018-06-28 3434.9441 3477.0565 3416.9476 3423.5255 HS300
2018-06-29 3431.9619 3512.3834 3425.2159 3510.9845 HS300
2018-07-02 3504.4571 3506.8996 3383.5006 3407.9638 HS300
D:\anaconda\lib\site-packages\ipykernel_launcher.py:2: FutureWarning:
.ix is deprecated. Please use
.loc for label based indexing or
.iloc for positional indexing
See the documentation here:
http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#ix-indexer-is-deprecated
2.3.2 列截取 1 2 3 4 5 print('df的一列选取' ) print(df['OPEN' ]) print() print('df的两列同时选取' ) print(df[['OPEN' ,'LOW' ]])
df的一列选取
2018-06-28 3434.9441
2018-06-29 3431.9619
2018-07-02 3504.4571
2018-07-03 3410.4767
2018-07-04 3398.7788
2018-07-05 3365.5547
2018-07-06 3347.0624
2018-07-09 3378.9056
2018-07-10 3464.9064
Name: OPEN, dtype: float64
df的两列同时选取
OPEN LOW
2018-06-28 3434.9441 3416.9476
2018-06-29 3431.9619 3425.2159
2018-07-02 3504.4571 3383.5006
2018-07-03 3410.4767 3319.2889
2018-07-04 3398.7788 3359.0861
2018-07-05 3365.5547 3330.7113
2018-07-06 3347.0624 3295.7296
2018-07-09 3378.9056 3378.9056
2018-07-10 3464.9064 3437.2706
2.3.3 DataFrame行列同时截取 1 2 print('截取df的前4行的close和low列' ) df.ix[:4 ,['CLOSE' ,'LOW' ]]
截取df的前4行的close和low列
D:\anaconda\lib\site-packages\ipykernel_launcher.py:2: FutureWarning:
.ix is deprecated. Please use
.loc for label based indexing or
.iloc for positional indexing
See the documentation here:
http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#ix-indexer-is-deprecated
CLOSE
LOW
2018-06-28
3423.5255
3416.9476
2018-06-29
3510.9845
3425.2159
2018-07-02
3407.9638
3383.5006
2018-07-03
3409.2801
3319.2889
2.3.4 DataFrame条件截取 1 2 3 4 5 6 print('截取df CLOSE大于等于3500的记录' ) print(df[df['CLOSE' ]>=3500 ]) print('' ) print('截取df CLOSE大于3300且LOW小于3400的记录' ) print(df[(df['CLOSE' ]>3300 )&(df['LOW' ]<3400 )]) print('' )
截取df CLOSE大于等于3500的记录
OPEN HIGH LOW CLOSE 名称
2018-06-29 3431.9619 3512.3834 3425.2159 3510.9845 HS300
截取df CLOSE大于3300且LOW小于3400的记录
OPEN HIGH LOW CLOSE 名称
2018-07-02 3504.4571 3506.8996 3383.5006 3407.9638 HS300
2018-07-03 3410.4767 3422.0398 3319.2889 3409.2801 HS300
2018-07-04 3398.7788 3418.3311 3359.0861 3363.7473 HS300
2018-07-05 3365.5547 3398.4852 3330.7113 3342.4379 HS300
2018-07-06 3347.0624 3396.2458 3295.7296 3365.1227 HS300
2018-07-09 3378.9056 3459.3153 3378.9056 3459.1837 HS300
2.4 DataFrame缺失值处理 例如下面这个数据框data,其中就存在缺失值
1 2 3 4 5 6 7 data = {'state' : ['Ohio' , 'Ohio' , 'Ohio' , 'Nevada' , 'Nevada' ], 'year' : [2000 , 2001 , 2002 , 2001 , 2002 ], 'pop' : [1.5 , 1.7 , 3.6 , 2.4 , 2.9 ]} data = pd.DataFrame(data) data.loc[1 ,'pop' ] = np.NaN data.loc[3 ,'state' ] = None data
state
year
pop
0
Ohio
2000
1.5
1
Ohio
2001
NaN
2
Ohio
2002
3.6
3
None
2001
2.4
4
Nevada
2002
2.9
state
year
pop
0
Ohio
2000
1.5
2
Ohio
2002
3.6
4
Nevada
2002
2.9
state
year
pop
0
Ohio
2000
1.5
1
Ohio
2001
NaN
2
Ohio
2002
3.6
3
None
2001
2.4
4
Nevada
2002
2.9
1 2 data.dropna(how="all" , axis=1 )
state
year
pop
0
Ohio
2000
1.5
1
Ohio
2001
NaN
2
Ohio
2002
3.6
3
None
2001
2.4
4
Nevada
2002
2.9
1 2 data.dropna(thresh=3 , axis=0 )
state
year
pop
0
Ohio
2000
1.5
2
Ohio
2002
3.6
4
Nevada
2002
2.9
1 2 data.dropna(thresh=3 , axis=1 )
state
year
pop
0
Ohio
2000
1.5
1
Ohio
2001
NaN
2
Ohio
2002
3.6
3
None
2001
2.4
4
Nevada
2002
2.9
state
year
pop
0
Ohio
2000
1.5
1
Ohio
2001
NaN
2
Ohio
2002
3.6
3
None
2001
2.4
4
Nevada
2002
2.9
1 2 print('用0填充数据框中的缺失值,0是可选参数之一' ) data.fillna(value=0 )
用0填充数据框中的缺失值,0是可选参数之一
state
year
pop
0
Ohio
2000
1.5
1
Ohio
2001
0.0
2
Ohio
2002
3.6
3
0
2001
2.4
4
Nevada
2002
2.9
1 2 data.fillna(method='ffill' )
state
year
pop
0
Ohio
2000
1.5
1
Ohio
2001
1.5
2
Ohio
2002
3.6
3
Ohio
2001
2.4
4
Nevada
2002
2.9
1 2 data.fillna(method="bfill" )
state
year
pop
0
Ohio
2000
1.5
1
Ohio
2001
3.6
2
Ohio
2002
3.6
3
Nevada
2001
2.4
4
Nevada
2002
2.9
氦核:这些填补都是什么鬼方法,无语。
2.5 DataFrame排序
OPEN
HIGH
LOW
CLOSE
名称
2018-06-28
3434.9441
3477.0565
3416.9476
3423.5255
HS300
2018-06-29
3431.9619
3512.3834
3425.2159
3510.9845
HS300
2018-07-02
3504.4571
3506.8996
3383.5006
3407.9638
HS300
2018-07-03
3410.4767
3422.0398
3319.2889
3409.2801
HS300
2018-07-04
3398.7788
3418.3311
3359.0861
3363.7473
HS300
2018-07-05
3365.5547
3398.4852
3330.7113
3342.4379
HS300
2018-07-06
3347.0624
3396.2458
3295.7296
3365.1227
HS300
2018-07-09
3378.9056
3459.3153
3378.9056
3459.1837
HS300
2018-07-10
3464.9064
3474.1396
3437.2706
3467.5155
HS300
1 2 print('df按列OPEN降序排序' ) df.sort_values('OPEN' )
df按列OPEN降序排序
OPEN
HIGH
LOW
CLOSE
名称
2018-07-06
3347.0624
3396.2458
3295.7296
3365.1227
HS300
2018-07-05
3365.5547
3398.4852
3330.7113
3342.4379
HS300
2018-07-09
3378.9056
3459.3153
3378.9056
3459.1837
HS300
2018-07-04
3398.7788
3418.3311
3359.0861
3363.7473
HS300
2018-07-03
3410.4767
3422.0398
3319.2889
3409.2801
HS300
2018-06-29
3431.9619
3512.3834
3425.2159
3510.9845
HS300
2018-06-28
3434.9441
3477.0565
3416.9476
3423.5255
HS300
2018-07-10
3464.9064
3474.1396
3437.2706
3467.5155
HS300
2018-07-02
3504.4571
3506.8996
3383.5006
3407.9638
HS300
1 2 print('df按列LOW升序排序' ) df.sort_values('LOW' ,ascending=True )
df按列LOW升序排序
OPEN
HIGH
LOW
CLOSE
名称
2018-07-06
3347.0624
3396.2458
3295.7296
3365.1227
HS300
2018-07-03
3410.4767
3422.0398
3319.2889
3409.2801
HS300
2018-07-05
3365.5547
3398.4852
3330.7113
3342.4379
HS300
2018-07-04
3398.7788
3418.3311
3359.0861
3363.7473
HS300
2018-07-09
3378.9056
3459.3153
3378.9056
3459.1837
HS300
2018-07-02
3504.4571
3506.8996
3383.5006
3407.9638
HS300
2018-06-28
3434.9441
3477.0565
3416.9476
3423.5255
HS300
2018-06-29
3431.9619
3512.3834
3425.2159
3510.9845
HS300
2018-07-10
3464.9064
3474.1396
3437.2706
3467.5155
HS300
2.6 DataFrame的基本函数 1 2 print('按列求均值' ) df.mean()
按列求均值
OPEN 3415.227522
HIGH 3451.655144
LOW 3371.850689
CLOSE 3416.640111
dtype: float64
1 2 print('按行求均值' ) df.mean(axis=1 )
按行求均值
2018-06-28 3438.118425
2018-06-29 3470.136425
2018-07-02 3450.705275
2018-07-03 3390.271375
2018-07-04 3384.985825
2018-07-05 3359.297275
2018-07-06 3351.040125
2018-07-09 3419.077550
2018-07-10 3460.958025
dtype: float64
函数汇总 下面的函数都是通过数据框.函数名(参数设置)来进行调用,一般的参数是axis=0/1,选择为0则是按行来实现函数,1则是按列来实现函数
序号
函数
函数含义
1
count
计数非na值
2
describe
针对Series或个DataFrame列基本描述统计
3
min、max
计算最小值和最大值
4
argmin、argmax
获取到最大值和最小值的索引位置(整数)
5
idxmin、idxmax
计算能够获取到最大值和最小值得索引值
6
quantile
计算样本的分位数(0到1)
7
sum
求和
8
mean
求平均数
9
median
求中位数(50%分位数)
10
mad
计算平均绝对离差
11
var
样本方差
12
std
样本标准差
13
skew
样本偏度(三阶矩)
14
kurt
样本峰度(四阶矩)
15
cumsum
样本累计和
16
cummin,cummax
样本累计最大值和累计最小值
17
cumprod
样本累计积
18
diff
计算一阶差分
19
pct_change
计算百分数变化
20
corr
计数相关性
2.7 DataFrame拼接 下面介绍了三个函数来实现 DataFrame的拼接功能——concat函数,merge函数和join函数
2.7.1 DataFrame拼接—pd.concat 通过Wind API可以获取到各种金融数据,可以使用代码生成器生成获取数据的函数代码。获取到数据后,可参考一下代码将数据转换为DataFrame格式
1 2 3 4 5 6 7 8 from WindPy import *from pandas import DataFrame w.start() wsd_data = w.wsd("000001.SZ" , "lastradeday_s,sec_name,open,high,low,close" , "2017-11-01" , "2017-11-05" , "" ) data_df = DataFrame(wsd_data.Data,columns=wsd_data.Times,index=wsd_data.Fields) data_df = data_df.T data_df
LASTRADEDAY_S
SEC_NAME
OPEN
HIGH
LOW
CLOSE
2017-11-01
2017-11-01
平安银行
11.56
11.59
11.32
11.4
2017-11-02
2017-11-02
平安银行
11.36
11.58
11.26
11.54
2017-11-03
2017-11-03
平安银行
11.49
11.68
11.35
11.39
1 2 3 4 wsd_data1 = w.wsd("000002.SZ" , "lastradeday_s,sec_name,open,high,low,close" , "2017-11-01" , "2017-11-05" , "" ) data_df1 = DataFrame(wsd_data1.Data,columns=wsd_data.Times,index=wsd_data.Fields) data_df1 = data_df1.T data_df1
LASTRADEDAY_S
SEC_NAME
OPEN
HIGH
LOW
CLOSE
2017-11-01
2017-11-01
万科A
28.96
30.54
28.73
29.15
2017-11-02
2017-11-02
万科A
29.3
29.48
28.68
29.45
2017-11-03
2017-11-03
万科A
29.23
29.52
28.05
28.19
1 2 print('按行拼接' ) pd.concat([data_df,data_df1],axis=0 )
按行拼接
LASTRADEDAY_S
SEC_NAME
OPEN
HIGH
LOW
CLOSE
2017-11-01
2017-11-01
平安银行
11.56
11.59
11.32
11.4
2017-11-02
2017-11-02
平安银行
11.36
11.58
11.26
11.54
2017-11-03
2017-11-03
平安银行
11.49
11.68
11.35
11.39
2017-11-01
2017-11-01
万科A
28.96
30.54
28.73
29.15
2017-11-02
2017-11-02
万科A
29.3
29.48
28.68
29.45
2017-11-03
2017-11-03
万科A
29.23
29.52
28.05
28.19
1 2 print('按列拼接' ) pd.concat([data_df,data_df1],axis=1 )
按列拼接
LASTRADEDAY_S
SEC_NAME
OPEN
HIGH
LOW
CLOSE
LASTRADEDAY_S
SEC_NAME
OPEN
HIGH
LOW
CLOSE
2017-11-01
2017-11-01
平安银行
11.56
11.59
11.32
11.4
2017-11-01
万科A
28.96
30.54
28.73
29.15
2017-11-02
2017-11-02
平安银行
11.36
11.58
11.26
11.54
2017-11-02
万科A
29.3
29.48
28.68
29.45
2017-11-03
2017-11-03
平安银行
11.49
11.68
11.35
11.39
2017-11-03
万科A
29.23
29.52
28.05
28.19
2.7.3 DataFrame拼接—pd.merge pd.merge一般针对的是按列合并。
pd.merge(left, right, how=’inner’, on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=True, suffixes=(‘_x’, ‘_y’), copy=True, indicator=False)
left: 一个dataframe对象
right: 另一个dataframe对象
how: 可以是’left’, ‘right’, ‘outer’, ‘inner’. 默认为inner。
on: 列名,两个dataframe都有的列。如果不传参数,而且left_index和right_index也等于False,则默认把两者交叉/共有的列作为链接键(join keys)。可以是一个列名,也可以是包含多个列名的list。
left_on: 左边dataframe的列会用做keys。可以是列名,或者与dataframe长度相同的矩阵array。
right_on: 右边同上。
left_index: 如果为Ture,用左侧dataframe的index作为连接键。如果是多维索引,level数要跟右边相同才行。
right_index: 右边同上。
sort: 对合并后的数据框排序,以连接键。
suffixes: 一个tuple,包字符串后缀,用来加在重叠的列名后面。默认是(‘_x’,’_y’)。
copy: 默认Ture,复制数据。
indicator: 布尔型(True/FALSE),或是字符串。如果为True,合并之后会增加一列叫做_merge。是分类数据,用left_only, right_only, both来标记来自左边,右边和两边的数据。
参考:http://www.jianshu.com/p/dc8ba1c0eada
希望将上面两个 DataFrame left_data和right_data拼接起来,但要求是按照时间来进行拼接
1 2 print('按LASTRADEDAY_S拼接,只保留共同的部分' ) pd.merge(data_df,data_df1,on='LASTRADEDAY_S' )
按LASTRADEDAY_S拼接,只保留共同的部分
LASTRADEDAY_S
SEC_NAME_x
OPEN_x
HIGH_x
LOW_x
CLOSE_x
SEC_NAME_y
OPEN_y
HIGH_y
LOW_y
CLOSE_y
0
2017-11-01
平安银行
11.56
11.59
11.32
11.4
万科A
28.96
30.54
28.73
29.15
1
2017-11-02
平安银行
11.36
11.58
11.26
11.54
万科A
29.3
29.48
28.68
29.45
2
2017-11-03
平安银行
11.49
11.68
11.35
11.39
万科A
29.23
29.52
28.05
28.19
1 2 print('按LASTRADEDAY_S拼接,但所有的数据都保留下来' ) pd.merge(data_df,data_df1,on='LASTRADEDAY_S' ,how='outer' )
按LASTRADEDAY_S拼接,但所有的数据都保留下来
LASTRADEDAY_S
SEC_NAME_x
OPEN_x
HIGH_x
LOW_x
CLOSE_x
SEC_NAME_y
OPEN_y
HIGH_y
LOW_y
CLOSE_y
0
2017-11-01
平安银行
11.56
11.59
11.32
11.4
万科A
28.96
30.54
28.73
29.15
1
2017-11-02
平安银行
11.36
11.58
11.26
11.54
万科A
29.3
29.48
28.68
29.45
2
2017-11-03
平安银行
11.49
11.68
11.35
11.39
万科A
29.23
29.52
28.05
28.19
1 2 print('LASTRADEDAY_S,但所有的数据都保留下来,且生成一列来表示数据的来源' ) pd.merge(data_df,data_df1,on='LASTRADEDAY_S' ,how='outer' ,indicator='数据来源' )
LASTRADEDAY_S,但所有的数据都保留下来,且生成一列来表示数据的来源
LASTRADEDAY_S
SEC_NAME_x
OPEN_x
HIGH_x
LOW_x
CLOSE_x
SEC_NAME_y
OPEN_y
HIGH_y
LOW_y
CLOSE_y
数据来源
0
2017-11-01
平安银行
11.56
11.59
11.32
11.4
万科A
28.96
30.54
28.73
29.15
both
1
2017-11-02
平安银行
11.36
11.58
11.26
11.54
万科A
29.3
29.48
28.68
29.45
both
2
2017-11-03
平安银行
11.49
11.68
11.35
11.39
万科A
29.23
29.52
28.05
28.19
both
2.7.4 DataFrame拼接—.join DataFrame.join(other, on=None, how=’left’, lsuffix=’’, rsuffix=’’, sort=False)
other:一个DataFrame、Series(要有命名),或者DataFrame组成的list。
on:列名,包含列名的list或tuple,或矩阵样子的列 (如果是多列,必须有MultiIndex)。 跟上面的几种方法一样,用来指明依据哪一列进行合并。 如果没有赋值,则依据两个数据框的index合并。
how:合并方式, {‘left’, ‘right’, ‘outer’, ‘inner’}, 默认‘left‘。
lsuffix:字符串。用于左侧数据框的重复列。 把重复列重新命名,原来的列名+字符串。 【如果有重复列,必须添加这个参数。】
rsuffix:同上。右侧。
sort:布尔型,默认False。如果为True,将链接键(on的那列)按字母排序。
参考:http://www.jianshu.com/p/dc8ba1c0eada
1 2 print('注意到两个拼接的数据框,含有相同的列LASTRADEDAY_S,故重新命名了这两个列' ) data_df.join(data_df1,lsuffix='_left' ,rsuffix='_right' )
注意到两个拼接的数据框,含有相同的列LASTRADEDAY_S,故重新命名了这两个列
LASTRADEDAY_S_left
SEC_NAME_left
OPEN_left
HIGH_left
LOW_left
CLOSE_left
LASTRADEDAY_S_right
SEC_NAME_right
OPEN_right
HIGH_right
LOW_right
CLOSE_right
2017-11-01
2017-11-01
平安银行
11.56
11.59
11.32
11.4
2017-11-01
万科A
28.96
30.54
28.73
29.15
2017-11-02
2017-11-02
平安银行
11.36
11.58
11.26
11.54
2017-11-02
万科A
29.3
29.48
28.68
29.45
2017-11-03
2017-11-03
平安银行
11.49
11.68
11.35
11.39
2017-11-03
万科A
29.23
29.52
28.05
28.19
2.8 DataFrame重复值剔除 有时候,希望能够剔除掉DataFrame中的重复记录。
1 2 3 error_code,df3 = w.wsd("000001.SZ" , "fa_eps_basic" , "2017-08-07" , "2017-08-15" , "Days=Alldays;currencyType=" ,usedf=True ) df3
FA_EPS_BASIC
2017-08-07
0.31
2017-08-08
0.31
2017-08-09
0.31
2017-08-10
0.31
2017-08-11
0.68
2017-08-12
0.68
2017-08-13
0.68
2017-08-14
0.68
2017-08-15
0.68
1 2 print('查看DataFrame中是否存在重复记录,标记为True的为重复记录' ) df3.duplicated()
查看DataFrame中是否存在重复记录,标记为True的为重复记录
2017-08-07 False
2017-08-08 True
2017-08-09 True
2017-08-10 True
2017-08-11 False
2017-08-12 True
2017-08-13 True
2017-08-14 True
2017-08-15 True
dtype: bool
1 2 print('剔除数据框中的重复记录' ) df3.drop_duplicates()
剔除数据框中的重复记录
FA_EPS_BASIC
2017-08-07
0.31
2017-08-11
0.68
2.9 DataFrame分组及透视表(groupby) 2.9.1 分组——groupby函数 氦核:这个函数很厉害。下面列几个用法:
1.根据DataFrame本身的某一列或多列内容进行分组聚合。
2.还可以利用for循环,对分组进行迭代。(下面举了个小栗子)
for name,group in df.groupby('key1'):
print(name)
print(group)
若仅使用一个变量name,会影响输出结果的索引层次表达方式,且结果为元组。
3.对聚合后的数据片段,进行格式类型转化
4.利用groupby,根据dtypes对列进行分组,此时,需指定axis=1
,否则,groupby默认根据axis=0
进行分组,而行数据由于类型不统一,故无法根据dtypes对列进行分组。
*#将聚合后df转化为字典格式,后根据df的数据类型对列进行分组*
grouped=df.groupby(df.dtypes,axis=1) dict(list(grouped))
我们设定,如果当天收益率大于0,我们标记为up,反之为down。把收盘价大于11的标记为good,反之为bad。正式举例。
1 2 3 4 5 6 7 8 from WindPy import *w.start() error_code,df4 = w.wsd("000001.SZ" , "open,close,pct_chg" , "2018-04-20" , "2018-04-30" , "" ,usedf=True ) df4['standard' ] = df4.PCT_CHG.apply(lambda x: 'up' if x > 0 else 'down' ) df4['expression' ] = df4.CLOSE.apply(lambda x: 'good' if x > 11 else 'bad' ) df4
OPEN
CLOSE
PCT_CHG
standard
expression
2018-04-20
11.51
11.35
-1.046207
down
good
2018-04-23
11.30
11.57
1.938326
up
good
2018-04-24
11.63
11.86
2.506482
up
good
2018-04-25
11.76
11.68
-1.517707
down
good
2018-04-26
11.66
11.42
-2.226027
down
good
2018-04-27
11.49
10.85
-4.991243
down
bad
1 2 grouped = df4['CLOSE' ].groupby(df4['standard' ]) grouped
<pandas.core.groupby.generic.SeriesGroupBy object at 0x0000020B26C63648>
氦核:上面这行是聚合后不适用配合函数的输出。
这是由于变量grouped是一个GroupBy对象,它实际上还没有进行任何计算,只是含有一些有关分组键df[‘key1’]
的中间数据而已,然后我们可以调用配合函数(如:.mean()方法)来计算分组平均值等。 因此,一般为方便起见可直接在聚合之后+“配合函数” ,默认情况下,所有数值列都将会被聚合,虽然有时可能会被过滤为一个子集。 一般,如果对df直接聚合时,df.groupby([df['key1'],df['key2']]).mean()
(分组键为:Series)与df.groupby(['key1','key2']).mean()
(分组键为:列名)是等价的,输出结果相同。 但是,如果对df的指定列进行聚合时,df['data1'].groupby(df['key1']).mean()
(分组键为:Series),唯一方式。 此时,直接使用“列名”作分组键,提示“Error Key”。 注意:分组键中的任何缺失值都会被排除在结果之外。
参考groupby用法博客链接
standard
down 11.325
up 11.715
Name: CLOSE, dtype: float64
1 2 means = df4['CLOSE' ].groupby([df4['standard' ],df4['expression' ]]).mean() means
standard expression
down bad 10.850000
good 11.483333
up good 11.715000
Name: CLOSE, dtype: float64
对两个键进行了分组,得到的Series具有一个层次化索引。
expression
bad
good
standard
down
10.85
11.483333
up
NaN
11.715000
你还可以将列名用作分组键。
1 df4.groupby('standard' ).mean()
OPEN
CLOSE
PCT_CHG
standard
down
11.605
11.325
-2.445296
up
11.465
11.715
2.222404
1 df4.groupby([df4['standard' ],df4['expression' ]]).mean()
OPEN
CLOSE
PCT_CHG
standard
expression
down
bad
11.490000
10.850000
-4.991243
good
11.643333
11.483333
-1.596647
up
good
11.465000
11.715000
2.222404
我们还可以用size方法,返回一个含有分组大小的Series。
1 df4.groupby(['standard' ,'expression' ]).size()
standard expression
down bad 1
good 3
up good 2
dtype: int64
2.9.2 对分组进行迭代 GroupBy对象支持迭代,可以产生一组二元元组。
1 2 3 for name,group in df4.groupby('standard' ): print(name) print(group)
down
OPEN CLOSE PCT_CHG standard expression
2018-04-20 11.51 11.35 -1.046207 down good
2018-04-25 11.76 11.68 -1.517707 down good
2018-04-26 11.66 11.42 -2.226027 down good
2018-04-27 11.49 10.85 -4.991243 down bad
up
OPEN CLOSE PCT_CHG standard expression
2018-04-23 11.30 11.57 1.938326 up good
2018-04-24 11.63 11.86 2.506482 up good
对于多重组件 的情况,元素的第一个元素将会是有键值组成的元组:
1 2 3 for (k1,k2), group in df4.groupby(['standard' ,'expression' ]): print(k1,k2) print(group)
down bad
OPEN CLOSE PCT_CHG standard expression
2018-04-27 11.49 10.85 -4.991243 down bad
down good
OPEN CLOSE PCT_CHG standard expression
2018-04-20 11.51 11.35 -1.046207 down good
2018-04-25 11.76 11.68 -1.517707 down good
2018-04-26 11.66 11.42 -2.226027 down good
up good
OPEN CLOSE PCT_CHG standard expression
2018-04-23 11.30 11.57 1.938326 up good
2018-04-24 11.63 11.86 2.506482 up good
当然,你可以对这些数据片段做任何操作。将这些数据片段做成一个字典:
1 2 pieces = dict(list(df4.groupby('standard' ))) pieces
{'down': OPEN CLOSE PCT_CHG standard expression
2018-04-20 11.51 11.35 -1.046207 down good
2018-04-25 11.76 11.68 -1.517707 down good
2018-04-26 11.66 11.42 -2.226027 down good
2018-04-27 11.49 10.85 -4.991243 down bad,
'up': OPEN CLOSE PCT_CHG standard expression
2018-04-23 11.30 11.57 1.938326 up good
2018-04-24 11.63 11.86 2.506482 up good}
groupby默认是在axis=0
上进行分组的。通过设置也可以对其他任何轴上进行分组。比如我们可以根据dtype对列进行分组:
OPEN float64
CLOSE float64
PCT_CHG float64
standard object
expression object
dtype: object
1 2 grouped = df4.groupby(df4.dtypes,axis=1 ) dict(list(grouped))
{dtype('float64'): OPEN CLOSE PCT_CHG
2018-04-20 11.51 11.35 -1.046207
2018-04-23 11.30 11.57 1.938326
2018-04-24 11.63 11.86 2.506482
2018-04-25 11.76 11.68 -1.517707
2018-04-26 11.66 11.42 -2.226027
2018-04-27 11.49 10.85 -4.991243, dtype('O'): standard expression
2018-04-20 down good
2018-04-23 up good
2018-04-24 up good
2018-04-25 down good
2018-04-26 down good
2018-04-27 down bad}
2.9.3 选取一个或一组列 1 df4.groupby(['standard' ,'expression' ])[['CLOSE' ]].mean()
氦核:再加一个中括号。
CLOSE
standard
expression
down
bad
10.850000
good
11.483333
up
good
11.715000
或者是以分组的Series:
1 2 s_grouped = df4.groupby(['standard' ,'expression' ])['CLOSE' ] s_grouped.mean()
standard expression
down bad 10.850000
good 11.483333
up good 11.715000
Name: CLOSE, dtype: float64
2.9.4 通过字典或者Series进行分组 除数组以外,分组信息还可以以其他形式存在。我们新构建一个DataFrame。
1 2 error_code,df_wss = w.wss("000001.SZ,000088.SZ,002626.SZ,600021.SH,600036.SH" , "open,high,low,volume,amt,pct_chg" , "tradeDate=2018-05-29;priceAdj=1;cycle=1" ,usedf=True ) df_wss
OPEN
HIGH
LOW
VOLUME
AMT
PCT_CHG
000001.SZ
10.58
10.63
10.35
88949497.0
9.303870e+08
-1.983003
000088.SZ
7.65
7.79
7.61
9731389.0
7.493758e+07
-0.260756
002626.SZ
19.13
19.72
18.97
7058799.0
1.367769e+08
-0.679561
600021.SH
8.15
8.20
8.10
2065681.0
1.685831e+07
-0.368098
600036.SH
28.65
28.98
28.41
48053415.0
1.376605e+09
0.486111
1 2 3 df_wss.ix[2 :3 , ['OPEN' ,'HIGH' ]] = np.nan df_wss
D:\anaconda\lib\site-packages\ipykernel_launcher.py:2: FutureWarning:
.ix is deprecated. Please use
.loc for label based indexing or
.iloc for positional indexing
See the documentation here:
http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#ix-indexer-is-deprecated
氦核:依然不建议使用ix。
OPEN
HIGH
LOW
VOLUME
AMT
PCT_CHG
000001.SZ
10.58
10.63
10.35
88949497.0
9.303870e+08
-1.983003
000088.SZ
7.65
7.79
7.61
9731389.0
7.493758e+07
-0.260756
002626.SZ
NaN
NaN
18.97
7058799.0
1.367769e+08
-0.679561
600021.SH
8.15
8.20
8.10
2065681.0
1.685831e+07
-0.368098
600036.SH
28.65
28.98
28.41
48053415.0
1.376605e+09
0.486111
假设已知列的分组关系,并希望根据分组计算列的总和:
1 mapping = {'OPEN' :'r' ,'HIGH' :'r' ,'LOW' :'b' ,'VOLUME' :'b' ,'AMT' :'b' ,'PCT_CHG' :'o' }
只需要将这个字典传给groupby即可:(行方向)
1 2 by_colum = df_wss.groupby(mapping,axis=1 ) by_colum.sum()
b
o
r
000001.SZ
1.019336e+09
-1.983003
21.21
000088.SZ
8.466897e+07
-0.260756
15.44
002626.SZ
1.438358e+08
-0.679561
0.00
600021.SH
1.892400e+07
-0.368098
16.35
600036.SH
1.424658e+09
0.486111
57.63
Series也有这样的功能。
1 2 map_series = pd.Series(mapping) map_series
OPEN r
HIGH r
LOW b
VOLUME b
AMT b
PCT_CHG o
dtype: object
1 df_wss.groupby(map_series,axis=1 ).count()
b
o
r
000001.SZ
3
1
2
000088.SZ
3
1
2
002626.SZ
3
1
0
600021.SH
3
1
2
600036.SH
3
1
2
2.9.5 根据索引级别分组 层次化索引数据最方便的地方就是在于它能够根据索引级别进行聚合。要实现该目的,通过level关键字传入级别编号或名称即可:
OPEN
HIGH
LOW
VOLUME
AMT
PCT_CHG
000001.SZ
10.58
10.63
10.35
88949497.0
9.303870e+08
-1.983003
000088.SZ
7.65
7.79
7.61
9731389.0
7.493758e+07
-0.260756
002626.SZ
NaN
NaN
18.97
7058799.0
1.367769e+08
-0.679561
600021.SH
8.15
8.20
8.10
2065681.0
1.685831e+07
-0.368098
600036.SH
28.65
28.98
28.41
48053415.0
1.376605e+09
0.486111
1 2 3 4 columns = pd.MultiIndex.from_arrays([['行情' ,'行情' ,'行情' ,'量' ,'量' ,'幅度' ], ['OPEN' ,'HIGH' ,'LOW' ,'VOLUME' ,'AMT' ,'PCT_CHG' ]],names=['s1' ,'s2' ]) hier_df = pd.DataFrame(df_wss.values, columns=columns,index=df_wss.index) hier_df
s1
行情
量
幅度
s2
OPEN
HIGH
LOW
VOLUME
AMT
PCT_CHG
000001.SZ
10.58
10.63
10.35
88949497.0
9.303870e+08
-1.983003
000088.SZ
7.65
7.79
7.61
9731389.0
7.493758e+07
-0.260756
002626.SZ
NaN
NaN
18.97
7058799.0
1.367769e+08
-0.679561
600021.SH
8.15
8.20
8.10
2065681.0
1.685831e+07
-0.368098
600036.SH
28.65
28.98
28.41
48053415.0
1.376605e+09
0.486111
1 hier_df.groupby(level='s1' ,axis=1 ).count()
s1
幅度
行情
量
000001.SZ
1
3
2
000088.SZ
1
3
2
002626.SZ
1
1
2
600021.SH
1
3
2
600036.SH
1
3
2
(完)
依然鸣谢:某大哥假粉。愿四下空虚的灵魂皆能得以慰藉。
本文链接:
https://konelane.github.io/2020/02/06/200206pandaslearning/
-- EOF --
转载请注明出处 署名-非商业性使用-禁止演绎 3.0 国际(CC BY-NC-ND 3.0)