刺猬教你量化投资(七):数据处理进阶

Posted by 刺猬偷腥 on October 13, 2017

数据处理进阶知识

  1. 按组分类后统计频数

先用groupby()函数分组,然后带count()函数,即可求出该组的频数值,比如:

In [1]:
import pandas as pd
df=pd.DataFrame({'num':['one','two','three','one'],'values':['2','3','2','5']})
df.groupby('num').count()
Out[1]:
       values
 num	
one  	2
three	1
two	    1

也可以直接对某列进行value_counts():

In [2]:
import pandas as pd
df=pd.DataFrame({'num':['one','two','three','one'],'values':['2','3','2','5']})
print df.num.value_counts()
print '*'*30
#或者写成df['num'].value_counts()也行
print df['num'].value_counts()

one      2
three    1
two      1
Name: num, dtype: int64
******************************
one      2
three    1
two      1
Name: num, dtype: int64

2.获得累计求和值

累计求和英文是cumulative sum, 只需在计算频数后加上.cumsum(),即可得出答案:

In [3]:
import pandas as pd
df=pd.DataFrame({'num':['one','two','three','one'],'values':['2','3','2','5']})
print df.num.value_counts()
print '*'*30
#或者写成df['num'].value_counts()
print df['num'].value_counts().cumsum()
one      2
three    1
two      1
Name: num, dtype: int64
******************************
one      2
three    3
two      4
Name: num, dtype: int64

3.数据透视表

创建透视表的格式是df.pivot_table(index='',columns='',values='',aggfunc=)

In [4]:
import pandas as pd
df=pd.DataFrame({'num':['one','two','three','one'],'values':[2,3,2,5]})
df['cat']=['little cat','fat cat','little cat','my cat']
df['cat label']=[20,38,27,56]
print df
print "*"*30
print df.pivot_table(index='cat') #以cat列为索引,并尝试找出具有相同值的行的规律,默认是找平均数
​
     num  values         cat  cat label
0    one       2  little cat         20
1    two       3     fat cat         38
2  three       2  little cat         27
3    one       5      my cat         56
******************************
            cat label  values
cat                          
fat cat          38.0       3
little cat       23.5       2
my cat           56.0       5

除了求平均值,我们还可以通过定义aggfunc来实现不同的目的,比如计算频数:

In[5]:
print df
print "*"*30
print df.pivot_table(index='cat',aggfunc='count')  
​
     num  values         cat  cat label
0    one       2  little cat         20
1    two       3     fat cat         38
2  three       2  little cat         27
3    one       5      my cat         56
******************************
            cat label  num  values
cat                               
fat cat             1    1       1
little cat          2    2       2
my cat              1    1       1

实际运用中,数据表往往有很多列,我们若只想显示某一列,则可用values参数来进行定义:

In[6]:
print df
print "*"*30
df.pivot_table(index='cat',aggfunc=len,values='num') 
#len表示计数
#以cat列为索引,并找出num列的计数值
​
     num  values         cat  cat label
0    one       2  little cat         20
1    two       3     fat cat         38
2  three       2  little cat         27
3    one       5      my cat         56
******************************
Out[33]:
cat
fat cat       1
little cat    2
my cat        1
Name: num, dtype: int64

在透视表函数中,参数还可指定多列:

In[7]:
print df
print "*"*30
df.pivot_table(index='cat',aggfunc=[np.mean,len],values=['num','cat label']) 
#len表示计数
#以cat列为索引,并找出num列的计数值
​
     num  values         cat  cat label
0    one       2  little cat         20
1    two       3     fat cat         38
2  three       2  little cat         27
3    one       5      my cat         56
******************************
Out[7]:

In[8]: 透视数据表可同时求多个函数

index也可以有多个,按顺序进行分组计数:

print df
print "*"*30
df.pivot_table(index=['cat','num'],aggfunc=[np.mean,len],values=['num','cat label']) 
#len表示计数
#以cat列为索引,然后再以num为索引,对每一行的数据先求均值再求长度
​

     num  values         cat  cat label
0    one       2  little cat         20
1    two       3     fat cat         38
2  three       2  little cat         27
3    one       5      my cat         56

Out[8]:

按部就班地求

两个索引同时看有点不好看,那么可以同时制定索引和列名,换种方式呈现结果:

