import pandas as pd
import numpy as np
概述
pandas 索引和选择的操作主要是以下五种:
操作 |
语法 |
Result |
选择列 |
df[col] |
Series |
通过标签选择行 |
df.loc[label] |
Series |
通过整数下标选择行 |
df.iloc[loc] |
Series |
行切片 |
df[5:10] |
DataFrame |
通过布尔向量切片 |
df[bool_vec] |
DataFrame |
df = pd.DataFrame(np.random.randn(4, 5), index=['a', 'b', 'c', 'd'], columns=['A', 'B', 'C', 'D', 'E'])
df
|
A |
B |
C |
D |
E |
a |
-0.103212 |
-0.719843 |
-0.355287 |
-0.440257 |
1.083105 |
b |
1.215091 |
0.350809 |
1.129627 |
0.179248 |
-0.367324 |
c |
0.703286 |
0.733214 |
-1.472511 |
1.311112 |
-0.663189 |
d |
0.644637 |
0.739376 |
1.270120 |
-1.353912 |
0.187226 |
a -0.719843
b 0.350809
c 0.733214
d 0.739376
Name: B, dtype: float64
|
B |
C |
a |
-0.719843 |
-0.355287 |
b |
0.350809 |
1.129627 |
c |
0.733214 |
-1.472511 |
d |
0.739376 |
1.270120 |
A 0.644637
B 0.739376
C 1.270120
D -1.353912
E 0.187226
Name: d, dtype: float64
A -0.103212
B -0.719843
C -0.355287
D -0.440257
E 1.083105
Name: a, dtype: float64
|
A |
B |
C |
D |
E |
a |
-0.103212 |
-0.719843 |
-0.355287 |
-0.440257 |
1.083105 |
b |
1.215091 |
0.350809 |
1.129627 |
0.179248 |
-0.367324 |
c |
0.703286 |
0.733214 |
-1.472511 |
1.311112 |
-0.663189 |
|
A |
B |
C |
D |
E |
a |
False |
False |
False |
False |
True |
b |
True |
True |
True |
True |
False |
|
A |
B |
C |
D |
E |
a |
0.000000 |
0.000000 |
0.000000 |
0.000000 |
1.083105 |
b |
1.215091 |
0.350809 |
1.129627 |
0.179248 |
0.000000 |
c |
0.703286 |
0.733214 |
0.000000 |
1.311112 |
0.000000 |
d |
0.644637 |
0.739376 |
1.270120 |
0.000000 |
0.187226 |
使用 [] 进行索引
使用 []
进行索引,实际上就是选择低维切片。对于 Series 对象和 DataFrame 对象,[]
返回的类型不同。
对象类型 |
调用方法 |
返回值类型 |
Series |
series[label] |
标量值 |
DataFrame |
frame[colname] |
对应 colname 的 Series |
dates = pd.date_range('1/1/2000', periods=8)
df = pd.DataFrame(np.random.randn(8, 4),
index=dates, columns=['A', 'B', 'C', 'D'])
df
|
A |
B |
C |
D |
2000-01-01 |
0.169225 |
-0.158166 |
-0.166857 |
-0.078189 |
2000-01-02 |
0.584719 |
0.631690 |
0.001675 |
0.263198 |
2000-01-03 |
-0.234786 |
-1.622012 |
-0.705652 |
-0.171561 |
2000-01-04 |
1.038103 |
-1.316517 |
-0.135135 |
-0.411320 |
2000-01-05 |
1.123070 |
0.290033 |
-0.372262 |
-0.340214 |
2000-01-06 |
0.900263 |
0.304163 |
-1.663322 |
0.633026 |
2000-01-07 |
0.766208 |
0.359713 |
-0.460340 |
0.746346 |
2000-01-08 |
0.864615 |
-0.576092 |
0.065375 |
-1.200949 |
2000-01-01 0.169225
2000-01-02 0.584719
2000-01-03 -0.234786
2000-01-04 1.038103
2000-01-05 1.123070
2000-01-06 0.900263
2000-01-07 0.766208
2000-01-08 0.864615
Freq: D, Name: A, dtype: float64
0.9002627651374207
交换 A
和 B
两列:
df[['B', 'A']] = df[['A', 'B']]
df
|
A |
B |
C |
D |
2000-01-01 |
-0.158166 |
0.169225 |
-0.166857 |
-0.078189 |
2000-01-02 |
0.631690 |
0.584719 |
0.001675 |
0.263198 |
2000-01-03 |
-1.622012 |
-0.234786 |
-0.705652 |
-0.171561 |
2000-01-04 |
-1.316517 |
1.038103 |
-0.135135 |
-0.411320 |
2000-01-05 |
0.290033 |
1.123070 |
-0.372262 |
-0.340214 |
2000-01-06 |
0.304163 |
0.900263 |
-1.663322 |
0.633026 |
2000-01-07 |
0.359713 |
0.766208 |
-0.460340 |
0.746346 |
2000-01-08 |
-0.576092 |
0.864615 |
0.065375 |
-1.200949 |
注意,如果使用了 loc
或者 iloc
,pandas 会先对齐所有 axes
。这不会修改 df
,因为列对齐在赋值之前。
df.loc[:, ['B', 'A']] = df[['A', 'B']]
df
|
A |
B |
C |
D |
2000-01-01 |
-0.158166 |
0.169225 |
-0.166857 |
-0.078189 |
2000-01-02 |
0.631690 |
0.584719 |
0.001675 |
0.263198 |
2000-01-03 |
-1.622012 |
-0.234786 |
-0.705652 |
-0.171561 |
2000-01-04 |
-1.316517 |
1.038103 |
-0.135135 |
-0.411320 |
2000-01-05 |
0.290033 |
1.123070 |
-0.372262 |
-0.340214 |
2000-01-06 |
0.304163 |
0.900263 |
-1.663322 |
0.633026 |
2000-01-07 |
0.359713 |
0.766208 |
-0.460340 |
0.746346 |
2000-01-08 |
-0.576092 |
0.864615 |
0.065375 |
-1.200949 |
可以强转成 ndarray
数组来实现这一操作:
df.loc[:, ['B', 'A']] = df[['A', 'B']].to_numpy()
df
|
A |
B |
C |
D |
2000-01-01 |
0.169225 |
-0.158166 |
-0.166857 |
-0.078189 |
2000-01-02 |
0.584719 |
0.631690 |
0.001675 |
0.263198 |
2000-01-03 |
-0.234786 |
-1.622012 |
-0.705652 |
-0.171561 |
2000-01-04 |
1.038103 |
-1.316517 |
-0.135135 |
-0.411320 |
2000-01-05 |
1.123070 |
0.290033 |
-0.372262 |
-0.340214 |
2000-01-06 |
0.900263 |
0.304163 |
-1.663322 |
0.633026 |
2000-01-07 |
0.766208 |
0.359713 |
-0.460340 |
0.746346 |
2000-01-08 |
0.864615 |
-0.576092 |
0.065375 |
-1.200949 |
切片
切片的规则和 Python 以及 NumPy 中的切片规则,一样。这里用 []
运算符说明切片的语义。
s = pd.Series(np.random.randn(7), index=list('abcdefg'))
s
a -0.381270
b -0.485434
c -0.298939
d 0.508133
e 0.961189
f 0.107214
g -1.452212
dtype: float64
a -0.381270
b -0.485434
c -0.298939
d 0.508133
e 0.961189
dtype: float64
a -0.381270
c -0.298939
e 0.961189
g -1.452212
dtype: float64
g -1.452212
f 0.107214
e 0.961189
d 0.508133
c -0.298939
b -0.485434
a -0.381270
dtype: float64
a 0.000000
b 0.000000
c 0.000000
d 0.508133
e 0.961189
f 0.107214
g -1.452212
dtype: float64
df = pd.DataFrame(np.random.randn(3, 4), index=list('abc'), columns=list('ABCD'))
df
|
A |
B |
C |
D |
a |
0.871967 |
1.381672 |
0.395105 |
-1.459083 |
b |
1.466618 |
1.626593 |
-1.002821 |
0.092995 |
c |
0.384346 |
0.020456 |
-0.441192 |
-0.476958 |
|
A |
B |
C |
D |
a |
0.871967 |
1.381672 |
0.395105 |
-1.459083 |
b |
1.466618 |
1.626593 |
-1.002821 |
0.092995 |
|
A |
B |
C |
D |
c |
0.384346 |
0.020456 |
-0.441192 |
-0.476958 |
b |
1.466618 |
1.626593 |
-1.002821 |
0.092995 |
a |
0.871967 |
1.381672 |
0.395105 |
-1.459083 |
通过属性索引
s = pd.Series([1, 2, 3], index=list('abc'))
s
a 1
b 2
c 3
dtype: int64
2
df = pd.DataFrame(np.random.randn(3, 4), index=list('abc'), columns=list('ABCD'))
df
|
A |
B |
C |
D |
a |
0.147620 |
-1.336105 |
0.945316 |
0.501963 |
b |
1.220405 |
0.697981 |
-0.869925 |
0.790545 |
c |
0.935809 |
0.584775 |
1.316057 |
0.138111 |
a 0.147620
b 1.220405
c 0.935809
Name: A, dtype: float64
df.A = list(range(len(df.index)))
df
|
A |
B |
C |
D |
a |
0 |
-1.336105 |
0.945316 |
0.501963 |
b |
1 |
0.697981 |
-0.869925 |
0.790545 |
c |
2 |
0.584775 |
1.316057 |
0.138111 |
采用访问属性的方法必须确保该属性存在。如果要创建新的一列,仍然需要通过 []
。否则,会出现 UserWanring
的警告。
df['E'] = list(range(len(df.index)))
df
|
A |
B |
C |
D |
E |
a |
0 |
-1.336105 |
0.945316 |
0.501963 |
0 |
b |
1 |
0.697981 |
-0.869925 |
0.790545 |
1 |
c |
2 |
0.584775 |
1.316057 |
0.138111 |
2 |
通过标签索引
使用 loc
方法可以使用标签对行进行索引。
s = pd.Series(np.random.randn(6), index=list('abcdef'))
s
a 0.763607
b -0.538096
c -0.032027
d 0.312734
e 1.096504
f -0.857242
dtype: float64
-0.5380958810076775
标签支持冒号表达式,进行切片运算。
c -0.032027
d 0.312734
e 1.096504
f -0.857242
dtype: float64
df = pd.DataFrame(np.random.randn(6, 4), index=list('abcdef'), columns=list('ABCD'))
df
|
A |
B |
C |
D |
a |
-0.367401 |
2.027401 |
-0.379841 |
-1.462746 |
b |
0.032665 |
0.143619 |
-2.085444 |
0.442935 |
c |
-1.117230 |
0.937448 |
0.738852 |
-0.411036 |
d |
0.238427 |
0.326619 |
0.182713 |
1.151853 |
e |
0.454272 |
0.844479 |
-1.220454 |
-1.453612 |
f |
-1.706529 |
-0.733242 |
0.400927 |
-0.431352 |
DataFrame 对象可以行列同时索引。
df.loc[['a', 'b', 'd'], ['A', 'C']]
|
A |
C |
a |
-0.367401 |
-0.379841 |
b |
0.032665 |
-2.085444 |
d |
0.238427 |
0.182713 |
|
A |
B |
C |
d |
0.238427 |
0.326619 |
0.182713 |
e |
0.454272 |
0.844479 |
-1.220454 |
f |
-1.706529 |
-0.733242 |
0.400927 |
注意:下面的切片不是下标切片,而是标签切片。因此,3:5
表示标签 3
和 5
之间的所有标签。3
和 5
之间还有一个标签 2
,因此返回结果为:
s = pd.Series(list('abcdef'), index=[0, 3, 2, 5, 4, 2])
s.loc[3:5]
3 b
2 c
5 d
dtype: object
通过下标位置索引
使用 iloc
方法可以通过下标位置进行索引。
s = pd.Series(np.random.randn(5), index=list(range(0, 10, 2)))
s
0 -0.465348
2 -0.507533
4 0.600791
6 -0.485520
8 0.703295
dtype: float64
0 -0.465348
2 -0.507533
4 0.600791
dtype: float64
0.7032949052125851
df = pd.DataFrame(np.random.randn(6, 4),
index=list(range(0, 12, 2)),
columns=list(range(0, 8, 2)))
df
|
0 |
2 |
4 |
6 |
0 |
1.490701 |
-0.549809 |
0.504431 |
-1.027572 |
2 |
-1.790752 |
0.687135 |
0.674383 |
-1.053664 |
4 |
1.168693 |
-0.129001 |
0.078535 |
-0.770111 |
6 |
0.711808 |
-0.269357 |
1.663142 |
-1.358983 |
8 |
-0.405399 |
-0.868119 |
0.183488 |
-1.307719 |
10 |
2.091057 |
0.426331 |
0.120099 |
0.599744 |
DataFrame 对象可以行列同时索引。
|
0 |
2 |
4 |
6 |
0 |
1.490701 |
-0.549809 |
0.504431 |
-1.027572 |
2 |
-1.790752 |
0.687135 |
0.674383 |
-1.053664 |
4 |
1.168693 |
-0.129001 |
0.078535 |
-0.770111 |
|
4 |
6 |
2 |
0.674383 |
-1.053664 |
4 |
0.078535 |
-0.770111 |
6 |
1.663142 |
-1.358983 |
8 |
0.183488 |
-1.307719 |
df.iloc[[1, 3, 5], [1, 3]]
|
2 |
6 |
2 |
0.687135 |
-1.053664 |
6 |
-0.269357 |
-1.358983 |
10 |
0.426331 |
0.599744 |
|
0 |
2 |
4 |
6 |
2 |
-1.790752 |
0.687135 |
0.674383 |
-1.053664 |
4 |
1.168693 |
-0.129001 |
0.078535 |
-0.770111 |
可以超出索引范围,但是可能会返回空 DataFrame。
选择接受可调用对象
[]
、loc
和 iloc
都接受可调用对象进行索引。
df = pd.DataFrame(np.random.randn(6, 4),
index=list('abcdef'),
columns=list('ABCD'))
df
|
A |
B |
C |
D |
a |
-0.363806 |
2.135196 |
0.112095 |
0.183855 |
b |
0.964061 |
1.549231 |
0.162025 |
1.408502 |
c |
0.033714 |
0.484294 |
0.895077 |
1.834204 |
d |
-1.632735 |
0.628079 |
1.497278 |
1.194587 |
e |
-1.692414 |
0.494285 |
1.618099 |
-1.882802 |
f |
-1.543841 |
0.550801 |
-1.429393 |
-0.001107 |
df.loc[lambda df: df['A'] > 0, :]
|
A |
B |
C |
D |
b |
0.964061 |
1.549231 |
0.162025 |
1.408502 |
c |
0.033714 |
0.484294 |
0.895077 |
1.834204 |
df.loc[:, lambda df: ['A', 'B']]
|
A |
B |
a |
-0.363806 |
2.135196 |
b |
0.964061 |
1.549231 |
c |
0.033714 |
0.484294 |
d |
-1.632735 |
0.628079 |
e |
-1.692414 |
0.494285 |
f |
-1.543841 |
0.550801 |
df.iloc[:, lambda df: [0, 1]]
|
A |
B |
a |
-0.363806 |
2.135196 |
b |
0.964061 |
1.549231 |
c |
0.033714 |
0.484294 |
d |
-1.632735 |
0.628079 |
e |
-1.692414 |
0.494285 |
f |
-1.543841 |
0.550801 |
df[lambda df: df.columns[0]]
a -0.363806
b 0.964061
c 0.033714
d -1.632735
e -1.692414
f -1.543841
Name: A, dtype: float64
df['A'].loc[lambda s: s > 0]
b 0.964061
c 0.033714
Name: A, dtype: float64
快速访问
由于使用 []
进行索引必须处理很多情况(单标签访问、切片、布尔索引等),因此它需要一些开销才能确定您的要求。如果您只想访问一个标量值,最快的方法是使用 at
和 iat
方法,它们在所有数据结构上都实现了。
s = pd.Series(np.random.randint(0, 7, size=(7,)), index=list('abcdefg'))
s
a 0
b 6
c 0
d 6
e 6
f 1
g 1
dtype: int32
1
0
df = pd.DataFrame(np.random.randint(0, 7, size=(3, 4)), index=list('abc'), columns=list('ABCD'))
df
|
A |
B |
C |
D |
a |
1 |
5 |
6 |
5 |
b |
1 |
4 |
5 |
3 |
c |
4 |
3 |
1 |
0 |
5
1
布尔索引
Series 对象的布尔索引和 Python 以及 NumPy 类似。
s = pd.Series(range(-3, 4))
s
0 -3
1 -2
2 -1
3 0
4 1
5 2
6 3
dtype: int64
4 1
5 2
6 3
dtype: int64
0 -3
1 -2
4 1
5 2
6 3
dtype: int64
3 0
4 1
5 2
6 3
dtype: int64
df = pd.DataFrame(np.random.randn(7, 4),
index=pd.date_range('2022/02/22', periods=7),
columns=list('ABCD'))
df
|
A |
B |
C |
D |
2022-02-22 |
-1.645831 |
-0.603577 |
0.855909 |
-0.172192 |
2022-02-23 |
-0.006510 |
-0.708135 |
-0.788163 |
-2.029753 |
2022-02-24 |
-1.034041 |
0.977184 |
-0.176987 |
-0.066881 |
2022-02-25 |
0.713977 |
2.029726 |
-0.441814 |
0.105782 |
2022-02-26 |
-0.038251 |
-1.624340 |
-0.882659 |
0.655924 |
2022-02-27 |
1.122102 |
-0.019443 |
1.120410 |
-0.599446 |
2022-02-28 |
1.829295 |
0.039461 |
-0.468706 |
1.038191 |
|
A |
B |
C |
D |
2022-02-25 |
0.713977 |
2.029726 |
-0.441814 |
0.105782 |
2022-02-27 |
1.122102 |
-0.019443 |
1.120410 |
-0.599446 |
2022-02-28 |
1.829295 |
0.039461 |
-0.468706 |
1.038191 |
高级布尔函数
isin(values)
用于判断元素是否包含在 values
中,适用于 Series
,DataFrame
和 Index
对象。
df = pd.DataFrame({'num_legs': [2, 4], 'num_wings': [2, 0]},
index=['falcon', 'dog'])
df
|
num_legs |
num_wings |
falcon |
2 |
2 |
dog |
4 |
0 |
isin
函数可以接受 list、dict、Seires 等可迭代对象作为参数。
|
num_legs |
num_wings |
falcon |
True |
True |
dog |
False |
True |
如果传入的是 dict,则可以分别设置每一列的判断规则。如若不设置,默认得到 False。
df.isin({'num_wings': [0, 3]})
|
num_legs |
num_wings |
falcon |
False |
False |
dog |
False |
True |
如果传入的是 Series 或者 DataFrame 对象,那么必须确保每行每列匹配。
other = pd.DataFrame({'num_legs': [8, 3], 'num_wings': [0, 2]},
index=['spider', 'falcon'])
df.isin(other)
|
num_legs |
num_wings |
falcon |
False |
True |
dog |
False |
False |
查询 num_wings
列中值为 2 或 4 的行。
df[df["num_wings"].isin([2, 4])]
|
num_legs |
num_wings |
falcon |
2 |
2 |
过滤并保留 num_wings
列中值为 4 或 8 的行。
df = df[df["num_legs"].isin([4, 8])]
df
|
num_legs |
num_wings |
dog |
4 |
0 |