一、基本功能

1.1 重新索引

pandas对象的一个重要方法就是reindex,其作用是创建一个新的对象,它的数据符合新的索引:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import pandas as pd
obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=["d", "b", "a", "c"])
print("-----obj-----")
print(obj)

# reindex根据索引进行重排,如果某个索引值当前不在,就引入缺失值
obj2 = obj.reindex(["a", "b", "c", "d", "e"])
print("----obj2-----")
print(obj2)

# 结果
-----obj----
d 4.5
b 7.2
a -5.3
c 3.6
dtype: float64
-----obj2-----
a -5.3
b 7.2
c 3.6
d 4.5
e NaN
dtype: float64

对于时间序列这样的有序数据,重新索引时可能需要做一些插值处理。method选项即可达到此目的,例如,使用ffill可以实现前向值填充:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
···
obj3 = pd.Series(["blue", "purple", "yellow"], index=[0, 2, 4])
print("-----obj3-----")
print(obj3)

# method, ffill
obj4 = obj3.reindex(range(6), method="ffill")
print(obj4)

# 结果
-----obj3-----
0 blue
2 purple
4 yellow
dtype: object
0 blue
1 blue
2 purple
3 purple
4 yellow
5 yellow
dtype: object

借助DataFrame,reindex可以修改(行)索引和列。只传递一个序列时,会重新索引结果的行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import pandas as pd
import numpy as np
frame = pd.DataFrame(np.arange(9).reshape((3,3)), index=["a", "b", "d"], columns=['Ohio', 'Texas', 'California'])
print("-----frame-----")
print(frame)

frame2 = frame.reindex(["a", "b", "c", "d"])
print("-----frame2-----")
print(frame2)

# 列可以用columns关键字重新索引
states = ["Texas", "Utah", "California"]
print(frame.reindex(columns=states))

# 结果
-----frame-----
Ohio Texas California
a 0 1 2
b 3 4 5
d 6 7 8
-----frame2-----
Ohio Texas California
a 0.0 1.0 2.0
b 3.0 4.0 5.0
c NaN NaN NaN
d 6.0 7.0 8.0
Texas Utah California
a 1 NaN 2
b 4 NaN 5
d 7 NaN 8

Process finished with exit code 0

下表列出了reindex函数的各参数及说明。

1.2 丢弃指定轴的项

丢弃某条轴上的一个或多个项很简单,只要有一个索引数组或列表即可。由于需要执行一些数据整理和集合逻辑,所以drop方法返回的是一个在指定轴上删除了指定值的新对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import pandas as pd
import numpy as np
obj = pd.Series(np.arange(5.), index=["a", "b", "c", "d", "e"])
print("-----obj-----")
print(obj)

new_obj = obj.drop("c")
print("----now_obj-----")
print(new_obj)

new_obj1 = obj.drop(["a", "b"]) # 列表
print(new_obj1)

# 结果
-----obj-----
a 0.0
b 1.0
c 2.0
d 3.0
e 4.0
dtype: float64
----now_obj-----
a 0.0
b 1.0
d 3.0
e 4.0
dtype: float64
c 2.0
d 3.0
e 4.0
dtype: float64

对于DataFrame,可以删除任意轴上的索引值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import pandas as pd
import numpy as np
data = pd.DataFrame(np.arange(16).reshape((4,4)), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['one', 'two', 'three', 'four'])
print("-----data-----")
print(data)

# 用标签序列调用drop会从行标签(axis 0)删除值
print(data.drop(['Colorado', 'Ohio']))

# 通过传递axis=1或axis='columns'可以删除列的值:
print(data.drop("two", axis=1))
print(data.drop(["two", "four"], axis="columns"))


# 结果
-----data-----
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
one two three four
Utah 8 9 10 11
New York 12 13 14 15
one three four
Ohio 0 2 3
Colorado 4 6 7
Utah 8 10 11
New York 12 14 15
one three
Ohio 0 2
Colorado 4 6
Utah 8 10
New York 12 14

