Pandas之索引和查看数据


细致的朋友可能会发现一个现象,不论是序列也好,还是数据框也好,对象的最左边总有一个非原始数据对象,这个是什么呢?不错,就是我们接下来要介绍的索引。

在我看来,序列或数据框的索引有两大用处,一个是通过索引值或索引标签获取目标数据,另一个是通过索引,可以使序列或数据框的计算、操作实现自动化对齐。

1、索引对象


Index

pandas的索引对象用来保存坐标轴标签和其它元数据(如坐标轴名或名称)。构建一个Series或DataFrame时通过index属性来访问索性对象。

import pandas as pd
obj = pd.Series(range(3), index=['a', 'b', 'c'])
index = obj.index
index

>>:

Out[1]:
Index(['a', 'b', 'c'], dtype='object')

如果一个DataFrame的indexcolumns有它们的name,也会被显示出来:

pop = {'Nevada': {2001: 2.4, 2002: 2.9},'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
frame3 = pd.DataFrame(pop)
print(frame3)
print('\n',frame3.columns)
print(frame3.index)
      Nevada  Ohio
2000     NaN   1.5
2001     2.4   1.7
2002     2.9   3.6

Index(['Nevada', 'Ohio'], dtype='object')
Int64Index([2000, 2001, 2002], dtype='int64')

索引对象是不可变

索引对象是不可变的,因此不能由用户改变,下列操作将报错:

import pandas as pd
obj = pd.Series(range(3), index=['a', 'b', 'c'])
index = obj.index
index
index[1] = 'd'

输出:

索引对象的不可变性非常重要,这样它可以在数据结构中安全的共享,单独创建一个index对象赋值给dataframe,如果中途修改了index的值,运行期间会报错"TypeError: Index does not support mutable operations"

import numpy as np
index = pd.Index(np.arange(3))
obj2 = pd.Series([1.5, -2.5, 0], index=index)
obj2.index is index
Out[10]:True

修改index报错:

obj2.index[1]=10
print(obj2)

索引的函数(了解,不重点介绍)

下述表格是库中内建的索引类清单。通过一些开发努力,索引可以被子类化,来实现特定坐标轴索引功能。

Index 最通用的索引对象,使用Python对象的NumPy数组来表示坐标轴标签。
Int64Index 对整形值的特化索引。
MultiIndex “分层”索引对象,表示单个轴的多层次的索引。可以被认为是类似的元组的数组。
DatetimeIndex 存储纳秒时间戳(使用NumPy的datetime64 dtyppe来表示)。
PeriodIndex 对周期数据(时间间隔的)的特化索引。

除了类似于阵列,索引也有类似固定大小集合一样的功能:

print(frame3)
#in的这种语法很像遍历数组
print('Ohio' in frame3.columns)
print(2003 in frame3.index)

输出:

      Nevada  Ohio
2000     NaN   1.5
2001     2.4   1.7
2002     2.9   3.6

True
False

每个索引都有许多关于集合逻辑的方法和属性,且能够解决它所包含的数据的常见问题,如下述表格:

append 链接额外的索引对象,产生一个新的索引
diff 计算索引的差集
intersection 计算交集
union 计算并集
isin 计算出一个布尔数组表示每一个值是否包含在所传递的集合里
delete 计算删除位置i的元素的索引
drop 计算删除所传递的值后的索引
insert 计算在位置i插入元素后的索引
is_monotonic 返回True,如果每一个元素都比它前面的元素大或相等
is_unique 返回True,如果索引没有重复的值
unique 计算索引的唯一值数组

索性的自动对齐

如果有两个序列,需要对这两个序列进行算术运算,这时索引的存在就体现的它的价值了—自动化对齐.

s5 = pd.Series(np.array([10,15,20,30,55,80]),index = ['a','b','c','d','e','f'])
print(s5) 
s6 = pd.Series(np.array([12,11,13,15,14,16]), index = ['a','c','g','b','d','f'])
print('\n',s6)
print('\n',s5 + s6)
print('\n',s5/s6)

输出:

a    10
b    15
c    20
d    30
e    55
f    80
dtype: int64

 a    12
c    11
g    13
b    15
d    14
f    16
dtype: int64

 a    22.0
b    30.0
c    31.0
d    44.0
e     NaN
f    96.0
g     NaN
dtype: float64

 a    0.833333
b    1.000000
c    1.818182
d    2.142857
e         NaN
f    5.000000
g         NaN
dtype: float64

由于s5中没有对应的g索引,s6中没有对应的e索引,所以数据的运算会产生两个缺失值NaN。注意,这里的算术结果就实现了两个序列索引的自动对齐,而非简单的将两个序列加总或相除。对于数据框的对齐,不仅仅是行索引的自动对齐,同时也会自动对齐列索引(变量名)

数据框中同样有索引,而且数据框是二维数组的推广,所以其不仅有行索引,而且还存在列索引,关于数据框中的索引相比于序列的应用要强大的多,这部分内容将放在数据查询中讲解。

自动对齐本质是索引的或运算。

2、查看数据


1、通过索引值或索引标签获取数据

import pandas as pd
s4 = pd.Series(np.array([1,1,2,3,5,8]))
s4

如果不给序列一个指定的索引值,则序列自动生成一个从0开始的自增索引。可以通过index查看序列的索引

s4.index

现在我们为序列设定一个自定义的索引值:

s4.index = ['a','b','c','d','e','f']
s4

序列有了索引,就可以通过索引值或索引标签(索引切片)进行数据的获取:

import pandas as pd
s4 = pd.Series(np.array([1,1,2,3,5,8]))
s4.index = ['a','b','c','d','e','f']
print('s4:\n',s4)

print('\n',s4[3])
print('\n',s4['e'])
print('\n',s4[[1,3,5]])
print('\n',s4[['a','b','d','f']])
print('\n',s4[:4])
print('\n',s4['c':])
print('\n',s4['b':'e'])

千万注意:如果通过索引标签获取数据的话,末端标签所对应的值是可以返回的!在一维数组中,就无法通过索引标签获取数据,这也是序列不同于一维数组的一个方面。

2、用 head 和 tail 查看顶端和底端的几列

dates = pd.date_range('20130101', periods=6)
dates

df = pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('ABCD'))
df
df.head()
df.tail(3)

