一. 索引对象
在之前介绍的Series和DataFrame结构中,我们已经接触到了索引对象,它是pandas的重要组成部分。pandas定义了Index类来表示基本索引对象,想要获取数据的索引对象,只需调用数据的index属性即可index=df.index
。
这里有几点需要强调:
1. 索引是可以重复的
虽然很多时候都要求索引唯一,但这并不是强制的。我们可以使用索引对象的is_unique属性,来判断索引是否唯一。
d=DF({'A':[1,2,3,4,5],'B':[6,7,8,9,10]},index=[1,1,2,2,3])
print(d)
print(d.index.is_unique)
Out[1]:
A B
1 1 6
1 2 7
2 3 8
2 4 9
3 5 10
False
2. 索引一旦确立就不可以再修改
索引是不可以修改的,但是可以全部重置。怎么理解呢?就是不可以修改索引的任何一部分,但是可以全部替换掉。索引的不可修改性十分重要,因为只有这样才能保证数据结构间安全共享(eg.自动对齐)。
那么如何替换掉所有的索引呢?有4种方法:
reset_index:替换旧索引,新的索引按0,1,2,3,4.....递增
Series/DataFrame.reset_index(level=None, drop=False, inplace=False, col_level=0, col_fill=' ')
level:要删除哪一级索引(多重索引)
drop:False则将旧索引变成列,True则删除旧索引
inplace:是否在原数据中修改
col_level:如果列是多重标签,旧索引名插入到哪一层
col_fill:如果列是多重标签,剩下的标签名是什么set_index :将dataframe其中某列作为索引
DataFrame.set_index(keys, drop=True, append=False, inplace=False, verify_integrity=False)
keys:要置为索引的列标签(列表)
drop:True设置为新索引的列被删除,False被保留
append:True保留原索引,keys中的列变为下一级索引
inplace:是否在原数据中修改
verify_integrity:True检测新的索引是否重复,重复则报错。reindex:设置新索引, 新索引中不存在对应的数据,则将数据设为nan
reindex更多的不是修改pandas对象的索引,而只是修改索引的顺序,如果修改的索引不存在就会使用默认的None代替此行。
Series/Panel/DataFrame.reindex(labels=None, index=None, columns=None, axis=None, method=None, copy=True, level=None, fill_value=nan, limit=None, tolerance=None)
前4个参数:传入新的索引数组,说明要修改行索引还是列标签。
举个例子:我们看到,旧索引是[0,1,2,3,4],替换的新索引是[1,2,3,4,5,6],2个索引的交集被保留下来,新索引中不存在的标签0被删除,同时引入了新索引中的标签[5,6],数据为NAN
d=DF({'A':[1,1,3,4,5],'B':[6,7,8,9,10]})
print(d)
d=d.reindex([1,2,3,4,5,6])
print(d)
Out[2]:
A B
0 1 6
1 1 7
2 3 8
3 4 9
4 5 10
A B
1 1.0 7.0
2 3.0 8.0
3 4.0 9.0
4 5.0 10.0
5 NaN NaN
6 NaN NaN
method:新引入的索引标签的数据填充方法。pad / ffill向前保持一致;backfill / bfill向后保持一致;nearest和最近保持一致。
d=DF({'A':[1,1,3,4,5],'B':[6,7,8,9,10]},index=[0,1,3,4,5])
print(d)
d=d.reindex([1,2,3,4,5,6],method='pad')
print(d)
Out[3]:
A B
0 1 6
1 1 7
3 3 8
4 4 9
5 5 10
A B
1 1 7
2 1 7
3 3 8
4 4 9
5 5 10
6 5 10
fill_value:新引入的索引标签的数据填充值。
- 直接赋值:直接将索引赋值给index变量,长度要和数据一致
data=pd.DataFrame({'A':[1,2,],'B':[0,0,],'C':[7,8]})
data.index=['a','b']
Out:
A B C
a 1 0 7
b 2 0 8
二. 多重索引对象
多重索引(hierarchical indexing)是pandas的一个重要的功能,它可以在一个轴上有多个(两个以上)的索引,这就表示着,它能够以低维度形式来表示高维度的数据。注意,这里我说的是轴,这就意味着,多重索引可以是行索引,也可以是列索引。
1. 创建多重行索引
-
显式创建多重行索引:利用pandas.MultiIndex对象
MultiIndex是pandas中标准的多重索引类,使用时只需将该对象赋值给基本结构的index参数即可。那么,我们如何创建这个MultiIndex对象呢?主要有以下几种方法:
- 从数组构建:
MultiIndex.from_arrays(arrays, sortorder=None, names=None)
- 从元组构建:
MultiIndex.from_tuples(tuples, sortorder=None, names=None)
- 从数组交差配对构建:
MultiIndex.from_product(iterables, sortorder=None, names=None)
其中,第一个参数是索引结构,names是索引名,举个例子:
#注意观察从数组构建,与从交叉迭代构建的区别!!
arr=[['a','b'],[1,2]]
ind=pd.MultiIndex.from_arrays(arr,names=['alpha','number'])
data=pd.DataFrame({'A':[1,2,],'B':[0,0,],'C':[7,8]},index=ind)
print(data)
Out:
A B C
alpha number
a 1 1 0 7
b 2 2 0 8
arr=[['a','b'],[1,2]]
ind=pd.MultiIndex.from_product(arr,names=['alpha','number'])#交叉迭代
data=pd.DataFrame({'A':[1,2,3,4],'B':[0,0,5,6],'C':[7,8,0,0]},index=ind)
print(data)
Out:
A B C
alpha number
a 1 1 0 7
2 2 0 8
b 1 3 5 0
2 4 6 0
- 隐式创建多重行索引
- 利用set_index()函数添加索引
更多的时候我们不是自己创建数据结构,而是从文件中读取数据,然后自己设定索引列。还记得之前介绍set_index()函数的时候,提到过一个参数append,它被设置为True的时候,原索引不变,指定列被设置为原索引的下一级索引,我们可以利用这个特点,构造多重索引。
举个例子:可以看到,栗子中的B列变成了2级索引。
data=pd.DataFrame({'A':[1,2,3],'B':[0,0,4],'C':[7,8,5]})
data.index.name='index'
data.set_index(keys=['B'],append=True,inplace=True)
print(data)
Out:
A C
index B
0 0 1 7
1 0 2 8
2 4 3 5
- 构造数据时,直接传入多个索引数组
直接上栗子,这个很好理解
data=pd.DataFrame({'A':[1,2,3],'B':[0,0,4],'C':[7,8,5]},index=[['a','a','b'],[1,2,3]])
print(data)
Out:
A B C
a 1 1 0 7
2 2 0 8
b 3 3 4 5
2. 创建多重列索引
直接使用MultiIndex对象显示创建多重列索引。
arr=[['A','A','C'],['a','b','a']]
ind=pd.MultiIndex.from_arrays(arr,names=['letter','number'])
data=pd.DataFrame([[1,2,3],[0,0,4],[7,8,5]],columns=ind)
print(data)
Out:
letter A C
number a b a
0 1 2 3
1 0 0 4
2 7 8 5
3.多重索引对象下的索引操作
之前讲pandas基本数据结构的时候,我们提到,常用的索引操作方式主要有以下几种:
- 点字符 :访问列
- 中括号 [ ]
- loc[ ] :基于标签索引,可以批量选取
- iloc[ ] :基于位置索引,可以批量选取
- at[ ] : 基于标签索引,只能选取一个元素
- iat[ ] : 基于位置索引,只能选取一个元素
在多重索引中也同样适用,而且使用方法基本雷同。这个时候可能会有人问,如何选择子索引呢?这个很简单,下面我们一起来看:
示例数据:
A C
a b a
1 i 1 2 3
ii 0 0 4
3 iii 7 8 5
- 索引元组:如果想要选取最外层索引,和普通单索引对象没区别。若是想要选取多层索引,就要使用元组的括号把索引包裹起来,我们看个栗子。
#只选最外层
print(data['A'])
Out:
a b
1 i 1 2
ii 0 0
3 iii 7 8
#选列多层
print(data[ ('A','a') ])
Out:
1 i 1
ii 0
3 iii 7
#行列都来个多层
print(data.loc[ (1,'ii') , ('A','a') ])
Out:
0
2.切片
多重索引也支持切片操作,只需用元组括号包裹多层的索引就可以了。
print(data.loc[(1,'ii'):,('A','a')])
Out:
1 ii 0
3 iii 7
另外,slice(None), 是Python中的切片操作,这里用来选择任意的id,要注意!不能使用‘:’来指定任意index,‘:’用来指定dataframe任意的列
print(data.loc[(slice(None),'ii')])
Out:
A C
a b a
ii 0 0 4
3.点字符
多重索引也支持点字符访问列,可以每一级使用一个点字符。
print(data.A.a)
Out:
1 i 1
ii 0
3 iii 7
4.删除多重索引
使用pandas.MultiIndex.droplevel()
函数,可以删除指定level的行索引。
data.index=data.index.droplevel(0)
print(data)
Out:
A C
a b a
i 1 2 3
ii 0 0 4
iii 7 8 5