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

数据处理进阶知识

  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.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容