许多函数,如drop,会修改Series或DataFrame的大小或形状,可以就地修改对象,不会返回新的对象:

1
2
3
4
5
6
7
8
9
···
obj.drop(["a", "b"], inplace=True) # 列表
print(obj)

# 结果
c 2.0
d 3.0
e 4.0
dtype: float64

小心使用inplace,它会销毁所有被删除的数据。

二、索引、选取和过滤

2.1 索引

Series索引(obj[…])的工作方式类似于NumPy数组的索引,只不过Series的索引值不只是整数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import pandas as pd
import numpy as np
obj = pd.Series(np.arange(4.), index=["a", "b", "c", "d"])
print("-----obj-----")
print(obj)

print("----obj['b']------")
print(obj['b'])
print("----obj[1]------")
print(obj[1])
print("----obj[2:4]------")
print(obj[2:4])
print("----obj[['b', 'a', 'd']]------")
print(obj[['b', 'a', 'd']])
print("----obj[[1,3]]------")
print(obj[[1,3]])
print("-----obj[obj < 2]-----") # 布尔过滤
print(obj[obj < 2])

# 结果
-----obj-----
a 0.0
b 1.0
c 2.0
d 3.0
dtype: float64
----obj['b']------
1.0
----obj[1]------
1.0
----obj[2:4]------
c 2.0
d 3.0
dtype: float64
----obj[['b', 'a', 'd']]------
b 1.0
a 0.0
d 3.0
dtype: float64
----obj[[1,3]]------
b 1.0
d 3.0
dtype: float64
-----obj[obj < 2]-----
a 0.0
b 1.0
dtype: float64

利用标签的切片运算与普通的Python切片运算不同,其末端是包含的:

1
2
3
4
5
6
7
···
print(obj["b":"c"])

# 结果
b 1.0
c 2.0
dtype: float64

用切片可以对Series的相应部分进行设置:

1
2
3
4
5
6
7
8
9
10
···
obj["b":"c"] = 5
print(obj)

# 结果
a 0.0
b 5.0
c 5.0
d 3.0
dtype: float64

用一个值或序列对DataFrame进行索引其实就是获取一个或多个列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
···
data = pd.DataFrame(np.arange(16).reshape((4, 4)),index=['Ohio', 'Colorado', 'Utah', 'New York'],columns=['one', 'two', 'three', 'four'])
print("-----data-----")
print(data)

print("-----data['two']-----")
print(data["two"])
print("-----data[['three', 'one']]-----")
print(data[['three', 'one']])

# 结果
-----data-----
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
-----data['two']-----
Ohio 1
Colorado 5
Utah 9
New York 13
Name: two, dtype: int64
-----data[['three', 'one']]-----
three one
Ohio 2 0
Colorado 6 4
Utah 10 8
New York 14 12

这种索引方式有几个特殊的情况。首先通过切片或布尔型数组选取数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
···
# 切片选择
print("切片选择")
print(data[:2]) # 切片选择行
# 布尔筛选
print("布尔筛选")
print(data[data["three"] > 5]) ##注意!!!!

# 结果
切片选择
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
布尔筛选
one two three four
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15

选取行的语法data[:2]十分方便。向[ ]传递单一的元素或列表,就可选择列。

另一种用法是通过布尔型DataFrame(比如下面这个由标量比较运算得出的)进行索引:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
bools = data < 5
print("-----bools----")
print(bools)

data[data < 5] = 0
print(data)

-----bools----
one two three four
Ohio True True True True
Colorado True False False False
Utah False False False False
New York False False False False
one two three four
Ohio 0 0 0 0
Colorado 0 5 6 7
Utah 8 9 10 11
New York 12 13 14 15

这使得DataFrame的语法与NumPy二维数组的语法很像。

2.2 选取