In[9]:
print df
print "*"*30
df.pivot_table(index=['cat'],columns=['num'],aggfunc=[np.mean],values=['num','cat label']) 
#len表示计数
#以cat列为索引,以num的values为打横的列名,然后计算相对应的mean值
#若没结果,则填入空值
​
     num  values         cat  cat label
0    one       2  little cat         20
1    two       3     fat cat         38
2  three       2  little cat         27
3    one       5      my cat         56
******************************

表格变简单了

若需对空值进行填充,则可加上fill_value参数,比如

df.pivot_table(index=['cat'],columns=['num'],aggfunc=[np.mean],values=['num','cat label'],fill_value='0') 
#将空值替换成数字0

大功告成

再进一步,求每列数值占当列数值总额的百分比:

In [10]:
print df1
df1.apply(lambda x:(x/x.sum())*100) #默认按列求和
#如果要按行相处,则加入axis=1即可
#df1.apply(lambda x:(x/x.sum())*100,axis='columns') 
#计算每个值占当列的百分比
             mean                              
           values           cat label          
num           one three two       one three two
cat                                            
fat cat         0     0   3         0     0  38
little cat      2     2   0        20    27   0
my cat          5     0   0        56     0   0

Out[10]:

计算结果

若要在df下面新增一行来显示结果,则可以用df.loc['your cat']=来实现:

In [11]:
print df1
df1.loc['sum']=df1.apply(lambda x:x.sum()) #新增一行显示计算结果
df1
       values  cat label
num                     
one         2         20
two         3         38
three       2         27
one         5         56
Out[11]:
    values	cat label
num		
one	    2	20
two	    3	38
three	2	27
one	    5	56
sum    	12	141
  1. index的相关处理

set_index()后,如果想返回初始的状态,则可用reset_index(),如果本身就是初始状态,用了reset_index()后,会多了一个index_0作为列。

若是set_index后,不想显示index的名字而导致多了一个空白行,则可用’df.index.name=None’来使其消失。

还可以用reindex()函数,对数据集的索引进行重新编制,用其他数据集的索引,用原数据集的数据,一一配对,没有数据的地方以空值填充:

In [12]:
df_index=pd.date_range('10/10/2017',periods=5,freq='D')
df1=pd.DataFrame({'cash':[100,30,np.nan,32,199]},index=df_index)
print df1
df_index1=pd.date_range('10/10/2017',periods=8,freq='2D')
df1.reindex(df_index1)
            cash
2017-10-10   100
2017-10-11    30
2017-10-12   NaN
2017-10-13    32
2017-10-14   199
Out[12]:
            cash
2017-10-10	100
2017-10-12	NaN
2017-10-14	199
2017-10-16	NaN
2017-10-18	NaN
2017-10-20	NaN
2017-10-22	NaN
2017-10-24	NaN
  1. 设定数据集的布局

先创建一个df:

In [13]:
df=pd.DataFrame(np.arange(0,12).reshape((3,4)),index=['1','2','3'],columns=['a','b','c','d'])
print df
df1=pd.melt(df,id_vars=['b']) #对df数据集按变量b重新布局,显示出当变量b为某个值时,其他变量对应的values是什么
#改变布局后,只显示两列数据
df1
   a  b   c   d
1  0  1   2   3
2  4  5   6   7
3  8  9  10  11

Out[13]:

重新布局后的结果

实际运用中,可设id_vars=交易日期,然后就得出两列数据,股票代码和收盘价。

In [14]:
df1=pd.melt(df,id_vars=['b'],value_vars=['c'])
df1
Out[14]:
    b	variable	value
0	1	c	2
1	5	c	6
2	9	c	10

变回去也行,用pivot_table()即可:

In [14]:
df1=pd.melt(df,id_vars=['a'])
print df1
df1.pivot_table(index='a',columns='variable',values='value')  #pivot_table是melt的反面
​
   a variable  value
0  0        b      1
1  4        b      5
2  8        b      9
3  0        c      2
4  4        c      6
5  8        c     10
6  0        d      3
7  4        d      7
8  8        d     11
Out[14]:
variable	b	c	d
a			
0	1	2	3
4	5	6	7
8	9	10	11

