Python语言Pandas库的DataFrames数据类型的索引写法比较多,既提供了方便也容易出错。一般的Python书籍上对Pandas索引都有介绍,本文总结一些个人体会,大体分为用中括号索引和用loc/iloc[]索引。
先生成一个DataFrame对象为例:
df=pd.DataFrame(np.random.rand(4,4), index=list('abcd'), columns=list('ABCD'))
A | B | C | D | |
a | 0.959245 | 0.552285 | 0.265993 | 0.249411 |
b | 0.743880 | 0.582683 | 0.310940 | 0.675503 |
c | 0.644287 | 0.796247 | 0.202314 | 0.232712 |
d | 0.149495 | 0.570265 | 0.095389 | 0.029824 |
在用中括号索引时最容易犯错的是混淆了行索引和列索引。基本原则如下:
(1)单值索引只能索引列
df['A']是正确的写法,等同于df.A。如果想索引某一行,不能写成df['a']或df['a',:],否则会报错。但可以改用df[df.index=='a']或者df.loc['a']的形式。
(2)列表索引也只能索引列
如果想同时索引多列,可以写成df[['A','B']],记住有两层中括号,不能少一层中括号。如果写成df['A','B']会报错,因为逗号被解释成了维度之间的分隔符。这里行索引只有'a',而没有'A',而且要表示'a'行'B'列应该用df.loc['a','B'],不能少了loc。列表索引可以改变索引列的顺序,例如写成df[['C','B','A']]将按C、B、A的顺序显示,这叫花式索引。花式索引也可以写成对象属性的形式,[[df.C, df.B, df.A]]也是正确的。
(3)切片只能索引多行
切片索引写成df['a':'c']或df[:2]表示索引a到c三行,但不能写成df['A':'C']或df[:,'A':'C']来索引三列。这点跟numpy的array不同,如果df是ndarray类型的,可以用df[:, 1:3]来切片第1~2列。要想切片多列可以写成df.loc[:,'A':'C'],但这里不能少了loc和:,,否则也报错。另外,切片只能用中括号或loc索引,而不能写成对象属性的形式,df.loc[:, df.A:df.C]也会报错。
上面说了中括号不能对单个行进行索引,而用loc/iloc就解决了这个问题,例如df.loc['B']或df.iloc[2],所以要想索引某一行只能用loc/iloc的形式。由于loc可以索引单个行,为了不引起混淆,索引单个列时必须在前面加上符号“:,”,例如df.loc[:,'A']表示索引A列,如果写成df.loc['A']就会报错,因为Notebook会将df.loc['A']解读为df的A行而实际上df并没有A行。同样,可以用iloc[]来索引一个元素或切片,例如df.iloc[2][3]跟df.iloc[2,3]是等价的,都得到0.232712。df.iloc[2][3]相当于先从df中取出df.iloc[2]这一行,再从这行中取出第3个数。同理,df.iloc[2][1:3]表示第2行的1到2切片。但博主不建议用两个方括号iloc[][]的写法,有时程序会出意外错误。
(1)布尔条件索引既可以索引行又可以索引列,既可以用于中括号索引又可以用于loc/iloc索引。但我建议尽量用loc索引,尤其是对列索引操作时不容易出错,用iloc或直接用方括号索引有时会出现未知错误。如果逻辑表达式是关于变量(列)取值的,布尔索引返回的是行数据,例如写成df.loc[关于列的条件]返回的是行数据。如果逻辑表达式是关于行索引取值的,例如写成df.loc[关于行的条件],则返回的是列数据,例如df.loc[:, df.loc['c']>0.1]。另外还需注意df.loc[df['A']>0.1]中内层的df不能漏了,如写成df[['A']>0.1]或df['A'>0.1]系统只会把'A'当成是一个字符而报错,系统不知道A是指df的一列。还有一个原因,是内侧用于逻辑判断的表跟外侧被索引的表可以不相同,即df1.loc[df2['A']>0.1]的写法,假定df1和df2不是同一个表,这里[df2['A']>0.1]返回一个df2中为True的元素位置的索引列表,然后在df1中按照同样的位置把行取出来。因此用于逻辑判断的字段就必须带上表名,否则不知道是指哪个表里的字段。如果只需要显示A列数据,不能写成df.A[df>0.1],而应该写成df.A[df.A>0.1]。
(2)当逻辑表达式是关于列名的,布尔索引可以用于对列索引,例如df.iloc[:, df.columns!='B']或df.loc[:, df.columns!='B']都能执行,但此处不能少了loc和iloc,否则也报错。总之凡是把行索引写成“:,”再写列的选取条件的形式只能用在loc/iloc格式。
(3)如果要用布尔关系将多个条件组合起来,要给每个条件加小括号,例如df.loc[(df['A']>0.7) & (df['B']<0.5) & (df['C']>0.6)],漏写小括号也会出错。注意这里的运算符是位运算符&,而不是布尔运算符and,后者也会出错。如果需要返回整个矩阵,只能用中括号索引,而不能用loc/iloc[]。例如返回df中大于0.1的值应当写成df[df>0.1],而不能写成df.loc[df>0.1]