3、describe()显示数据的概要

df.describe()
              A         B         C         D
count  6.000000  6.000000  6.000000  6.000000
mean   0.073711 -0.431125 -0.687758 -0.233103
std    0.843157  0.922818  0.779887  0.973118
min   -0.861849 -2.104569 -1.509059 -1.135632
25%   -0.611510 -0.600794 -1.368714 -1.076610
50%    0.022070 -0.228039 -0.767252 -0.386188
75%    0.658444  0.041933 -0.034326  0.461706
max    1.212112  0.567020  0.276232  1.071804

4、获取行/列

注意,以下这些对交互式环境很友好,但是作为 production code 请用优化过的.at,.iat,.loc,.iloc.ix

用columns选择列,用index选择行。注意:选择列的时候单次只能选择某一列的数据,不能同时选择多列;而使用index的时候一定要使用范围(类似于[1:2]),单独某个index会报错。

从 DataFrame 选择一个列,就得到了 Series

df['A']
2013-01-01    0.469112
2013-01-02    1.212112
2013-01-03   -0.861849
2013-01-04    0.721555
2013-01-05   -0.424972
2013-01-06   -0.673690
Freq: D, Name: A, dtype: float64

如果同时选择多列df['A','B'],报错:

df['A','B']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~/local/anaconda3/lib/python3.6/site-packages/pandas/core/indexes/base.py in get_loc
(self, key, method, tolerance)
   2441             try:
-> 2442                 return self._engine.get_loc(key)
   2443             except KeyError:

和 numpy 类似,这里也能用[],通过索引访问

df[0:3]
                   A         B         C         D
2013-01-01  0.469112 -0.282863 -1.509059 -1.135632
2013-01-02  1.212112 -0.173215  0.119209 -1.044236
2013-01-03 -0.861849 -2.104569 -0.494929  1.071804
df['20130102':'20130104']
                   A         B         C         D
2013-01-02  1.212112 -0.173215  0.119209 -1.044236
2013-01-03 -0.861849 -2.104569 -0.494929  1.071804
2013-01-04  0.721555 -0.706771 -1.039575  0.271860

5、通过 label 选择

使用loc方法,通过位置标签选择:统一格式为DataFrame.loc[index:index,[‘columns’]],loc方法当中的columns可以选择多列,如果表示只按列选择的话index可以不填但是冒号(:)和逗号(,)一定要写.

另外,如果loc还能这么用:DataFrame.loc[index,[‘columns’]],这时的index为特定能够的label或值,这样用会返回一个Series;DataFrame.loc[index,‘columns’],这里面的index和columns都是唯一的,返回一个值。

