python联萌|pandas(国宝库

目录

最后编辑于:2020.02.06 18:00

Pandas库

Pandas是基于NumPy 的一种工具,其出现是为了解决数据分析任务。(氦核:个人觉得更像是探索工具,没有模型,简单分析。)
Pandas吸纳了大量库和一些标准的数据模型,提供了高效操作大型数据集所需的工具。
Pandas中的函数和方法能够使我们快速便捷地处理数据。
它是使Python成为强大而高效的数据分析环境的重要因素之一。

http://pandas.pydata.org/pandas-docs/stable/api.html

本文参考万旷网教程

1
2
3
# 首先导入pandas库
import numpy as np
import 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
# 可以通过index来查看序列Series中的元素
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
# 基于index 可以修改序列s中的元素
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()
# 大多数numpy的函数可以直接应用于 序列 Series
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
1
2
# 数据框的转置
df.T
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(df.iloc[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
1
2
#删除含有缺失的行
data.dropna()
state year pop
0 Ohio 2000 1.5
2 Ohio 2002 3.6
4 Nevada 2002 2.9
1
2
#表示该行都为缺失的行才删除 注意是这一行中的每一个元素都为缺失才删除这一行
data.dropna(how="all")
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
#表示保留至少存在3个非NaN的行,即如果某一行的非缺失值个数小于3个,则会被删除
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
#表示保留至少存在3个非NaN的列,即如果某一列的非缺失值个数小于3个,则会被删除
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
1
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
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
#填充缺失值 用缺失值所在列的前一个非NaN值来进行填充  
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
#用缺失值所在列的后一个非NaN来填充
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排序

1
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
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()

# 先取一个金融时间序列,以DataFrame的形式
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用法博客链接

1
grouped.mean()
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具有一个层次化索引。

1
means.unstack()
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对列进行分组:

1
df4.dtypes
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']前后再多加一组[]即可

氦核:再加一个中括号。

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
# 添加几个空值NAN
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关键字传入级别编号或名称即可:

1
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 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 --

¥^¥请氦核牛饮一盒奶~suki