5.1.3 索引对象

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

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

print(index)
print(index[1:])

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

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

索引对象是不可变的,因此用户是无法修改索引对象的:

index[1] = 'd'  # TypeError

index[1] = 'd'  # TypeError
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

 in ()
----> 1 index[1] = 'd'  # TypeError
/usr/local/lib/python3.6/dist-packages/pandas/core/indexes/base.py in __setitem__(self, key, value)
   3936
   3937     def __setitem__(self, key, value):
-> 3938         raise TypeError("Index does not support mutable operations")
   3939
   3940     def __getitem__(self, key):
TypeError: Index does not support mutable operations

不变性使得在多种数据结构中分享索引对象更为安全:

labels = pd.Index(np.arange(3))
print(labels)

print("-"*50)
obj2 = pd.Series([1.5, -2.5, 0], index=labels)
print(obj2)

print("-"*50)
print(obj2.index is labels)

labels = pd.Index(np.arange(3))
print(labels)

print("-"*50)
obj2 = pd.Series([1.5, -2.5, 0], index=labels)
print(obj2)

print("-"*50)
print(obj2.index is labels)
Int64Index([0, 1, 2], dtype='int64')
--------------------------------------------------
0    1.5
1   -2.5
2    0.0
dtype: float64
--------------------------------------------------
True

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

除了类似数组,索引对象也像一个固定大小的集合:

print(frame3)
print("-"*50)
print(frame3.columns)
print("-"*50)
print('Ohio' in frame3.columns)
print("-"*50)
print(2002 in frame3.index)
print(2003 in frame3.index)

print(frame3)
print("-"*50)
print(frame3.columns)
print("-"*50)
print('Ohio' in frame3.columns)
print("-"*50)
print(2002 in frame3.index)
print(2003 in frame3.index)
state  Nevada  Ohio
year
2000      NaN   1.5
2001      2.4   1.7
2002      2.9   3.6
--------------------------------------------------
Index(['Nevada', 'Ohio'], dtype='object', name='state')
--------------------------------------------------
True
--------------------------------------------------
True
False

与Python集合不同,pandas索引对象可以包含重复标签:

dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar'])

print(dup_labels)
print(dup_labels.unique())
print('|'.join(dup_labels.unique()))

dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar'])

print(dup_labels)
print(dup_labels.unique())
print('|'.join(dup_labels.unique()))
Index(['foo', 'foo', 'bar', 'bar'], dtype='object')
Index(['foo', 'bar'], dtype='object')
foo|bar

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

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

方法

描述

append

将额外的索引对象粘贴到原索引后,产生一个新的索引

difference

计算两个索引的差集

intersection

计算两个索引的交集

union

计算两个索引的并集

isin

计算表示每一个值是否在传值容器中的布尔数组

delete

将位置i的元素删除,并产生新的索引

drop

根据传参删除指定索引值,并产生新的索引

insert

在位置i插入元素,并产生新的索引

is monotonic

如果索引序列递增则返回True

Is unique

如果索引序列唯一则返回True

unique

计算索引的唯一值序列

5.2 基本功能

接下来将会指引了解与Series或DataFrame中数据交互的基础机制。后续的内容中会更为深入地讲解使用pandas进行数据分析和操作的主题。

5.2.1 重建索引

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

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

obj

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

obj
d    4.5
b    7.2
a   -5.3
c    3.6
dtype: float64

Series调用reindex方法时,会将数据按照新的索引进行排列,如果某个索引值之前并不存在,则会引入缺失值:

obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])

obj2

obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])

obj2
a   -5.3
b    7.2
c    3.6
d    4.5
e    NaN
dtype: float64

对于顺序数据,比如时间序列,在重建索引时可能会需要进行插值或填值。method可选参数允许使用诸如ffill等方法在重建索引时插值,ffill方法会将值前向填充:

obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
obj3

obj3.reindex(range(6), method='ffill')

obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
obj3

obj3.reindex(range(6), method='ffill')
0      blue
1      blue
2    purple
3    purple
4    yellow
5    yellow
dtype: object

在DataFrame中,reindex可以改变行索引、列索引,也可以同时改变二者。当仅传入一个序列时,结果中的行会重建索引:

frame = pd.DataFrame(np.arange(9).reshape((3, 3)),
                     index=['a', 'c', 'd'],
                     columns=['Ohio', 'Texas', 'California'])

frame

frame = pd.DataFrame(np.arange(9).reshape((3, 3)),
                     index=['a', 'c', 'd'],
                     columns=['Ohio', 'Texas', 'California'])

frame

Ohio

Texas

California

a

0

1

2

c

3

4

5

d

6

7

8

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

frame2

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

frame2

Ohio

Texas

California

a

0.0

1.0

2.0

b

NaN

NaN

NaN

c

3.0

4.0

5.0

d

6.0

7.0

8.0

列可以使用columns关键字重建索引:

states = ['Texas', 'Utah', 'California']
frame.reindex(columns=states)

states = ['Texas', 'Utah', 'California']
frame.reindex(columns=states)

Texas

Utah

California

a

1

NaN

2

c

4

NaN

5

d

7

NaN

8

下表是reindex方法的参数列表。

参数

描述

index

新建作为索引的序列,

可以是索引实例或任意其他序列型Python数据结构索引使用时无须复制

method

插值方式;'ffill'为前向填充,而'bfill'是后向填充

fill_value

通过重新索引引入缺失数据时使用的替代值

limit

当前向或后向填充时,所需填充的最大尺寸间隙(以元素数量)

tolerance

当前向或后向填充时,

所需填充的不精确匹配下的最大尺寸间隙(以绝对数字距离)

level

匹配 MultiIndex级别的简单索引;否则选择子集

copy

如果为True,即使新索引等于旧索引,也总是复制底层数据;

如果是 False,则在索引相同时不要复制数据

更深入地探索时,可以使用loc进行更为简洁的标签索引,许多用户更倾向于使用这种方式:

# 不增加数据内容的,不会产生报错
print(frame.loc[['a','c','d'],['Ohio','Texas']])
print("-"*50)
# 会有后期功能不可用的警告(提示使用reindex)
print(frame.loc[['a', 'b', 'c', 'd'], states])

# 不增加数据内容的,不会产生报错
print(frame.loc[['a','c','d'],['Ohio','Texas']])
print("-"*50)
# 会有后期功能不可用的警告(提示使用reindex)
print(frame.loc[['a', 'b', 'c', 'd'], states])
Ohio  Texas
a     0      1
c     3      4
d     6      7
--------------------------------------------------
   Texas  Utah  California
a    1.0   NaN         2.0
b    NaN   NaN         NaN
c    4.0   NaN         5.0
d    7.0   NaN         8.0


/usr/local/lib/python3.6/dist-packages/pandas/core/indexing.py:1494: FutureWarning:
Passing list-likes to .loc or [] with any missing label will raise
KeyError in the future, you can use .reindex() as an alternative.

See the documentation here:
https://pandas.pydata.org/pandas-docs/stable/indexing.html#deprecate-loc-reindex-listlike
  return self._getitem_tuple(key)