返回介绍

5.2 Essential Functionality 主要功能

发布于 2023-07-20 22:46:19 字数 33548 浏览 0 评论 0 收藏 0

接下来介绍 pandas 中的一些主要功能,这里只介绍一些经常用到的。

1 Reindexing(重新索引)

pandas 中一个重要的方法是 reindex,已实施在创建 object 的时候遵照一个新的 index。如下例:

import pandas as pd
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 能更改 index,如果没有对应 index 的话会引入缺失数据:

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

在处理时间序列这样的数据时,我们可能需要在 reindexing 的时候需要修改值。method 选项能做到这一点,比如设定 method 为 ffill:

obj3 = pd.Series(['bule', 'purple', 'yellow'], index=[0, 2, 4])
obj3
0      bule
2    purple
4    yellow
dtype: object
obj3.reindex(range(6), method='ffill')
0      bule
1      bule
2    purple
3    purple
4    yellow
5    yellow
dtype: object

对于 DataFrame,reindex 能更改 row index,或 column index。reindex the rows:

import numpy as np
frame = pd.DataFrame(np.arange(9).reshape(3, 3),
                     index=['a', 'c', 'd'],
                     columns=['Ohio', 'Texas', 'California'])
frame
 OhioTexasCalifornia
a012
c345
d678
frame2 = frame.reindex(['a', 'b', 'c', 'd'])
frame2
 OhioTexasCalifornia
a0.01.02.0
bNaNNaNNaN
c3.04.05.0
d6.07.08.0

更改 columns index:

states = ['Texas', 'Utah', 'California']
frame.reindex(columns=states)
 TexasUtahCalifornia
a1NaN2
c4NaN5
d7NaN8

还可以使用 loc 更简洁的 reindex:

frame.loc[['a', 'b', 'c', 'd'], states]
 TexasUtahCalifornia
a1.0NaN2.0
bNaNNaNNaN
c4.0NaN5.0
d7.0NaN8.0

2 Dropping Entries from an Axis (按轴删除记录)

对于 series,drop 回返回一个新的 object,并删去你制定的 axis 的值:

obj = pd.Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])
obj
a    0.0
b    1.0
c    2.0
d    3.0
e    4.0
dtype: float64
new_obj = obj.drop('c')
new_obj
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64
obj.drop(['d', 'c'])
a    0.0
b    1.0
e    4.0
dtype: float64

对于 DataFrame,index 能按行或列的 axis 来删除:

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

行处理:如果 a sequence of labels(一个标签序列)来调用 drop,会删去 row labels(axis 0):

data.drop(['Colorado', 'Ohio'])
 onetwothreefour
Utah891011
New York12131415

列处理:drop 列的话,设定 axis=1 或 axis='columns':

data.drop('two', axis=1)
 onethreefour
Ohio023
Colorado467
Utah81011
New York121415
data.drop(['two', 'four'], axis='columns')
 onethree
Ohio02
Colorado46
Utah810
New York1214

drop 也可以不返回一个新的 object,而是直接更改 series or dataframe in-place:

obj.drop('c', inplace=True)
obj
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64

3 Indexing, Selection, and Filtering(索引,选择,过滤)

series indexing(obj[...]) 相当于 numpy 的 array indexing, 而且除了整数,还可以使用 series 的 index:

obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd'])
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

用 label 来 slicing(切片)的时候,和 python 的切片不一样的在于,会包括尾节点:

obj['b':'c']
b    1.0
c    2.0
dtype: float64

可以直接给选中的 label 更改值:

obj['b':'c'] = 5
obj
a    0.0
b    5.0
c    5.0
d    3.0
dtype: float64

而对于 DataFrame,indexing 可以通过一个值或序列,选中一个以上的列:

data = pd.DataFrame(np.arange(16).reshape((4, 4)),
                    index=['Ohio', 'Colorado', 'Utah', 'New York'],
                    columns=['one', 'two', 'three', 'four'])
data
 onetwothreefour
Ohio0123
Colorado4567
Utah891011
New York12131415
data['two']
Ohio         1
Colorado     5
Utah         9
New York    13
Name: two, dtype: int64
data[['three', 'one']]
 threeone