lociloc进行选取。对于DataFrame的行的标签索引,我引入了特殊的标签运算符lociloc。它们可以让你用类似NumPy的标记,使用轴标签(loc)或整数索引(iloc),从DataFrame选择行和列的子集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import pandas as pd
import numpy as np

data = pd.DataFrame(np.arange(16).reshape(4,4), index=['Ohio', 'Colorado', 'Utah', 'New York'],
columns=['one', 'two', 'three', 'four'])
print(data)

# 通过标签选择一行和多列
print("loc选择一行和多列")
print(data.loc['Colorado', ['two', 'three']])

# 用iloc和整数进行选取
print("用iloc和整数进行选取")
print(data.iloc[[1,2], [3,0,1]])


# 结果
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15

loc选择一行和多列
two 5
three 6
Name: Colorado, dtype: int64

用iloc和整数进行选取
four one two
Colorado 7 4 5
Utah 11 8 9

这两个索引函数也适用于一个标签或多个标签的切片:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
···
# 索引函数适用于一个标签或多个标签的切片
print(data.loc[:"Utah", 'two'])
print(data.iloc[:, :3][data.three > 3]) # 注意!!!

# 结果
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15

Ohio 1
Colorado 5
Utah 9
Name: two, dtype: int64

one two three
Colorado 4 5 6
Utah 8 9 10
New York 12 13 14

在pandas中,有多个方法可以选取和重新组合数据。对于DataFrame,下表进行了总结:

对于整数索引标签索引,因为我的表索引可能是整数也可能不是,所以如果轴索引含有整数,数据选取总会使用标签。为了更准确,请使用loc(标签)或iloc(整数)。

三、算术运算和数据对齐

3.1 算术运算及数据对齐

pandas最重要的一个功能是,它可以对不同索引的对象进行算术运算。在将对象相加时,如果存在不同的索引对,则结果的索引就是该索引对的并集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import pandas as pd
import numpy as np

s1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=["a", "c", "d", "e"])
s2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1], index=["a", "c", "e", "f", "g"])
print("-----s1-----")
print(s1)
print("-----s2-----")
print(s2)
print("-----s1 + s2-----")
print(s1 + s2)

# 结果,发现没有相同的索引就引入缺失值
-----s1-----
a 7.3
c -2.5
d 3.4
e 1.5
dtype: float64
-----s2-----
a -2.1
c 3.6
e -1.5
f 4.0
g 3.1
dtype: float64
-----s1 + s2-----
a 5.2
c 1.1
d NaN
e 0.0
f NaN
g NaN
dtype: float64

自动的数据对齐操作在不重叠的索引处引入了NA值。缺失值会在算术运算过程中传播。