要把这个a消掉,加个reset_index()即可。

  1. 类别设置

以学生考试成绩打分为例,将不同分值的结果赋予定性的判断:

In [15]:
import pandas as pd
import numpy as np
df=pd.DataFrame({'student':['one','two','three','four'],'marks':[55,79,73,62],'raw_grade':['c','a','a','b']})
df['grade']=df['raw_grade'].astype('category') #新增一列,内容是marks的values,但类别为分类
df.set_index('student')
print df['grade']
df['grade'].cat.categories=['good','just so so','bad'] #分别对应a\b\c, cat是category的意思
df['grade']
​
0    c
1    a
2    a
3    b
Name: grade, dtype: category
Categories (3, object): [a, b, c]
Out[15]:
0           bad
1          good
2          good
3    just so so
Name: grade, dtype: category
Categories (3, object): [good, just so so, bad]
  1. 链接两个df

假如有两个df表,他们某个列有相同的values,则可以进行合并,进行对应填充:

In [16]:
import pandas as pd
import numpy as np
df1=pd.DataFrame({'animal':['dog','cat','cat','cow','dog'],'price':[55,79,73,62,40],'grade':['c','a','c','b','d']})
df2=pd.DataFrame({'animals':['dog','cat','cow'],'weight':[553,792,731]})
print df1
print df2
df=pd.merge(df1,df2,how='inner',left_on='animal',right_on='animals') #方式用内部合并,左边显示animal的数据,右边显示animals的数据,对应填充。
df
  animal grade  price
0    dog     c     55
1    cat     a     79
2    cat     c     73
3    cow     b     62
4    dog     d     40
  animals  weight
0     dog     553
1     cat     792
2     cow     731

Out[16]:

df合并后的结果

还有另外一种方法,就是将index设为一致,然后再合并,比如:

In [17]:
import pandas as pd
import numpy as np
df1=pd.DataFrame({'animal':['dog','cat','cat','cow','dog'],'price':[55,79,73,62,40],'grade':['c','a','c','b','d']})
df2=pd.DataFrame({'animals':['dog','cat','cow'],'weight':[553,792,731]})
print '*'*30
print df1
print '*'*30
print df2
print '*'*30
one=df1.set_index('animal')
two=df2.set_index('animals')
print one
print '*'*30
print two
print '*'*30
print two.reindex(one.index)
print '*'*30
one['weight']=two.reindex(one.index)  #新增一列的内容就是tworeindex后的value,填充过去了
print one
******************************
  animal grade  price
0    dog     c     55
1    cat     a     79
2    cat     c     73
3    cow     b     62
4    dog     d     40
******************************
  animals  weight
0     dog     553
1     cat     792
2     cow     731
******************************
       grade  price
animal             
dog        c     55
cat        a     79
cat        c     73
cow        b     62
dog        d     40
******************************
         weight
animals        
dog         553
cat         792
cow         731
******************************
        weight
animal        
dog        553
cat        792
cat        792
cow        731
dog        553
******************************
       grade  price  weight
animal                     
dog        c     55     553
cat        a     79     792
cat        c     73     792
cow        b     62     731
dog        d     40     553
  1. isnull()的补充

前面提到如何使用isnull()函数去判断数据表中是否有空值:

In[18]:
print df
print df.isnull()*1
print np.sum(df.isnull()*1,axis=0) #axis=0意味着按列相加,axis=1意味着按行相加
np.sum(df.isnull()*1,axis=1) !=0
   one  two  three
a    1    1      2
b    2    2      4
c    3    3      6
d  NaN    4    NaN
   one  two  three
a    0    0      0
b    0    0      0
c    0    0      0
d    1    0      1
one      1
two      0
three    1
dtype: int64
Out[18]:
a    False
b    False
c    False
d     True
dtype: bool

加上any参数,如isnull().any(axis=1),即可判断每一行是否有空值,返回布尔值。不定义axis,则默认按列检查。

9.改变数据类型

astype()可以改变数据类型,对于数据表中的某行某列,可以改变类型后再赋予自己,比如:df['a','b']=df['a','b'].astype(float)

结语

至此,我们已掌握了Python的基本知识。下一章我们将学习金融建模中的excel函数,敬请期待。



刺猬偷腥
2017年10月13日

***
to be continued.