Ohio20
Colorado64
Utah108
New York1412

dataframe 的 indexing 有一些比较特别的方式。比如通过布尔数组:

data[:2]
 onetwothreefour
Ohio0123
Colorado4567
data[data['three'] > 5]
 onetwothreefour
Colorado4567
Utah891011
New York12131415

行选择的语法格式 data[:2] 是很方便的。给 [] 里传入一个 list 的话,可以选择列。

另一种方法是用 boolean dataframe:

data < 5
 onetwothreefour
OhioTrueTrueTrueTrue
ColoradoTrueFalseFalseFalse
UtahFalseFalseFalseFalse
New YorkFalseFalseFalseFalse
data[data < 5] = 0
data
 onetwothreefour
Ohio0000
Colorado0567
Utah891011
New York12131415

Selection with loc and iloc(用 loc 和 iloc 来选择)

对于 label-indexing on rows, 我们介绍特别的索引符,loc and iloc. 这两个方法能通过 axis labels(loc)或 integer(iloc),来选择行或列。

一个列子,选中一行多列 by label:

data
 onetwothreefour
Ohio0000
Colorado0567
Utah891011
New York12131415
data.loc['Colorado', ['two', 'three']]
two      5
three    6
Name: Colorado, dtype: int64

同 iloc 实现相同的效果:

data.iloc[2, [3, 0, 1]]
four    11
one      8
two      9
Name: Utah, dtype: int64
data.iloc[2] # 一行
one       8
two       9
three    10
four     11
Name: Utah, dtype: int64
data.iloc[[1, 2], [3, 0, 1]]
 fouronetwo
Colorado705
Utah1189

indexing 函数也能用于切片,不论是 single labels 或 lists of labels:

data.loc[:'Utah', 'two']
Ohio        0
Colorado    5
Utah        9
Name: two, dtype: int64
data.iloc[:, :3][data.three > 5]
 onetwothree
Colorado056
Utah8910
New York121314

pandas 中有很多用于选择和重新选择数据的方法。

注意:当设计 padnas 的时候,作者发现 frame[:, col]这样的语法是比较冗长的,因为这是会被经常用到的一个功能。作者把一些 indexing 的功能(lable or integer)集成在了 ix 这个方法上。实际中,因为这种 label 和 integer 都可以用的方式很方便,于是 pandas team 设计了 loc 和 ilco 来实现 label-based 和 integer-based indexing.

虽然 ix indexing 依然错在,但是已经过时,不推荐使用。

4 Integer Indexes(整数索引)

一些新手再用 integer 来 index 的时候,总是会被绊倒。因为这种方法和 python 用于 list 和 tuple 的 indexing 方法不同。

比如,你不希望下面的代码出现 error:

ser = pd.Series(np.arange(3.))
ser
0    0.0
1    1.0
2    2.0
dtype: float64
ser[-1]

看到了,pandas 在整数索引上可能会出错。这里我们有一个 index 包括 0,1,2,但是猜测用户想要什么是很困难的:

ser
0    0.0
1    1.0
2    2.0
dtype: float64

另一方面,如果用非整数来做 index,就没有歧义了:

ser2 = pd.Series(np.arange(3.), index=['a', 'b', 'c'])
ser2[-1]
2.0

为了保持连贯性,如果 axis index 里包含 integer,那么选择数据的时候,就会是 label-orented. 为了更精确地选择,使用 loc (for label)或 ilco (for integers):

ser[:1]
0    0.0
dtype: float64
ser.loc[:1]
0    0.0
1    1.0
dtype: float64
ser.iloc[:1]
0    0.0
dtype: float64

5 Arithmetic and Data Alignment (算数和数据对齐)

pandas 一个有用的 feature 就是,不同 index 的 obejct 之间的算数计算。如果两个 object 相加,但他们各自的 index 并不相同,最后结果得到的 index 是这两个 index 的合集:

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'])
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    9.4
c    1.1
d    NaN
e    0.0
f    NaN
g    NaN
dtype: float64

