5.1 pandas 数据结构介绍

为了入门pandas,你需要熟悉两个常用的工具数据结构:series和dataframe。

5.1 Series

Series是一种一维的数组型对象,它包含了一个值序列(与Numpy中的类型相似),并且包含了数据标签,称为索引(index)。最简单的序列可以仅仅由一个数组形成:

In [1]: import pandas as pd

In [2]: import numpy as np

In [3]: obj = pd.Series([4,7,-5,3])

In [4]: obj
Out[4]: 
0    4
1    7
2   -5
3    3
dtype: int64

交互式环境中Series的字符串表示,索引在左边,值在右边。由于我们不为数据指定索引,默认生成的索引是从0到N-1(N是数据的长度)。你可以通过values属性和index属性分别获得Series对象的值和索引:
In [5]: obj.values
Out[5]: array([ 4,  7, -5,  3])

In [6]: obj.index # 类似于range(4)
Out[6]: RangeIndex(start=0, stop=4, step=1) # 开始是0,停止是4,步进为1

通常需要创建一个索引序列,用标签标识每个数据点:
In [7]: obj2 = pd.Series([4,7,-5,3],index=['d','v','a','c'])

In [8]: obj2
Out[8]: 
d    4
v    7
a   -5
c    3
dtype: int64

In [11]: obj2.index
Out[11]: Index(['d', 'v', 'a', 'c'], dtype='object')

与numpy的数组相比,你可以在从数据中选择数据的时候使用标签来进行索引:
In [14]: obj2['a']
Out[14]: -5

In [15]: obj2['v']
Out[15]: 7

In [16]: obj2[['c','a','d']]
Out[16]: 
c    3
a   -5
d    4
dtype: int64

上面的例子中,['c','a','d']包含的不是数字而是字符串,作为索引列表。

使用numpy的函数或者numpy风格的操作,比如使用布尔值数组进行过滤,与标量相乘,或是应用数学函数,这些操作将保存索引值连接:
In [17]: obj2[obj2>0]
Out[17]: 
d    4
v    7
c    3
dtype: int64

In [18]: obj2 *2
Out[18]: 
d     8
v    14
a   -10
c     6
dtype: int64

In [19]: np.exp(obj2)
Out[19]: 
d      54.598150
v    1096.633158
a       0.006738
c      20.085537
dtype: float64

从另一个角度考虑Series,可以认为它是一个长度固定且有序的字典,因为它将索引值和数据值按位置配对。在你可能会使用字典的上下文中,也可以使用series:
In [21]: 'a' in obj2
Out[21]: True

In [22]: 'e' in obj2
Out[22]: False

如果你已经有数据包含在Python字典中,你可以使用字典生成一个series:
In [23]: sdata = {'xiongwei':34,'yaowei':24,'tunwei':36}

In [24]: obj3 = pd.Series(sdata)

In [25]: obj3
Out[25]: 
xiongwei    34
yaowei      24
tunwei      36
dtype: int64

当你把字典传递给Series构造函数时,产生的Series的索引将是排序好的字典键。你可以将字典键按照你所想要的顺序传递给构造函数,从而使生成的Series的索引顺序符合你的预期:
In [26]: states = ['tunwei','yaowei','xiongwei']

In [27]: obj4 = pd.Series(sdata,index = states)

In [28]: obj4
Out[28]: 
tunwei      36
yaowei      24
xiongwei    34
dtype: int64

上面的例子中,sdata中的三个值被放置在正确的位置,如果输入的值没有出现在sdata的键中,它对应的值是NaN,这是pandas中标记缺失值或NA值的方式,它将被排除在结果对象外。

pandas中使用isnull和notnull函数来检查缺失数据:
In [31]: pd.isnull(obj4)
Out[31]: 
tunwei      False
yaowei      False
xiongwei    False
datui        True
dtype: bool

In [32]: pd.notnull(obj4)
Out[32]: 
tunwei       True
yaowei       True
xiongwei     True
datui       False
dtype: bool

Series对象自身和其索引都有name属性,这个特性与pandas其他重要功能集合在一起:
In [36]: obj4.name = 'pop'

In [37]: obj4.index.name = 'state'

In [38]: obj4
Out[38]: 
state
tunwei      36.0
yaowei      24.0
xiongwei    34.0
datui        NaN
Name: pop, dtype: float64

Series的索引可以通过按位置赋值的方式进行改变:
In [42]: obj = pd.Series([4,7,-5,3])

In [43]: obj
Out[43]: 
0    4
1    7
2   -5
3    3
dtype: int64

In [44]: obj.index = ['a','b','c','d']

In [45]: obj
Out[45]: 
a    4
b    7
c   -5
d    3
dtype: int64

5.1.2 DataFrame

DataFrame表示的是矩阵的数据表,它包含已排序的列集合,每一列可以是不同的值类型(数值、字符串、布尔值等)。DataFrame既有行索引也有列索引,它可以被视为一个共享相同索引的Series的字典。在DataFrame中,数据被存储为一个以上的二维块,而不是列表、字典或其他一维数组的集合。

有多重方式可以构建DataFrame,其中最常用的方式是利用包含等长度列表或numpy数组的字典来形成dataframe:
In [46]: data = {'piaoxiaomin':['34','24','36'],'jinxuanya':['34','23','34'],'quanzhixian':['34','24','34']}

In [47]: frame = pd.DataFrame(data)

In [48]: frame
Out[48]: 
  piaoxiaomin jinxuanya quanzhixian
0          34        34          34
1          24        23          24
2          36        34          34

对于大型DataFrame,head方法将会只选出头部的五行:
In [49]: frame.head()
Out[49]: 
  piaoxiaomin jinxuanya quanzhixian
0          34        34          34
1          24        23          24
2          36        34          34

如果你指定了列的顺序,DataFrame的列将会按照指定顺序排列:
In [50]: pd.DataFrame(data,columns=['quanzhixian','jinxuanya','piaoxiaomin'])
Out[50]: 
  quanzhixian jinxuanya piaoxiaomin
0          34        34          34
1          24        23          24
2          34        34          36