对于DataFrame,对齐操作会同时发生在行和列上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
···
df1 = pd.DataFrame(np.arange(9.).reshape((3,3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'])
df2 = pd.DataFrame(np.arange(12.).reshape(4,3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])
print("-----df1-----")
print(df1)
print("-----df2-----")
print(df2)
print("-----df1 + df2-----")
print(df1 + df2)

# 结果
-----df1-----
b c d
Ohio 0.0 1.0 2.0
Texas 3.0 4.0 5.0
Colorado 6.0 7.0 8.0
-----df2-----
b d e
Utah 0.0 1.0 2.0
Ohio 3.0 4.0 5.0
Texas 6.0 7.0 8.0
Oregon 9.0 10.0 11.0
-----df1 + df2-----
b c d e
Colorado NaN NaN NaN NaN
Ohio 3.0 NaN 6.0 NaN
Oregon NaN NaN NaN NaN
Texas 9.0 NaN 12.0 NaN
Utah NaN NaN NaN NaN

因为’c’和’e’列均不在两个DataFrame对象中,在结果中以缺省值呈现。行也是同样。

如果DataFrame对象相加,没有共用的列或行标签,结果都会是空:

1
2
3
4
5
6
7
8
9
···
df1 = pd.DataFrame({'A': [1, 2]})
df2 = pd.DataFrame({'B': [3, 4]})
print(df2-df1)

# 结果
A B
0 NaN NaN
1 NaN NaN

3.2 在算术方法中填充值

在对不同索引的对象进行算术运算时,当一个对象中某个轴标签在另一个对象中找不到时填充一个特殊值(比如0):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list("abcd"))
df2 = pd.DataFrame(np.arange(20.).reshape((4, 5)), columns=list('abcde'))
df2.loc[1, 'b'] = np.nan

print("-----df1-----")
print(df1)
print("-----df2-----")
print(df2)
print("-----df1 + df2-----")
print(df1 + df2)

# 使用df1的add方法,传入df2以及一个fill_value参数
print("-----使用df1的add方法,传入df2以及一个fill_value参数-----")
print(df1.add(df2, fill_value=0))

# 结果,很有意思的add,fill_value()
-----df1-----
a b c d
0 0.0 1.0 2.0 3.0
1 4.0 5.0 6.0 7.0
2 8.0 9.0 10.0 11.0
-----df2-----
a b c d e
0 0.0 1.0 2.0 3.0 4.0
1 5.0 NaN 7.0 8.0 9.0
2 10.0 11.0 12.0 13.0 14.0
3 15.0 16.0 17.0 18.0 19.0
-----df1 + df2-----
a b c d e
0 0.0 2.0 4.0 6.0 NaN
1 9.0 NaN 13.0 15.0 NaN
2 18.0 20.0 22.0 24.0 NaN
3 NaN NaN NaN NaN NaN
-----使用df1的add方法,传入df2以及一个fill_value参数-----
a b c d e
0 0.0 2.0 4.0 6.0 4.0
1 9.0 5.0 13.0 15.0 9.0
2 18.0 20.0 22.0 24.0 14.0
3 15.0 16.0 17.0 18.0 19.0

下表列出了Series和DataFrame的算术方法。它们每个都有一个副本,以字母r开头,它会翻转参数。因此这两个语句是等价的:

1
2
3
4
5
6
7
8
9
10
11
12
13
···
print(1/df1)
print(df1.rdiv(1))

# 结果
a b c d
0 inf 1.000000 0.500000 0.333333
1 0.250 0.200000 0.166667 0.142857
2 0.125 0.111111 0.100000 0.090909
a b c d
0 inf 1.000000 0.500000 0.333333
1 0.250 0.200000 0.166667 0.142857
2 0.125 0.111111 0.100000 0.090909

与此类似,在对Series或DataFrame重新索引时,也可以指定一个填充值:

1
2
3
4
5
6
7
8
···
print(df1.reindex(columns=df2.columns, fill_value=00))

# 结果
a b c d e
0 0.0 1.0 2.0 3.0 0
1 4.0 5.0 6.0 7.0 0
2 8.0 9.0 10.0 11.0 0

四、DataFrame和Series之间的运算

跟不同维度的NumPy数组一样,DataFrame和Series之间算术运算也有明确规定。计算一个二维数组与其某行之间的差:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import numpy as np
arr = np.arange(12.).reshape((3,4))
print("-----arr-----")
print(arr)
print("-----arr[0]-----")
print(arr[0])
print("-----arr-arr[0]-----")
print(arr-arr[0])

# 结果
-----arr-----
[[ 0. 1. 2. 3.]
[ 4. 5. 6. 7.]
[ 8. 9. 10. 11.]]
-----arr[0]-----
[0. 1. 2. 3.]
-----arr-arr[0]-----
[[0. 0. 0. 0.]
[4. 4. 4. 4.]
[8. 8. 8. 8.]]

当我们从arr减去arr[0],每一行都会执行这个操作。这就叫做广播(broadcasting)。DataFrame和Series之间的运算差不多也是如此:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import pandas as pd
import numpy as np
frame = pd.DataFrame(np.arange(12.).reshape((4,3)),
columns=list("bde"),
index=["Utah", "Ohio", "Texas", "Oregon"])
series = frame.iloc[0]
print("-----frame-----")
print(frame)
print("-----series-----")
print(series)

# 默认情况下,DataFrame和Series之间的算术运算会将Series的索引匹配到DataFrame的列,然后沿着行一直向下广播
print("----frame-series-----")
print(frame-series)

# 结果
-----frame-----
b d e
Utah 0.0 1.0 2.0
Ohio 3.0 4.0 5.0
Texas 6.0 7.0 8.0
Oregon 9.0 10.0 11.0
-----series-----
b 0.0
d 1.0
e 2.0
Name: Utah, dtype: float64
----frame-series-----
b d e
Utah 0.0 0.0 0.0
Ohio 3.0 3.0 3.0
Texas 6.0 6.0 6.0
Oregon 9.0 9.0 9.0

如果某个索引值在DataFrame的列或Series的索引中找不到,则参与运算的两个对象就会被重新索引以形成并集:

1
2
3
4
5
6
7
8
9
10
11
12
···
series2 = pd.Series(range(3), index=["b","e","f"])
print("-----frame+series2-----")
print(frame+series2)

# 结果
-----frame+series2-----
b d e f
Utah 0.0 NaN 3.0 NaN
Ohio 3.0 NaN 6.0 NaN
Texas 6.0 NaN 9.0 NaN
Oregon 9.0 NaN 12.0 NaN

如果你希望匹配行且在列上广播,则必须使用算术运算方法。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
···
series3 = frame["d"]
print("-----frame-----")
print(frame)
print("-----series3-----")
print(series3)
print("-----frame.sub(series3, axis='index')") # 传入的轴号就是希望匹配的轴
print(frame.sub(series3, axis="index"))

# 结果
-----frame-----
b d e
Utah 0.0 1.0 2.0
Ohio 3.0 4.0 5.0
Texas 6.0 7.0 8.0
Oregon 9.0 10.0 11.0
-----series3-----
Utah 1.0
Ohio 4.0
Texas 7.0
Oregon 10.0
Name: d, dtype: float64
-----frame.sub(series3, axis='index')
b d e
Utah -1.0 0.0 1.0
Ohio -1.0 0.0 1.0
Texas -1.0 0.0 1.0
Oregon -1.0 0.0 1.0

五、函数应用和映射

Numpy的ufuncs(元素级数组方法)也可以用于操作Pandas对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd
import numpy as np
frame = pd.DataFrame(np.random.randn(4,3), columns=list('bde'),
index=["Utah","Ohio","Texas","Oregon"])
print("-----frame-----")
print(frame)
print("-----np.abs(frame)-----")
print(np.abs(frame))

# 结果
-----frame-----
b d e
Utah -1.921425 1.078646 0.515443
Ohio -0.110403 1.693725 -0.064599
Texas 0.687369 0.624990 0.028280
Oregon -0.059681 1.543326 -0.290820
-----np.abs(frame)-----
b d e
Utah 1.921425 1.078646 0.515443
Ohio 0.110403 1.693725 0.064599
Texas 0.687369 0.624990 0.028280
Oregon 0.059681 1.543326 0.290820

另一个常见的操作是,将函数应用到由各列或行所形成的一维数组上。DataFrame的apply方法即可实现此功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
···
f = lambda x: x.max() - x.min() # 匿名函数
print(frame.apply(f))
print(frame.apply(f, axis=colums))

# 结果
-----frame-----
b d e
Utah 0.705404 1.171658 0.818767
Ohio -1.456053 0.446005 -1.026048
Texas -0.721446 -1.954509 1.030867
Oregon -0.729384 -0.286799 -2.434124
-----np.abs(frame)-----
b d e
Utah 0.705404 1.171658 0.818767
Ohio 1.456053 0.446005 1.026048
Texas 0.721446 1.954509 1.030867
Oregon 0.729384 0.286799 2.434124
----frame.apply(f)----
# 这里的函数f,计算了一个Series的最大值和最小值的差,在frame的每列都执行了一次。结果是一个Series,使用frame的列作为索引
b 2.161457
d 3.126167
e 3.464991
# 如果传递axis='columns'到apply,这个函数会在每行执行
Utah 2.327275
Ohio 1.557350
Texas 1.058961
Oregon 1.479595
dtype: float64

许多最为常见的数组统计功能都被实现成DataFrame的方法(如sum和mean),因此无需使用apply方法。传递到apply的函数不是必须返回一个标量,还可以返回由多个值组成的Series:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
···
def f(x):
return pd.Series([x.min(), x.max()], index=["min", "max"])
print(frame.apply(f))

# 结果
-----frame-----
b d e
Utah 0.315588 -1.207591 1.462784
Ohio 1.115552 0.025713 -0.422715
Texas 0.526468 -0.428600 0.231712
Oregon -2.567452 0.674578 -0.269324
-----np.abs(frame)-----
b d e
Utah 0.315588 1.207591 1.462784
Ohio 1.115552 0.025713 0.422715
Texas 0.526468 0.428600 0.231712
Oregon 2.567452 0.674578 0.269324
b d e
min -2.567452 -1.207591 -0.422715
max 1.115552 0.674578 1.462784

元素级的Python函数也是可以用的。假如你想得到frame中各个浮点值的格式化字符串,使用applymap即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
···
format = lambda x: '.2f' % x
print(frame.applymap(format))

# 结果
-----frame-----
b d e
Utah 1.508442 -1.214953 -1.508734
Ohio -0.932995 1.465612 -1.866688
Texas 0.051614 -0.457426 -1.322147
Oregon -0.368997 -1.162484 0.916135
-----np.abs(frame)-----
b d e
Utah 1.508442 1.214953 1.508734
Ohio 0.932995 1.465612 1.866688
Texas 0.051614 0.457426 1.322147
Oregon 0.368997 1.162484 0.916135
b d e
Utah 1.51 -1.21 -1.51
Ohio -0.93 1.47 -1.87
Texas 0.05 -0.46 -1.32
Oregon -0.37 -1.16 0.92

之所以叫做applymap,是因为Series有一个用于应用元素级函数的map方法:

1
2
3
4
5
6
7
8
9
···
print(frame["e"].map(format))

# 结果
Utah -0.78
Ohio -2.09
Texas -0.58
Oregon 1.13
Name: d, dtype: object

六、排序和排名

6.1 按index排序

根据条件对数据集排序(sorting)也是一种重要的内置运算。要对行或列索引进行排序(按字典顺序),可使用sort_index方法,它将返回一个已排序的新对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
import pandas as pd

obj = pd.Series(range(4), index=["d", "a", "b", "c"])
print("-----obj.sort_index()")
print(obj.sort_index())

# 结果
-----obj.sort_index()
a 1
b 2
c 3
d 0
dtype: int64

对于DataFrame,则可以根据任意一个轴上的索引进行排序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import numpy as np
import pandas as pd

frame = pd.DataFrame(np.arange(8).reshape((2,4)),
index = ["three", "one"],
columns = ["d", "a", "b", "c"])
print("-----frame.sort_index()-----")
print(frame)
print("-----frame.sort_index(axis=1)----")
print(frame.sort_index(axis=1))

# 结果
-----frame.sort_index()-----
d a b c
one 4 5 6 7
three 0 1 2 3
-----frame.sort_index(axis=1)----
a b c d
three 1 2 3 0
one 5 6 7 4

数据默认是按升序排序的,但也可以降序排序:

1
2
3
4
5
6
7
8
···
print(frame.sort_index(axis=1, ascending=False))

# 结果
-----frame.sort_index(axis=1, ascending=False)
d c b a
three 0 3 2 1
one 4 7 6 5

6.2 按values排序

若要按值对Series进行排序,可使用其sort_values方法:

1
2
3
4
5
6
7
8
9
10
11
import pandas as pd
obj = pd.Series([4, 7, -3, 2])
print(obj.sort_values())

# 结果
-----obj.sort-values()-----
2 -3
3 2
0 4
1 7
dtype: int64

在排序时,任何缺失值默认都会被放到Series的末尾:

1
2
3
4
5
6
7
8
9
10
11
import pandas as pd
obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])
print(obj.sort_values())