这种数据对齐的方式(internal data alignment)引入了很多缺失值在没有陈赫的位置上。这些缺失值会被用在之后的算数计算中。

在 DataFrame 中,数据对齐同时发生在行和列上:

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'])
df1
 bcd
Ohio0.01.02.0
Texas3.04.05.0
Colorado6.07.08.0
df2
 bde
Utah0.01.02.0
Ohio3.04.05.0
Texas6.07.08.0
Oregon9.010.011.0

相加的结果就是两个 DataFrame,行和列的合集:

df1 + df2
 bcde
ColoradoNaNNaNNaNNaN
Ohio3.0NaN6.0NaN
OregonNaNNaNNaNNaN
Texas9.0NaN12.0NaN
UtahNaNNaNNaNNaN

因为'c'和'e'列都不在两个 DataFrame 里,所有全是缺失值。对于行,即使有相同的,但列不一样的话也会是缺失值。

如果两个 DataFrame 相加,而且没有 column 和 row,结果会全是 null:

df1 = pd.DataFrame({'A': [1, 2]})
df2 = pd.DataFrame({'B': [3, 4]})
df1
 A
01
12
df2
 B
03
14
df1 - df2
 AB
0NaNNaN
1NaNNaN

Arithmetic methods with fill values (带填充值的算数方法)

对于上面那些缺失值,我们想要填上 0:

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
df1
 abcd
00.01.02.03.0
14.05.06.07.0
28.09.010.011.0
df2
 abcde
00.01.02.03.04.0
15.0NaN7.08.09.0
210.011.012.013.014.0
315.016.017.018.019.0

不使用添加方法的结果:

df1 + df2
 abcde
00.02.04.06.0NaN
19.0NaN13.015.0NaN
218.020.022.024.0NaN
3NaNNaNNaNNaNNaN

使用 fill_value:

df1.add(df2, fill_value=0)
 abcde
00.02.04.06.04.0
19.05.013.015.09.0
218.020.022.024.014.0
315.016.017.018.019.0

每一个都有一个配对的,以 r 开头,意思是反转:

1 / df1
 abcd
0inf1.0000000.5000000.333333
10.2500000.2000000.1666670.142857
20.1250000.1111110.1000000.090909
df1.rdiv(1)
 abcd
0inf1.0000000.5000000.333333
10.2500000.2000000.1666670.142857
20.1250000.1111110.1000000.090909

在 reindex(重建索引)的时候,也可以使用 fill_value:

df1.reindex(columns=df2.columns, fill_value=0)
 abcde
00.01.02.03.00
14.05.06.07.00
28.09.010.011.00

Operations between DataFrame and Series (DataFrame 和 Series 之间的操作)

先举个 numpy 的例子帮助理解,可以考虑成一个二维数组和它的一行:

arr = np.arange(12.).reshape((3, 4))
arr
array([[  0.,   1.,   2.,   3.],
       [  4.,   5.,   6.,   7.],
       [  8.,   9.,  10.,  11.]])
arr[0]
array([ 0.,  1.,  2.,  3.])
arr - arr[0]
array([[ 0.,  0.,  0.,  0.],
       [ 4.,  4.,  4.,  4.],
       [ 8.,  8.,  8.,  8.]])

可以看到,这个减法是用在了每一行上。这种操作叫 broadcasting,在 Appendix A 有更详细的解释。DataFrame 和 Series 的操作也类似:

frame = pd.DataFrame(np.arange(12.).reshape((4, 3)),
                     columns=list('bde'),
                    index=['Utah', 'Ohio', 'Texas', 'Oregon'])
series = frame.iloc[0]
frame
 bde
Utah0.01.02.0
Ohio3.04.05.0
Texas6.07.08.0
Oregon9.010.011.0
series
b    0.0
d    1.0
e    2.0
Name: Utah, dtype: float64

可以理解为 series 的 index 与 dataframe 的列匹配,broadcasting down the rows(向下按行广播):

frame - series
 bde
Utah0.00.00.0
Ohio3.03.03.0
Texas6.06.06.0
Oregon9.09.09.0