如果你传的列不包含在字典中,将会在结果中出现缺失值:
In [51]: frame2 = pd.DataFrame(data,columns=['jinxuanya','piaoxiaomin','qiamzjoxoam','jinzhenxi'],index = ['xiongwei','yaowei','tu
    ...: nwei'])

In [52]: frame2
Out[52]: 
         jinxuanya piaoxiaomin qiamzjoxoam jinzhenxi
xiongwei        34          34         NaN       NaN
yaowei          23          24         NaN       NaN
tunwei          34          36         NaN       NaN

DataFrame中的一列,可以按字典型标记或属性那样检索为Series:
In [53]: frame2['piaoxiaomin']
Out[53]: 
xiongwei    34
yaowei      24
tunwei      36
Name: piaoxiaomin, dtype: object

In [55]: frame2.jinxuanya
Out[55]: 
xiongwei    34
yaowei      23
tunwei      34
Name: jinxuanya, dtype: object

frame2[colunm]对于任意列名均有效,但是frame2.column只在列名是有效的Python变量名时有效。

请注意,返回的Series与原DataFrame有相同的索引,且Series的name属性也会被合理地设置。

行也可以通过位置或特殊属性loc进行选取:
In [56]: frame2.loc['xiongwei']
Out[56]: 
jinxuanya       34
piaoxiaomin     34
qiamzjoxoam    NaN
jinzhenxi      NaN
Name: xiongwei, dtype: object

列的引用是可以修改的,例如,空的‘datui’列可以复制为标量值或值数组:
In [60]: frame2['datui'] = 'baihuahua'

In [61]: frame2
Out[61]: 
         jinxuanya piaoxiaomin qiamzjoxoam jinzhenxi      datui
xiongwei        34          34         NaN       NaN  baihuahua
yaowei          23          24         NaN       NaN  baihuahua
tunwei          34          36         NaN       NaN  baihuahua


In [63]: frame2['datui'] = np.arange(3.)

In [64]: frame2
Out[64]: 
         jinxuanya piaoxiaomin qiamzjoxoam jinzhenxi  datui
xiongwei        34          34         NaN       NaN    0.0
yaowei          23          24         NaN       NaN    1.0
tunwei          34          36         NaN       NaN    2.0

当你将列表或数组赋值给一个列时,值的长度必须和DataFrame的长度相匹配。如果你将Series赋值给一列时,Series的索引将会按照DataFrame的索引重新排列,并在空缺的地方填充缺失值:
In [69]: val = pd.Series(['dahuahua1','baihuahua2'],index = ['xiongwei','tunwei'])

In [70]: frame2['datui'] = val

In [71]: frame2
Out[71]: 
         jinxuanya piaoxiaomin qiamzjoxoam jinzhenxi       datui
xiongwei        34          34         NaN       NaN   dahuahua1
yaowei          23          24         NaN       NaN         NaN
tunwei          34          36         NaN       NaN  baihuahua2

如果被赋值的列并不存在,则会生成一个新的列。del关键字可以像字典中那样对DataFrame删除列.

在del的例子中,我首先增加一列,这一列是布尔值,判断条件时xiongwei列是否为‘34’:
In [74]: frame2['nicebody'] = frame2.jinxuanya == '34'

In [75]: frame2
Out[75]: 
         jinxuanya piaoxiaomin qiamzjoxoam jinzhenxi       datui  nicebody
xiongwei        34          34         NaN       NaN   dahuahua1      True
yaowei          23          24         NaN       NaN         NaN     False
tunwei          34          36         NaN       NaN  baihuahua2      True

注意frame2['nicebody']可以创建新列,而frame2.nicebody不能创建新的列。

del方法可以用于移除之前新建的列:
In [77]: del frame2['nicebody']

In [78]: frame2
Out[78]: 
         jinxuanya piaoxiaomin qiamzjoxoam jinzhenxi       datui
xiongwei        34          34         NaN       NaN   dahuahua1
yaowei          23          24         NaN       NaN         NaN
tunwei          34          36         NaN       NaN  baihuahua2

从DataFrame中选取的列是数据的视图,而不是拷贝。因此,对Series的修改会映射到DataFrame中。如果需要复制,则应当显式地使用Series的copy方法。

另一种常用的数据形式是包含字典的嵌套字典:
In [80]: data = {'piaoxiaomin':{'xiongwei':'34','yaowei':'24','tunwei':'36'},'jinxuanya':{'xiongwei':'34','yaowei':'23','tunwei':'
    ...: 34'}}

如果嵌套字典被赋值给DataFrame,pandas会将字典的键作为列,将内部字典的键作为行索引:
In [81]: frame3 = pd.DataFrame(data)

In [82]: frame3
Out[82]: 
         piaoxiaomin jinxuanya
xiongwei          34        34
yaowei            24        23
tunwei            36        34

你可以将使用类似numpy的语法对DataFrame进行转置操作(调换行和列):
In [83]: frame3.T
Out[83]: 
            xiongwei yaowei tunwei
piaoxiaomin       34     24     36
jinxuanya         34     23     34

内部字典的键被联合、排序后形成了结果的索引。如果已经显式指明索引的话,内部字典的键将不会被排序:
In [86]: pd.DataFrame(data,index=['xiongwei','datui','tunwei'])
Out[86]: 
         piaoxiaomin jinxuanya
xiongwei          34        34
datui            NaN       NaN
tunwei            36        34

包含Series的字典也可以用于构造DataFrame:
In [87]: pdata = {'jinxuanya':frame3['jinxuanya'][:-1],'piaoxiaomin':frame3['jinxuanya'][:-2]}

In [88]: pd.DataFrame(pdata)
Out[88]: 
         jinxuanya piaoxiaomin
xiongwei        34          34
yaowei          23         NaN

如果DataFrame的索引和列拥有name属性,则这些name属性也会被显示:
In [105]: frame3.index.name = 'sanwei';frame3.columns.name='name'

In [106]: frame3
Out[106]: 
name     piaoxiaomin jinxuanya
sanwei                        
xiongwei          34        34
yaowei            24        23
tunwei            36        34

和Series类似,DataFrame的values属性会将包含在DataFrame中的数据以二维ndarray的形式返回:
In [107]: frame3.values
Out[107]: 
array([['34', '34'],
       ['24', '23'],
       ['36', '34']], dtype=object)

如果DataFrame的列是不同的dtypes,则values的dtype会自动选择适合所有列的类型:
In [108]: frame2.values
Out[108]: 
array([['34', '34', nan, nan, 'dahuahua1'],
       ['23', '24', nan, nan, nan],
       ['34', '36', nan, nan, 'baihuahua2']], dtype=object)

5.1.3 索引对象

pandas中的索引对象是用于存储轴标签和其他元数据的(例如轴名称或标签)。在构造Series或DataFrame时,你所使用的任意数组或标签序列都可以在内部转换为索引对象:

In [109]: obj = pd.Series(range(3),index=['a','b','c'])

In [110]: index = obj.index

In [111]: index
Out[111]: Index(['a', 'b', 'c'], dtype='object')

索引对象是不可变的,因此用户是无法修改索引对象的:
In [113]: index[1] = 'd'
--------------------------------------------------------------------------
TypeError: Index does not support mutable operations

不变性使得在多种数据结构中分享索引对象更加安全:
In [114]: labels = pd.Index(np.arange(3))

In [115]: labels
Out[115]: Int64Index([0, 1, 2], dtype='int64')

In [116]: obj2 = pd.Series([1.5,-2.5,0],index=labels)

In [117]: obj2
Out[117]: 
0    1.5
1   -2.5
2    0.0
dtype: float64

In [118]: obj2 is labels
Out[118]: False

一些用户并不经常利用索引对象提供的功能,但是因为一些操作会产生包含索引花数据的结果,理解索引如何工作还是很重要的。

除了类似数组,索引对象也像一个固定大小的集合:
In [119]: frame3
Out[119]: 
name     piaoxiaomin jinxuanya
sanwei                        
xiongwei          34        34
yaowei            24        23
tunwei            36        34

In [126]: frame3.columns
Out[126]: Index(['piaoxiaomin', 'jinxuanya'], dtype='object', name='name')

In [127]: 'piaoxiaomin'in frame3.columns
Out[127]: True

In [128]: 'jinzhenxi' in frame3.index
Out[128]: False

与Python集合不同,pandas索引对象可以包含重复标签:
In [129]: dup = pd.Index(['xiongwei','xiongwei','yaowei','tunwei'])

In [130]: dup
Out[130]: Index(['xiongwei', 'xiongwei', 'yaowei', 'tunwei'], dtype='object')

根据重复标签进行筛选,会选取所有重复标签对应的数据。

每个索引都有一些集合逻辑的方法和属性,这些方法和属性解决了关于它所包含的数据的其他常见问题。

5.2 基本功能

5.2.1 重建索引

reindex是pandas对象的重要方法,该方法用于创建一个符合新索引的新对象。考虑下面的例子:

In [132]: obj = pd.Series([4.5,7.2,-5.3,3.6],index=['a','b','c','d'])

In [133]: obj
Out[133]: 
a    4.5
b    7.2
c   -5.3
d    3.6
dtype: float64

Series调用reindex方法时,会将数据按照新的索引进行排列,如果某个索引值之前并不存在,则会引入缺失值:
In [134]: obj2 = obj.reindex(['a','b','c','d','e'])

In [135]: obj2
Out[135]: 
a    4.5
b    7.2
c   -5.3
d    3.6
e    NaN
dtype: float64

对于顺序数据,比如时间序列,在重建索引时可能会需要进行插值或填值。method可选参数允许我们使用诸如ffill等方法在重建索引时插值,ffill方法会将值前向填充:
In [137]: obj3 = pd.Series(['blue','red','yellow'],index=[0,2,4,])

In [138]: obj3
Out[138]: 
0      blue
2       red
4    yellow
dtype: object

In [139]: obj3.reindex(range(6),method='ffill')
Out[139]: 
0      blue
1      blue
2       red
3       red
4    yellow
5    yellow
dtype: object

ffill:用前一个非缺失值去填充该缺失值

在DataFrame中,reindex可以改变行索引、列索引,也可以同时改变二者。当仅传入一个序列时,结果中的行会重建索引:
In [141]: frame = pd.DataFrame(np.arange(9).reshape((3,3)),index=['a','b','c'],columns=['quanxiaosheng','piaoxiaomin','jinzhenxi']
     ...: )

In [142]: frame
Out[142]: 
   quanxiaosheng  piaoxiaomin  jinzhenxi
a              0            1          2
b              3            4          5
c              6            7          8

In [143]: frame2 = frame.reindex(['a','b','c','d'])

In [144]: frame2
Out[144]: 
   quanxiaosheng  piaoxiaomin  jinzhenxi
a            0.0          1.0        2.0
b            3.0          4.0        5.0
c            6.0          7.0        8.0
d            NaN          NaN        NaN

列可以使用columns关键字重建索引:
In [146]: states = ['jinxuanya','piaozhiyan','piaocaoe']

In [147]: frame.reindex(columns=states)
Out[147]: 
   jinxuanya  piaozhiyan  piaocaoe
a        NaN         NaN       NaN
b        NaN         NaN       NaN
c        NaN         NaN       NaN

我们更深入地探索时,你可以使用loc进行更为简洁的标签索引,许多用户更倾向于是用这种方式:
In [162]: states= ['quanxiaosheng','piaoxiaomin','jinzhenxi']

In [163]: frame.loc[['a','b','c'],states]
Out[163]: 
   quanxiaosheng  piaoxiaomin  jinzhenxi
a              0            1          2
b              3            4          5
c              6            7          8

这里有个小意外,根据书上的案例,frame.loc[[‘a’,’b’,’c’,’e’],states],是带有’e’的。生成之后呢,e的那行,就都是NaN(因为没有数据嘛)。但是这么做之后,ipython发出报错:

KeyError: "Passing list-likes to .loc or [] with any missing labels is no longer supported. The following labels were missing: Index(['d'], dtype='object'). See https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#deprecate-loc-reindex-listlike"

意思似乎是不再支持“缺少至少一个标签”的情况。

根据官方文本的解读,建议替代方案是:

In [171]: frame.reindex(['a','b','c','d'],states)
<ipython-input-171-dd639d5b1969>:1: FutureWarning: Interpreting call
        '.reindex(a, b)' as 
        '.reindex(index=a, columns=b)'.
Use named arguments to remove any ambiguity. In the future, using positional arguments for 'index' or 'columns' will raise a 'TypeError'.
  frame.reindex(['a','b','c','d'],states)
Out[171]: 
   quanxiaosheng  piaoxiaomin  jinzhenxi
a            0.0          1.0        2.0
b            3.0          4.0        5.0
c            6.0          7.0        8.0
d            NaN          NaN        NaN

5.2.2 轴向上删除条目

如果你已经拥有索引数组或不含条目的列表,在轴向上删除一个或更多的条目就非常容易,但这样需要一些数据操作和机核逻辑。drop方法会返回一个含有指示值或轴向上剔除值的新对象:

In [186]: obj = pd.Series(np.arange(5.),index=['a','b','c','d','e'])

In [187]: obj
Out[187]: 
a    0.0
b    1.0
c    2.0
d    3.0
e    4.0
dtype: float64

In [188]: new_obj = obj.drop('c')

In [189]: new_obj
Out[189]: 
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64

In [191]: obj.drop(['d','c'])
Out[191]: 
a    0.0
b    1.0
e    4.0
dtype: float64

在DataFrame中,索引值可以轴向上删除。为了表明这个特性,我们首先创建一个示例:
In [192]: data= pd.DataFrame(np.arange(16).reshape((4,4)),index=['quanxiaosheng','piaoxiaomin','jinxuanya','jinzhenxi'],columns=['
     ...: one','two','three','four'])

In [193]: data
Out[193]: 
               one  two  three  four
quanxiaosheng    0    1      2     3
piaoxiaomin      4    5      6     7
jinxuanya        8    9     10    11
jinzhenxi       12   13     14    15

在调用drop时使用标签序列会根据行标签删除值(0轴):
In [194]: data.drop(['jinxuanya','jinzhenxi'])
Out[194]: 
               one  two  three  four
quanxiaosheng    0    1      2     3
piaoxiaomin      4    5      6     7

你可以通过传递axis = 1或axis='columns'来从列中删除值:
In [195]: data.drop(['two','four'],axis='columns')
Out[195]: 
               one  three
quanxiaosheng    0      2
piaoxiaomin      4      6
jinxuanya        8     10
jinzhenxi       12     14

In [196]: data.drop(['two','four'],axis=1)
Out[196]: 
               one  three
quanxiaosheng    0      2
piaoxiaomin      4      6
jinxuanya        8     10
jinzhenxi       12     14

很多函数,例如drop,会修改Series或Datafarame的尺寸或形状,这些方法直接操作原对象而不返回新对象:
In [197]: obj.drop('c',inplace=True)

In [198]: obj
Out[198]: 
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64

请注意inplace属性,它会清除被删除的数据。
5.2.3 索引、选择与过滤
Series的索引(obj[...])与numpy数组索引的功能类似,只不过Series的索引值可以不仅仅是整数:
In [199]: obj = pd.Series(np.arange(4.),index=['a','b','c','d'])

In [200]: obj
Out[200]: 
a    0.0
b    1.0
c    2.0
d    3.0
dtype: float64

In [201]: obj['b']
Out[201]: 1.0

In [202]: obj[1]
Out[202]: 1.0

In [203]: obj[2:4]
Out[203]: 
c    2.0
d    3.0
dtype: float64

In [205]: obj[['a','b','c']]
Out[205]: 
a    0.0
b    1.0
c    2.0
dtype: float64

In [206]: obj[[1,3]]
Out[206]: 
b    1.0
d    3.0
dtype: float64

In [207]: obj[obj < 2]
Out[207]: 
a    0.0
b    1.0
dtype: float64

普通的Python切片中是不包含尾部的,Series的切片与之不同:
In [212]: obj['b':'c'] # 从索引值b到c,且包含c
Out[212]: 
b    1.0
c    2.0
dtype: float64

使用这些方法设值时会修改Series相应的部分:
In [213]: obj['b':'c'] = 5

In [214]: obj
Out[214]: 
a    0.0
b    5.0
c    5.0
d    3.0
dtype: float64

使用单独值或序列,可以从DataFrame中索引处一个或多个列:
In [216]: data= pd.DataFrame(np.arange(16).reshape((4,4)),index=['quanxiaosheng','piaoxiaomin','jinxuanya','jinzhenxi'],columns=['
     ...: one','two','three','four'])

In [217]: data
Out[217]: 
               one  two  three  four
quanxiaosheng    0    1      2     3
piaoxiaomin      4    5      6     7
jinxuanya        8    9     10    11
jinzhenxi       12   13     14    15

In [218]: data['two']
Out[218]: 
quanxiaosheng     1
piaoxiaomin       5
jinxuanya         9
jinzhenxi        13
Name: two, dtype: int64

In [219]: data[['three','one']]
Out[219]: 
               three  one
quanxiaosheng      2    0
piaoxiaomin        6    4
jinxuanya         10    8
jinzhenxi         14   12

这种索引方式也有特殊案例。首先,可以根据一个布尔值数组切片或选择数据:
In [221]: data[data['three']>5]
Out[221]: 
             one  two  three  four
piaoxiaomin    4    5      6     7
jinxuanya      8    9     10    11
jinzhenxi     12   13     14    15

行选择语法data[:2]非常方便。传递单个元素或一个列表到[]符号中可以选择列。

另一个用例是使用布尔值DataFrame进行索引,布尔值DataFrame可以是对标量值进行比较产生的:
In [222]: data < 5
Out[222]: 
                 one    two  three   four
quanxiaosheng   True   True   True   True
piaoxiaomin     True  False  False  False
jinxuanya      False  False  False  False
jinzhenxi      False  False  False  False

In [223]: data[data<5] = 0

In [224]: data
Out[224]: 
               one  two  three  four
quanxiaosheng    0    0      0     0
piaoxiaomin      0    5      6     7
jinxuanya        8    9     10    11
jinzhenxi       12   13     14    15

在这个特殊例子中,这种索引方式使得DataFrame在语法上更像Numpy的二维数组。

5.2.3.1 使用loc和iloc选择数据

针对DataFrame在行上的标签索引,我将介绍特殊的索引符号loc和iloc。他们允许你使用轴标签(loc)或整数标签(iloc)以numpy风格的语法从DataFrame中选出数组的行和列的子集。

In [225]: data.loc['quanxiaosheng',['one','four']]
Out[225]: 
one     0
four    0
Name: quanxiaosheng, dtype: int64

然后我们使用整数标签iloc进行类似的数据选择:
In [226]: data.iloc[2,[3,0,1]]
Out[226]: 
four    11
one      8
two      9
Name: jinxuanya, dtype: int64

In [227]: data.iloc[2]
Out[227]: 
one       8
two       9
three    10
four     11
Name: jinxuanya, dtype: int64

In [228]: data.iloc[[1,2],[3,0,1]]
Out[228]: 
             four  one  two
piaoxiaomin     7    0    5
jinxuanya      11    8    9

除了单个标签或标签列表之外,索引功能还可以用于切片:
In [231]: data.loc[:'jinxuanya','two']
Out[231]: 
quanxiaosheng    0
piaoxiaomin      5
jinxuanya        9
Name: two, dtype: int64

In [233]: data.iloc[:,:3][data.three > 5]
Out[233]: 
             one  two  three
piaoxiaomin    0    5      6
jinxuanya      8    9     10
jinzhenxi     12   13     14

因此,有多种方式可以选择、重排pandas对象中的数据。

这里我补充一下一张图,可能会帮助理解上述代码。

5.2.4 整数索引

在pandas对象使上用整数索引对新用户来说经常会产生歧义,这属于因为它和在列表、元组等Python内建数据结构上进行索引有些不同。例如,你可能认为下面的代码会产生错误:

In [240]: ser = pd.Series(np.arange(3.))

In [241]: ser
Out[241]: 
0    0.0
1    1.0
2    2.0
dtype: float64

In [244]: ser[-1]
--------------------------------------------------------------------------
KeyError: -1


在上面的例子中,pandas可以“回退”到整数索引,但是这也的方式难免会引起一些微小的错误。假设我们有一个索引,它包含了0、1、2,但是推断用户所需要的索引方式是很难的。

另一方面,对于非整数索引,则不会有潜在的歧义:
In [242]: ser2  = pd.Series(np.arange(3.),index = ['a','b','c'])

In [243]: ser2[-1]
Out[243]: 2.0

为了保持一致性,如果你有一个包含整数的轴索引,数据选择时请始终使用标准索引。

为了更精确地处理,可以使用loc(用于标签)或iloc(用于整数):
In [245]: ser[:1]
Out[245]: 
0    0.0
dtype: float64

In [246]: ser.loc[:1]
Out[246]: 
0    0.0
1    1.0
dtype: float64

In [247]: ser.iloc[:1]
Out[247]: 
0    0.0
dtype: float64

5.2.5 算术和数据对齐

不同索引的对象之间的算术行为是pandas提供给一些应用的一项重要特性。当你将对象相加时,如果存在某个索引对不相同,则返回结果的索引将是索引对的并集。对数据库用户来说,这个特性类似于索引标签的自动外链接。

In [251]: s1 = pd.Series([7.3,-2.5,3.4,1.5],index=['a','c','d','e'])

In [252]: s2 = pd.Series([-2.1,3.6,-1.5,4,3.1],index=['a','c','e','f','g'])

In [253]: s1
Out[253]: 
a    7.3
c   -2.5
d    3.4
e    1.5
dtype: float64

In [254]: s2
Out[254]: 
a   -2.1
c    3.6
e   -1.5
f    4.0
g    3.1
dtype: float64

将这些对象相加会产生:
In [255]: s1 + s2
Out[255]: 
a    5.2
c    1.1
d    NaN
e    0.0
f    NaN
g    NaN
dtype: float64

没有交接的标签位置上,内部数据对齐会产生缺失值。缺失值会在后续的算术操作上产生影响。在DataFrame的示例中,行和列上都会执行对齐:
In [256]: df1 = pd.DataFrame(np.arange(9.).reshape((3,3)),columns=list('bcd'),index=['quanxiaosheng','piaoxiaomin','jinzhenxi'])

In [257]: df2 = pd.DataFrame(np.arange(12.).reshape((4,3)),columns=list('bde'),index=['piaozhiyan','piaoxiaomin','jinzhenxi','piao
     ...: caoe'])

In [258]: df1
Out[258]: 
                 b    c    d
quanxiaosheng  0.0  1.0  2.0
piaoxiaomin    3.0  4.0  5.0
jinzhenxi      6.0  7.0  8.0

In [259]: df2
Out[259]: 
               b     d     e
piaozhiyan   0.0   1.0   2.0
piaoxiaomin  3.0   4.0   5.0
jinzhenxi    6.0   7.0   8.0
piaocaoe     9.0  10.0  11.0

将这些对象加在一起,返回一个DataFrame,它的索引、列是每个DataFrame的索引、列的并集。
In [260]: df1+df2
Out[260]: 
                  b   c     d   e
jinzhenxi      12.0 NaN  15.0 NaN
piaocaoe        NaN NaN   NaN NaN
piaoxiaomin     6.0 NaN   9.0 NaN
piaozhiyan      NaN NaN   NaN NaN
quanxiaosheng   NaN NaN   NaN NaN

由于'c'列和'e'列并不是两个dataframe共有的列,这两列中产生了缺失值。对于行标签不同的dataframe对象也是如此。

如果你将两个行或列完全不同的dataframe对象相加,结果将全部为空:
In [261]: df1 = pd.DataFrame({'A':[1,2]})

In [262]: df2 = pd.DataFrame({'B':[3,4]})

In [263]: df1
Out[263]: 
   A
0  1
1  2

In [264]: df2
Out[264]: 
   B
0  3
1  4

In [265]: df1 -df2
Out[265]: 
    A   B
0 NaN NaN
1 NaN NaN

5.2.5.1 使用填充值的算术方法

在两个不同的索引化对象之间进行算术操作时,你可能会想要使用特殊填充值,比如当轴标签在一个对象中存在,另一个对象中不存在时,你想将缺失值填充为0:

In [268]: df1 = pd.DataFrame(np.arange(12.).reshape((3,4)),columns=list('abcd'))

In [269]: df2 = pd.DataFrame(np.arange(20.).reshape((4,5)),columns=list('abcde'))

In [270]: df2.loc[1,'b'] = np.nan

In [271]: df1
Out[271]: 
     a    b     c     d
0  0.0  1.0   2.0   3.0
1  4.0  5.0   6.0   7.0
2  8.0  9.0  10.0  11.0

In [272]: df2
Out[272]: 
      a     b     c     d     e
0   0.0   1.0   2.0   3.0   4.0
1   5.0   NaN   7.0   8.0   9.0
2  10.0  11.0  12.0  13.0  14.0
3  15.0  16.0  17.0  18.0  19.0

将这些df添加到一起会导致一些不重叠的位置出现NA值:
In [273]: df1+df2
Out[273]: 
      a     b     c     d   e
0   0.0   2.0   4.0   6.0 NaN
1   9.0   NaN  13.0  15.0 NaN
2  18.0  20.0  22.0  24.0 NaN
3   NaN   NaN   NaN   NaN NaN

在df1上使用add方法,我将df2和一个fill_value作为参数传入:
In [274]: df1.add(df2,fill_value=0)
Out[274]: 
      a     b     c     d     e
0   0.0   2.0   4.0   6.0   4.0
1   9.0   5.0  13.0  15.0   9.0
2  18.0  20.0  22.0  24.0  14.0
3  15.0  16.0  17.0  18.0  19.0

书说至此,书上就没有关于上面这段代码的介绍了。那么add方法和fill_value参数到底干啥用的呢?

add方法:将对象作为一个整体加入到字典中。

fill_value参数:如果df1内的value=NaN,那么value等于fill_value,然后与df1中相同索引的value相加。所以上述代码的意思就是,首先先计算df2进入df1里会出现多少缺失值,如果碰到缺失值则赋值:df2的相同索引的值+0。

下图是Series和DataFrame的算术方法。这些方法中的每一个都有一个以r开头的副本,这些副本方法的参数是翻转的。因此下面两个语句的结果是等价的:
In [283]: 1 / df1
Out[283]: 
       a         b         c         d
0    inf  1.000000  0.500000  0.333333
1  0.250  0.200000  0.166667  0.142857
2  0.125  0.111111  0.100000  0.090909

In [284]: df1.rdiv(1)
Out[284]: 
       a         b         c         d
0    inf  1.000000  0.500000  0.333333
1  0.250  0.200000  0.166667  0.142857
2  0.125  0.111111  0.100000  0.090909

与此相关的一点,当对Series或DataFrame重建索引时,你也可以指定一个不同的填充值:

In [285]: df1.reindex(columns=df2.columns,fill_value=0)
Out[285]: 
     a    b     c     d  e
0  0.0  1.0   2.0   3.0  0
1  4.0  5.0   6.0   7.0  0
2  8.0  9.0  10.0  11.0  0

5.2.5.2 DataFrame和Series间的操作

DataFrame和Series间的算术操作与Numpy中不同维度数组见的操作类似。首先,在下面的生动示例中,考虑二维数组和其中一行之间的区别:

In [292]: arr = np.arange(12.).reshape((3,4))

In [293]: arr
Out[293]: 
array([[ 0.,  1.,  2.,  3.],
       [ 4.,  5.,  6.,  7.],
       [ 8.,  9., 10., 11.]])

In [294]: arr[0]
Out[294]: array([0., 1., 2., 3.])

In [295]: arr - arr[0]
Out[295]: 
array([[0., 0., 0., 0.],
       [4., 4., 4., 4.],
       [8., 8., 8., 8.]])

补充一下,这里是arr的每一行都减[0,1,2,3]

当我们从arr中减去arr[0]时,每一行都进行了操作。这就是所谓的广播机制。DataFrame和Series间的操作是类似的:
In [298]: frame = pd.DataFrame(np.arange(12.).reshape((4,3)),columns=list('bde'),index=['quanxiaosheng','piaoxiaomin','piaozhiyan'
     ...: ,'jinxuanya'])

In [299]: series = frame.iloc[0]

In [300]: frame
Out[300]: 
                 b     d     e
quanxiaosheng  0.0   1.0   2.0
piaoxiaomin    3.0   4.0   5.0
piaozhiyan     6.0   7.0   8.0
jinxuanya      9.0  10.0  11.0

In [301]: series
Out[301]: 
b    0.0
d    1.0
e    2.0
Name: quanxiaosheng, dtype: float64

默认情况下,dataframe和series的数学操作中会将series的索引和dataframe的列进行匹配,并广播到各行:
In [302]: frame - series
Out[302]: 
                 b    d    e
quanxiaosheng  0.0  0.0  0.0
piaoxiaomin    3.0  3.0  3.0
piaozhiyan     6.0  6.0  6.0
jinxuanya      9.0  9.0  9.0

如果一个索引值不在dataframe的列里,也不在series的索引中,则对象会重建索引并形成联合:
In [303]: series2 = pd.Series(range(3),index=['b','e','f'])

In [304]: frame + series2
Out[304]: 
                 b   d     e   f
quanxiaosheng  0.0 NaN   3.0 NaN
piaoxiaomin    3.0 NaN   6.0 NaN
piaozhiyan     6.0 NaN   9.0 NaN
jinxuanya      9.0 NaN  12.0 NaN

如果你想改为在列上进行广播,在行上匹配,你必须使用算术方法中的一种。
In [305]: series3 = frame['d']

In [306]: frame
Out[306]: 
                 b     d     e
quanxiaosheng  0.0   1.0   2.0
piaoxiaomin    3.0   4.0   5.0
piaozhiyan     6.0   7.0   8.0
jinxuanya      9.0  10.0  11.0

In [307]: series3
Out[307]: 
quanxiaosheng     1.0
piaoxiaomin       4.0
piaozhiyan        7.0
jinxuanya        10.0
Name: d, dtype: float64

In [308]: frame.sub(series3,axis='index')
Out[308]: 
                 b    d    e
quanxiaosheng -1.0  0.0  1.0
piaoxiaomin   -1.0  0.0  1.0
piaozhiyan    -1.0  0.0  1.0
jinxuanya     -1.0  0.0  1.0

你传递的axis值是匹配轴的。上面的示例中表示我们需要在dataframe的行索引上对行匹配(axis='index' 或 axis=0),并进行广播。

这里值得说一下,简单来说,就是把frame和series3对应的列,进行相减(frame – series3)。

5.2.6 函数应用和映射

Numpy的通用函数(逐元素数组方法)对pandas对象也有效:

In [310]: frame = pd.DataFrame(np.random.randn(4,3),columns=list('bde'),index=['quanxiaosheng','piaoxiaomin','piaozhiyan' ,'jinxua
     ...: nya'])

In [311]: frame
Out[311]: 
                      b         d         e
quanxiaosheng -1.776766 -1.222338 -0.338254
piaoxiaomin   -0.010509 -0.714661  1.071737
piaozhiyan     1.520708  0.440294 -1.095024
jinxuanya      0.918618 -1.093099 -1.342356

In [312]: np.abs(frame) # 取绝对值
Out[312]: 
                      b         d         e
quanxiaosheng  1.776766  1.222338  0.338254
piaoxiaomin    0.010509  0.714661  1.071737
piaozhiyan     1.520708  0.440294  1.095024
jinxuanya      0.918618  1.093099  1.342356

另一个常用的操作是将函数应用到一行或一列的一位数组上。dataframe的apply方法可以实现这个功能:
In [313]: f = lambda x :x.max() - x.min()

In [314]: frame.apply(f)
Out[314]: 
b    3.297474
d    1.662632
e    2.414093
dtype: float64

这里的函数f,可以计算series最大值和最小值的差,会被frame中的每一列调用一次。结果是一个以frame的列作为索引的series。

如果你传递axis = 'columns'给apply函数,函数将会被每行调用一次:
In [318]: frame.apply(f,axis='columns')
Out[318]: 
quanxiaosheng    1.438512
piaoxiaomin      1.786398
piaozhiyan       2.615732
jinxuanya        2.260974
dtype: float64

大部分最常用的数组统计(比如sum和mean)都是dataframe的方法,因此计算统计值时使用apply并不是必须的。

传递给apply的函数并不一定要返回一个标量值,也可以返回带有多个值的series:
In [319]: def f(x):
     ...:     return pd.Series([x.min(),x.max()],index=['min','max'])
     ...: 

In [320]: frame.apply(f)
Out[320]: 
            b         d         e
min -1.776766 -1.222338 -1.342356
max  1.520708  0.440294  1.071737

逐元素的Python函数也可以使用。假设你想要根据frame中的每个浮点数计算一个格式化字符串,可以使用applymap方法:
In [321]: format = lambda x: '%.2f' % x

In [322]: frame.applymap(format)
Out[322]: 
                   b      d      e
quanxiaosheng  -1.78  -1.22  -0.34
piaoxiaomin    -0.01  -0.71   1.07
piaozhiyan      1.52   0.44  -1.10
jinxuanya       0.92  -1.09  -1.34

使用applymap作为函数名是因为series有map方法,可以将一个逐元素的函数应用在series上:
In [323]: frame['e'].map(format)
Out[323]: 
quanxiaosheng    -0.34
piaoxiaomin       1.07
piaozhiyan       -1.10
jinxuanya        -1.34
Name: e, dtype: object

5.2.7 排序和排名

根据某些准则对数据集进行排序是另一个重要的内建操作。如需按行或列索引进行字典型排序,需要使用sort_index方法,该方法返回一个新的、排序好的对象:

In [325]: obj = pd.Series(range(4),index=['d','a','b','c'])

In [326]: obj.sort_index()
Out[326]: 
a    1
b    2
c    3
d    0
dtype: int64

在dataframe中,你可以在各个轴上按索引排序:
In [327]: frame = pd.DataFrame(np.arange(8).reshape((2,4)),index=['three','one'],columns=['d','a','b','c'])

In [328]: frame.sort_index()
Out[328]: 
       d  a  b  c
one    4  5  6  7
three  0  1  2  3

In [329]: frame.sort_index(axis=1)
Out[329]: 
       a  b  c  d
three  1  2  3  0
one    5  6  7  4

数据默认会升序排序,但是也可以按照降序排序:
In [332]: frame.sort_index(axis=1,ascending=False)
Out[332]: 
       d  c  b  a
three  0  3  2  1
one    4  7  6  5

如果要根据series的值进行排序,使用sort_values方法:
In [333]: obj = pd.Series([4,7,-3,2])

In [334]: obj
Out[334]: 
0    4
1    7
2   -3
3    2
dtype: int64

In [335]: obj.sort_values()
Out[335]: 
2   -3
3    2
0    4
1    7
dtype: int64

默认情况下,所有的缺失值都会被排序到series的尾部:
In [336]: obj = pd.Series([4,np.nan,7,np.nan,-3,2])

In [337]: obj.sort_values()
Out[337]: 
4   -3.0
5    2.0
0    4.0
2    7.0
1    NaN
3    NaN
dtype: float64

当对DataFrame排序时,你可以使用一列或多列作为排序键。为了实现这个功能,传递一个或多个列名给sort_values的可选参数by:
In [338]: frame = pd.DataFrame({'b':[4,7,-3,2],'a':[0,1,0,1]})

In [339]: frame
Out[339]: 
   b  a
0  4  0
1  7  1
2 -3  0
3  2  1

In [340]: frame.sort_values(by='b')
Out[340]: 
   b  a
2 -3  0
3  2  1
0  4  0
1  7  1

对多列排序时,传递列名的列表:
In [341]: frame.sort_values(by=['a','b'])
Out[341]: 
   b  a
2 -3  0
0  4  0
3  2  1
1  7  1

排名是指对数组从1到有效数据点总数分配名次的操作。series和datafeame的rank方法是实现排名的方法,默认情况下,rank通过将平均排名分配到每个组来打破平级关系:
In [342]: obj = pd.Series([7,-5,7,4,2,0,4])

In [343]: obj.rank()
Out[343]: 
0    6.5
1    1.0
2    6.5
3    4.5
4    3.0
5    2.0
6    4.5
dtype: float64

这里需要补充两个点:

1、首先我们要明确,这里的位置是指该数字在原来组合里的位置,比如组合里的-5,在rank后,显示位置是1.0。

2、6.5和4.5是怎么来的:[7,-5,7,4,2,0,4]这个序列,按从小到大排序应该是[-5,0,2,4,4,7,7]。但是有两个4和两个7。那怎么排序呢?很简单,按照排序好的逻辑,第6个位置和第七个位置都是7,那么就(6+7)/2=6.5,7这个数字排在6.5上。4.5也是同理。

排名也可以根据他们在数据中的观察顺序进行分配:
In [344]: obj.rank(method='first')
Out[344]: 
0    6.0
1    1.0
2    7.0
3    4.0
4    3.0
5    2.0
6    5.0

在上面的例子中,对条目0和2设置的名次为6和7,而不是之前的平均排名6.5,是因为在数据标签中标签0在标签2前面。

你可以按降序排名:
In [345]: obj.rank(ascending=False,method='max')
Out[345]: 
0    2.0
1    7.0
2    2.0
3    4.0
4    5.0
5    6.0
6    4.0
dtype: float64

下图是可用的平级关系打破方法列表:

DataFrame 可以对行或列计算排名:
In [346]: frame = pd.DataFrame({'b':[4.3,7,-3,2],'a':[0,1,0,1],'c':[-2,5,8,-2.5]})

In [347]: frame
Out[347]: 
     b  a    c
0  4.3  0 -2.0
1  7.0  1  5.0
2 -3.0  0  8.0
3  2.0  1 -2.5

In [348]: frame.rank(axis='columns')
Out[348]: 
     b    a    c
0  3.0  2.0  1.0
1  3.0  1.0  2.0
2  1.0  2.0  3.0
3  3.0  2.0  1.0

5.2.8 含有重复标签的轴索引

目前为止我们所见过的示例中,轴索引都是唯一的(索引值)。尽管很多pandas函数(比如reindex)需要标签是唯一的,但这个并不是强制性的。让我们考虑一个小型的带有重复索引的series:

In [349]: obj = pd.Series(range(5),index=['a','a','b','b','c'])

In [350]: obj
Out[350]: 
a    0
a    1
b    2
b    3
c    4
dtype: int64

索引的is_unique属性可以告诉你它的标签是否唯一:
In [351]: obj.index.is_unique
Out[351]: False

带有重复索引的情况下,数据选择是与之前操作有差别的主要情况。根据一个标签索引多个条目会返回一个序列,而单个条目会返回标量值:
In [352]: obj['a']
Out[352]: 
a    0
a    1
dtype: int64

In [353]: obj['c']
Out[353]: 4

这可能会使代码更复杂,因为来自索引的输出类型可能因标签是否重复而有所不同。

相同的逻辑可以拓展到在dataframe中进行索引:
In [359]: df2 = pd.DataFrame(np.arange(18.).reshape((6,3)),columns=list('bde'),index=['piaozhiyan','piaoxiaomin','jinzhenxi','piao
     ...: caoe','jinzhenxi','piaoxiaomin'])

In [360]: df2
Out[360]: 
                b     d     e
piaozhiyan    0.0   1.0   2.0
piaoxiaomin   3.0   4.0   5.0
jinzhenxi     6.0   7.0   8.0
piaocaoe      9.0  10.0  11.0
jinzhenxi    12.0  13.0  14.0
piaoxiaomin  15.0  16.0  17.0

In [361]: df2.loc['piaoxiaomin']
Out[361]: 
                b     d     e
piaoxiaomin   3.0   4.0   5.0
piaoxiaomin  15.0  16.0  17.0

5.3 描述性统计的概述与计算

pandas对象装配了一个常用数学、统计学方法的集合。其中大部分属于归约或汇总统计的类别,这些方法从dataframe的行或列中抽取一个series或一系列值的单个值(如总和或平均值)。与numpy数组中的类似方法相比,它们内建了处理缺失值的功能,考虑一个小型的dataframe。

In [363]: df = pd.DataFrame([[1.4,np.nan],[7.1,-4.5],[np.nan,np.nan],[0.75,-1.3]],index=['a','b','c','d'],columns=['one','two'])

In [364]: df
Out[364]: 
    one  two
a  1.40  NaN
b  7.10 -4.5
c   NaN  NaN
d  0.75 -1.3

调用dataframe的sum方法返回一个包含列上加和的series:
In [364]: df
Out[364]: 
    one  two
a  1.40  NaN
b  7.10 -4.5
c   NaN  NaN
d  0.75 -1.3

In [365]: df.sum()
Out[365]: 
one    9.25
two   -5.80
dtype: float64

传入axis='columns'或axis=1,则会将一行上各个列的值相加:
In [366]: df.sum(axis='columns')
Out[366]: 
a    1.40
b    2.60
c    0.00
d   -0.55
dtype: float64

除非整个切片(本例上就是行或列)上都是NA,否则NA值是被自动排除的。可以通过禁用skipna来实现不排除NA值:
In [367]: df.mean(axis='columns',skipna=False)
Out[367]: 
a      NaN
b    1.300
c      NaN
d   -0.275
dtype: float64

下图是归约方法的常用可选参数列表:
一些方法,比如idxmin和idxmax,返回的是间接统计信息,比如最小值或最大值的索引值:
In [368]: df.idxmax()
Out[368]: 
one    b
two    d
dtype: object

除了归约方法外,有的方法是积累型方法:
In [369]: df.cumsum()
Out[369]: 
    one  two
a  1.40  NaN
b  8.50 -4.5
c   NaN  NaN
d  9.25 -5.8

还有一类方法既不是归约型方法也不是积累型方法。describe就是其中之一,它一次性产生多个汇总统计:
In [371]: df.describe()
Out[371]: 
            one       two
count  3.000000  2.000000
mean   3.083333 -2.900000
std    3.493685  2.262742
min    0.750000 -4.500000
25%    1.075000 -3.700000
50%    1.400000 -2.900000
75%    4.250000 -2.100000
max    7.100000 -1.300000

对于非数值型数据,describe产生另一种汇总统计:
In [372]: obj = pd.Series(['quanxiaosheng','quanxiaosheng','jinzhenxi','piaoxiaomin']*4)

In [373]: obj.describe()
Out[373]: 
count                16 # 一共16个字符串
unique                3 # 排重后是3个字符串
top       quanxiaosheng # 出现最多的是‘quanxiaosheng’
freq                  8 # 一个字符串最多出现了八次
dtype: object

下图是汇总统计及其相关方法的完整列表:

5.3.1 相关性和协方差

一些汇总统计,比如相关性和协方差,是由多个参数计算出的。考虑某些使用附加pandas-datareader库从雅虎上获取的包括股价和交易量的dataframe。如果你还没有安装它,可以通过conda或者pip进行安装:

conda install pandas-datareader

import pandas_datareader.data as web
import pandas as pd
all_data={ticker:web.get_data_yahoo(ticker) for ticker in ['AAPL','IBM','MSFT','GOOG']}
price = pd.DataFrame({ticker:data['Ad Close'] for ticker,data in all_data.items()})
volume = pd.DataFrame({ticker:data['Volume'] for ticker,data in all_data.items()})

现在我计算股价的百分比:
In [7]: returns = price.pct_change()

In [8]: returns.tail()
Out[8]: 
                AAPL       IBM      MSFT      GOOG
Date                                              
2021-03-19 -0.004480 -0.008919 -0.001604  0.003428
2021-03-22  0.028336  0.012801  0.024484 -0.002256
2021-03-23 -0.006889 -0.000689  0.006738  0.007049
2021-03-24 -0.019994  0.001226 -0.008923 -0.003848
2021-03-25  0.005080 -0.005742  0.003313  0.002411

Series的corr方法计算的是两个series中重叠的,非NA的,按索引对齐的值的相关性。相应地,cov计算的是协方差:
In [9]: returns.corr()
Out[9]: 
          AAPL       IBM      MSFT      GOOG
AAPL  1.000000  0.446896  0.712947  0.651114
IBM   0.446896  1.000000  0.532985  0.500124
MSFT  0.712947  0.532985  1.000000  0.778763
GOOG  0.651114  0.500124  0.778763  1.000000

In [10]: returns.cov()
Out[10]: 
          AAPL       IBM      MSFT      GOOG
AAPL  0.000365  0.000140  0.000236  0.000209
IBM   0.000140  0.000268  0.000151  0.000137
MSFT  0.000236  0.000151  0.000301  0.000227
GOOG  0.000209  0.000137  0.000227  0.000281

协方差:

可以通俗的理解为:两个变量在变化过程中是同方向变化?还是反方向变化?同向或反向程度如何?

你变大,同时我也变大,说明两个变量是同向变化的,这时协方差就是正的。

你变大,同时我变小,说明两个变量是反向变化的,这时协方差就是负的。

从数值来看,协方差的数值越大,两个变量同向程度也就越大。反之亦然。

转自知乎答主:GRAYLAMBGRAYLAMB
使用DataFrame的corrwith方法,你可以计算出dataFrame中的行或列与领一个序列或DataFrame的相关性。该方法传入一个series时,会返回一个含有为每列计算相关性值的seies:
n [11]: returns.corrwith(returns.IBM)
Out[11]: 
AAPL    0.446896
IBM     1.000000
MSFT    0.532985
GOOG    0.500124
dtype: float64

传入一个DataFrame时,会计算匹配到列名的相关性数值。在这里,我计算出交易量百分比变化的相关性:
In [13]: returns.corrwith(volume)
Out[13]: 
AAPL   -0.074007
IBM    -0.114693
MSFT   -0.084778
GOOG   -0.134113
dtype: float64

传入axis=‘columns’会逐行地进行计算。在所有例子中,在计算相关性之前,数据点已经按标签进行了对齐。

5.3.2 唯一值、计数和成员属性

另一类相关的方法可以从一维series包含的数值中提取信息。为了说明这些方法,请考虑这个例子:

obj = pd.Series(['c','a','d','a','a','b','b','c','c'])

第一个函数是unique = obj.unique

In [14]: obj = pd.Series(['c','a','d','a','a','b','b','c','c'])

In [15]: unique = obj.unique()

In [16]: unique
Out[16]: array(['c', 'a', 'd', 'b'], dtype=object)

唯一值并不一定按照排序好的顺序返回,但是如果需要的话可以进行排序(uniques.sort())。相应的,value_counts计算Series包含的值的个数:
In [17]: obj.value_counts()
Out[17]: 
c    3
a    3
b    2
d    1
dtype: int64

为了方便,返回的Series会按照数量降序排序。value_counts也是有效的pandas顶层方法,可以用于任意数组或序列:
In [18]: pd.value_counts(obj.values,sort=False)
Out[18]: 
a    3
d    1
c    3
b    2
dtype: int64

isin执行向量化的成员属性检查,还可以将数据集以Series或DataFrame一列的形式过滤为数据集的值子集:
In [19]: obj
Out[19]: 
0    c
1    a
2    d
3    a
4    a
5    b
6    b
7    c
8    c
dtype: object

In [20]: mask = obj.isin(['b','c'])

In [21]: mask
Out[21]: 
0     True
1    False
2    False
3    False
4    False
5     True
6     True
7     True
8     True
dtype: bool

In [22]: obj[mask]
Out[22]: 
0    c
5    b
6    b
7    c
8    c
dtype: object

与isin相关的Index.get_indexer方法,可以提供一个索引数组,这个索引数组可以将可能非唯一值数组转换为另一个唯一值数组:
In [23]: match = pd.Series(['c','a','b','b','c','a'])

In [24]: vals = pd.Series(['c','b','a'])

In [26]: pd.Index(vals).get_indexer(match) # vals在match中的位置
Out[26]: array([0, 2, 1, 1, 0, 2])
某些情况下,你可能想要计算dataframe多个相关性的直方图,如下面的例子:
In [28]: data = pd.DataFrame({'qu1':[1,3,4,3,4,],'qu2':[2,3,1,2,3,],'qu3':[1,5,2,4,4]})

In [29]: data
Out[29]: 
   qu1  qu2  qu3
0    1    2    1
1    3    3    5
2    4    1    2
3    3    2    4
4    4    3    4

将pandas.value_counts传入DataFrame的apply函数可以得到:
In [30]: result = data.apply(pd.value_counts).fillna(0)

In [31]: result
Out[31]: 
   qu1  qu2  qu3
1  1.0  1.0  1.0
2  0.0  2.0  1.0
3  2.0  2.0  0.0
4  2.0  0.0  2.0
5  0.0  0.0  1.0

这里,结果中的行标签是所有列中出现的不同值,数值则是这些不同值在每个列中出现的次数。

比如qu1,1在qu1列中只出现了一次,所以数字为1。2在qu1列中出现0次,所以为0。3在qu1列中出现了两次,所以为2。以此类推。

第五章完结,我们明天再见~

胭惜雨

2021年03月25日

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据