# 结果
3 -3.0
4 2.0
0 4.0
2 7.0
1 NaN
dtype: float64

当排序一个DataFrame时,可能希望根据一个或多个列中的值进行排序。将一个或多个列的名字传递给sort_values的by选项即可达到该目的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import numpy as np
import pandas as pd

frame = pd.DataFrame({'b': [4, 7, -3, 2], 'a': [0, 1, 0, 1]})
print("-----frame-----")
print(frame)
print("----frame.sort_values(by='b')-----")
print(frame.sort_values(by='b'))

# 要根据多个列进行排序,传入名称的列表即可
print("----frame.sort_values(by=['a', 'b'])-----")
print(frame.sort_values(by=['a', 'b']))

# 结果
-----frame-----
b a
0 4 0
1 7 1
2 -3 0
3 2 1
----frame.sort_values(by='b')-----
b a
2 -3 0
3 2 1
0 4 0
1 7 1
----frame.sort_values(by=['a', 'b'])-----
b a
2 -3 0
0 4 0
3 2 1
1 7 1

排名会从1开始一直到数组中有效数据的数量,就是先根据a确定一个状态,之后按照前一个状态排序。

6.3 rank方法

介绍Series和DataFrame的rank方法。默认情况下,rank是通过“为各组分配一个平均排名”的方式破坏平级关系的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd
obj = pd.Series([7, -5, 7, 4, 2, 0, 4])
print("-----obj.rank-----")
print(obj.rank)