如果一个 index 既不在 DataFrame 的 column 中,也不再 series 里的 index 中,那么结果也是合集:

series2 = pd.Series(range(3), index=['b', 'e', 'f'])
frame + series2
 bdef
Utah0.0NaN3.0NaN
Ohio3.0NaN6.0NaN
Texas6.0NaN9.0NaN
Oregon9.0NaN12.0NaN

如果想要广播列,去匹配行,必须要用到算数方法:

series3 = frame['d']
frame
 bde
Utah0.01.02.0
Ohio3.04.05.0
Texas6.07.08.0
Oregon9.010.011.0
series3
Utah       1.0
Ohio       4.0
Texas      7.0
Oregon    10.0
Name: d, dtype: float64
frame.sub(series3, axis='index')
 bde
Utah-1.00.01.0
Ohio-1.00.01.0
Texas-1.00.01.0
Oregon-1.00.01.0

axis 参数就是用来匹配轴的。在这个例子里是匹配 dataframe 的 row index( axis='index or axis=0 ),然后再广播。

6 Function Application and Mapping (函数应用和映射)

numpy 的 ufuncs(element-wise 数组方法)也能用在 pandas 的 object 上:

frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'), 
                     index=['Utah', 'Ohio', 'Texas', 'Oregon'])
frame
 bde
Utah-0.8104350.194448-0.705901
Ohio-0.8862750.5536401.066754
Texas0.189898-0.056108-0.159926
Oregon0.4483030.439650-1.351029
np.abs(frame)
 bde
Utah0.8104350.1944480.705901
Ohio0.8862750.5536401.066754
Texas0.1898980.0561080.159926
Oregon0.4483030.4396501.351029

另一个常用的操作是把一个用在一维数组上的函数,应用在一行或一列上。要用到 DataFrame 中的 apply 函数:

f = lambda x: x.max() - x.min()
frame.apply(f)
b    1.334579
d    0.609748
e    2.417783
dtype: float64

这里函数 f,计算的是一个 series 中最大值和最小值的差,在 frame 中的每一列,这个函数被调用一次。作为结果的 series,它的 index 就是 frame 的 column。

如果你传入 axis='column' 用于 apply,那么函数会被用在每一行:

frame.apply(f, axis='columns')
Utah      1.004883
Ohio      1.953030
Texas     0.349825
Oregon    1.799333
dtype: float64

像是 sum, mean 这样的数组统计方法,DataFrame 中已经集成了,所以没必要用 apply。

apply 不会返回标量,只会返回一个含有多个值的 series:

def f(x): 
    return pd.Series([x.min(), x.max()], index=['min', 'max'])
frame
 bde
Utah-0.8104350.194448-0.705901
Ohio-0.8862750.5536401.066754
Texas0.189898-0.056108-0.159926
Oregon0.4483030.439650-1.351029
frame.apply(f)
 bde
min-0.886275-0.056108-1.351029
max0.4483030.5536401.066754

element-wise 的 python 函数也能用。假设想要格式化 frame 中的浮点数,变为 string。可以用 apply map:

format = lambda x: '%.2f' % x
frame.applymap(format)
 bde
Utah-0.810.19-0.71
Ohio-0.890.551.07
Texas0.19-0.06-0.16
Oregon0.450.44-1.35

applymap 的做法是,series 有一个 map 函数,能用来实现 element-wise 函数:

frame['e'].map(format)
Utah      -0.71
Ohio       1.07
Texas     -0.16
Oregon    -1.35
Name: e, dtype: object

7 Sorting and Ranking (排序)

按 row 或 column index 来排序的话,可以用 sort_index 方法,会返回一个新的 object:

obj = pd.Series(range(4), index=['d', 'a', 'b', 'c'])
obj.sort_index()
a    1
b    2
c    3
d    0
dtype: int64

在 DataFrame,可以用 index 或其他 axis 来排序:

frame = pd.DataFrame(np.arange(8).reshape((2, 4)),
                     index=['three', 'one'],
                     columns=['d', 'a', 'b', 'c'])
frame
 dabc