由于降维的问题,pandas会对精度进行转换.

刚刚那个 DataFrame 可以通过时间戳的下标(dates[0] = Timestamp('20130101'))来访问。

df.loc[dates[0]]
A    0.469112
B   -0.282863
C   -1.509059
D   -1.135632
Name: 2013-01-01 00:00:00, dtype: float64

还可以多选

df.loc[:,['A','B']]
              A         B
2013-01-01 0.469112 -0.282863
2013-01-02 1.212112 -0.173215
2013-01-03 -0.861849 -2.104569
2013-01-04 0.721555 -0.706771
2013-01-05 -0.424972 0.567020
2013-01-06 -0.673690 0.113648

注意那个冒号,用法和NumPy 是一样的!所以也可以这样

df.loc['20130102':'20130104',['A','B']]
                   A         B
2013-01-02  1.212112 -0.173215
2013-01-03 -0.861849 -2.104569
2013-01-04  0.721555 -0.706771

当有一个维度是标量(而不是范围或序列)的时候,选择出的矩阵维度会减少

df.loc['20130102',['A','B']]
A    1.212112
B   -0.173215
Name: 2013-01-02 00:00:00, dtype: float64

如果对所有的维度都写了标量,不就是选出一个元素吗?

df.loc[dates[0],'A']
0.46911229990718628

这种情况通常用at,速度更快

df.at[dates[0],'A']
0.46911229990718628

6、通过整数下标选择

这个就和数组类似啦,直接看例子。选出第3行:

df.iloc[3]
A    0.721555
B   -0.706771
C   -1.039575
D    0.271860
Name: 2013-01-04 00:00:00, dtype: float64

选出3~4行,0~1列:

df.iloc[3:5,0:2]
                   A         B
2013-01-04  0.721555 -0.706771
2013-01-05 -0.424972  0.567020

也能用 list 选择

df.iloc[[1,2,4],[0,2]]
                   A         C
2013-01-02  1.212112  0.119209
2013-01-03 -0.861849 -0.494929
2013-01-05 -0.424972  0.276232

也能用 slice

df.iloc[1:3,:]
                   A         B         C         D
2013-01-02  1.212112 -0.173215  0.119209 -1.044236
2013-01-03 -0.861849 -2.104569 -0.494929  1.071804
df.iloc[:,1:3]
                   B         C
2013-01-01 -0.282863 -1.509059
2013-01-02 -0.173215  0.119209
2013-01-03 -2.104569 -0.494929
2013-01-04 -0.706771 -1.039575
2013-01-05  0.567020  0.276232
2013-01-06  0.113648 -1.478427

对应单个元素

df.iloc[1,1]
-0.17321464905330858
df.iat[1,1]
-0.17321464905330858

7、布尔值下标

基本用法

df[df.A >0]
                    A         B         C         D
2013-01-01  0.469112 -0.282863 -1.509059 -1.135632
2013-01-02  1.212112 -0.173215  0.119209 -1.044236
2013-01-04  0.721555 -0.706771 -1.039575  0.271860

没有填充的值等于 NaN

df[df>0]
                   A         B         C         D
2013-01-01  0.469112       NaN       NaN       NaN
2013-01-02  1.212112       NaN  0.119209       NaN
2013-01-03       NaN       NaN       NaN  1.071804
2013-01-04  0.721555       NaN       NaN  0.271860
2013-01-05       NaN  0.567020  0.276232       NaN
2013-01-06       NaN  0.113648       NaN  0.524988

isin()函数:是否在集合中

df2 = df.copy()
df2['E'] = ['one', 'one','two','three','four','three']
df2
                   A         B         C         D      E
2013-01-01  0.612417  0.095828 -0.054642  1.817248    one
2013-01-02  2.076892  0.092285  0.660803  0.894581    one
2013-01-03 -0.733269 -2.057131 -0.343663 -1.196418    two
2013-01-04 -0.650500  1.072853 -0.957207  1.301154  three
2013-01-05  0.118362  0.016416 -0.054961 -0.598852   four
2013-01-06  0.858298  1.206379  0.385798  0.642214  three
df2[df2['E'].isin(['two','four'])]
                   A           B           C           D    E
2013-01-03    -0.733269    -2.057131    -0.343663    -1.196418    two
2013-01-05    0.118362    0.016416    -0.054961    -0.598852    four

results matching ""

    No results matching ""