# 结果
-----obj.rank()-----
0 6.5
1 1.0
2 6.5
3 4.5
4 3.0
5 2.0
6 4.5
dtype: float64

也可以根据值在原数据中出现的顺序给出排名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
···
print("----obj.rank(method = 'first')")
print(obj.rank(method = 'first'))

# 结果
# 这里,条目0和2没有使用平均排名6.5,它们被设成了6和7,因为数据中标签0位于标签2的前面。
----obj.rank(method = 'first')
0 6.0
1 1.0
2 7.0
3 4.0
4 3.0
5 2.0
6 5.0
dtype: float64

也可以按降序进行排名:

1
2
3
4
5
6
7
8
9
10
···
-----obj.rank(ascending=False, method='max')-----
0 2.0
1 7.0
2 2.0
3 4.0
4 5.0
5 6.0
6 4.0
dtype: float64

下表列出了所有用于破坏平级关系的method选项。DataFrame可以在行或列上计算排名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
···
frame = pd.DataFrame({'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1],'c': [-2, 5, 8, -2.5]})

print("-----frame-----")
print(frame)
print("-----frame.rank(axis='columns')")
print(frame.rank(axis='columns'))

# 结果
-----frame-----
b a c
0 4.3 0 -2.0
1 7.0 1 5.0
2 -3.0 0 8.0
3 2.0 1 -2.5
-----frame.rank(axis='columns')
b a c
0 3.0 2.0 1.0
1 3.0 1.0 2.0
2 1.0 2.0 3.0
3 3.0 2.0 1.0
方法 说明
average 默认:在相等分组中,为各个值分配平均排名
min 使用整个分组的最小排名
max 使用整个分组的最大排名
first 按值在原始数据中的出现顺序分配排名
dense 类似于min方法,但是排名总是在分组之间增加1,而不是组中相同的元素数