three0123
one4567
frame.sort_index()
 dabc
one4567
three0123
frame.sort_index(axis=1)
 abcd
three1230
one5674

默认是升序,可以设置降序:

frame.sort_index(axis=1, ascending=False)
 dcba
three0321
one4765

通过值来排序,用 sort_values 方法:

obj = pd.Series([4, 7, -3, 2])
obj.sort_values()
2   -3
3    2
0    4
1    7
dtype: int64

缺失值会被排在最后:

obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])
obj.sort_values()
4   -3.0
5    2.0
0    4.0
2    7.0
1    NaN
3    NaN
dtype: float64

对于一个 DataFrame,可以用一列或多列作为 sort keys。这样的话,只需要把一列多多列的名字导入到 sort_values 即可:

frame = pd.DataFrame({'b': [4, 7, -3, 2], 'a': [0, 1, 0, 1]})
frame
 ab
004
117
20-3
312
frame.sort_values(by='b')
 ab
20-3
312
004
117

多列排序的话,传入一个 list of names:

frame.sort_values(by=['a', 'b'])
 ab
20-3
004
312
117

ranking(排名)是给有效的数据分配数字。rank 方法能用于 series 和 DataFrame,rank 方法默认会给每个 group 一个 mean rank(平均排名)。rank 表示在这个数在原来的 Series 中排第几名,有相同的数,取其排名平均(默认)作为值:

obj = pd.Series([7, -5, 7, 4, 2, 0, 4])
obj
0    7
1   -5
2    7
3    4
4    2
5    0
6    4
dtype: int64
obj.sort_values()
1   -5
5    0
4    2
3    4
6    4
0    7
2    7
dtype: int64
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

在 obj 中,4 和 4 的排名是第 4 名和第五名,取平均得 4.5。7 和 7 的排名分别是第六名和第七名,则其排名取平均得 6.5。

rank 也可以根据数据被观测到的顺序来设定:

obj
0    7
1   -5
2    7
3    4
4    2
5    0
6    4
dtype: int64
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

这里没有给 0 和 2(指两个数字 7)赋予 average rank 6.5,而是给第一个看到的 7(label 0)设置 rank 为 6,第二个看到的 7(label 2)设置 rank 为 7。

也可以设置降序:

# Assign tie values the maximum rank in the group
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

dataframe 可以根据行或列来计算 rank:

frame = pd.DataFrame({'b': [4.3, 7, -3, 2],
                      'a': [0, 1, 0, 1],
                      'c': [-2, 5, 8, -2.5]})
frame
 abc
004.3-2.0
117.05.0
20-3.08.0
312.0-2.5
frame.rank(axis='columns') # columns 表示列与列之间的排序(即每一行里数据间的排序)
 abc
02.03.01.0
11.03.02.0
22.01.03.0
32.03.01.0

8 Axis Indexes with Duplicate Labels (有重复 label 的轴索引)

我们看到的所有例子都有 unique axis labels(index values),唯一的轴标签(索引值)。一些 pandas 函数(reindex),需要 label 是唯一的,但这并是不强制的。比如下面有一个重复的索引:

obj = pd.Series(range(5), index=['a', 'a', 'b', 'b', 'c'])
obj
a    0
a    1
b    2
b    3
c    4
dtype: int64

index 的 is_unique 特性能告诉我们 label 是否是唯一的:

obj.index.is_unique
False

数据选择对于重复 label 则表现有点不同。如果一个 label 有多个值,那么就会返回一个 series, 如果是 label 只对应一个值的话,会返回一个标量:

obj['a']
a    0
a    1
dtype: int64
obj['c']
4

这个选择的逻辑也应用于 DataFrame:

df = pd.DataFrame(np.random.randn(4, 3), index=['a', 'a', 'b', 'b'])
df
 012
a-0.314526-1.3138610.823529
a0.994028-0.442338-0.846985
b-1.340453-0.0316120.044791
b-0.919341-0.409164-1.297257
df.loc['b']
 012
b-1.340453-0.0316120.044791
b-0.919341-0.409164-1.297257

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文