Python 数据分析三剑客之 Pandas(四):函数应用/映射/排序和层级索引


Pandas 系列文章:


专栏:

推荐学习资料与网站:


这里是一段防爬虫文本,请读者忽略。
本文原创首发于 CSDN,作者 TRHX。
博客首页:https://itrhx.blog.csdn.net/
本文链接:https://itrhx.blog.csdn.net/article/details/106758103
未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!

【01x00】函数应用和映射

Pandas 可直接使用 NumPy 的 ufunc(元素级数组方法) 函数:

>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.DataFrame(np.random.randn(5,4) - 1)
>>> obj
          0         1         2         3
0 -0.228107  1.377709 -1.096528 -2.051001
1 -2.477144 -0.500013 -0.040695 -0.267452
2 -0.485999 -1.232930 -0.390701 -1.947984
3 -0.839161 -0.702802 -1.756359 -1.873149
4  0.853121 -1.540105  0.621614 -0.583360
>>> 
>>> np.abs(obj)
          0         1         2         3
0  0.228107  1.377709  1.096528  2.051001
1  2.477144  0.500013  0.040695  0.267452
2  0.485999  1.232930  0.390701  1.947984
3  0.839161  0.702802  1.756359  1.873149
4  0.853121  1.540105  0.621614  0.583360

函数映射:在 Pandas 中 apply 方法可以将函数应用到列或行上,可以通过设置 axis 参数来指定行或列,默认 axis = 0,即按列映射:

>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.DataFrame(np.random.randn(5,4) - 1)
>>> obj
          0         1         2         3
0 -0.707028 -0.755552 -2.196480 -0.529676
1 -0.772668  0.127485 -2.015699 -0.283654
2  0.248200 -1.940189 -1.068028 -1.751737
3 -0.872904 -0.465371 -1.327951 -2.883160
4 -0.092664  0.258351 -1.010747 -2.313039
>>> 
>>> obj.apply(lambda x : x.max())
0    0.248200
1    0.258351
2   -1.010747
3   -0.283654
dtype: float64
>>>
>>> obj.apply(lambda x : x.max(), axis=1)
0   -0.529676
1    0.127485
2    0.248200
3   -0.465371
4    0.258351
dtype: float64

另外还可以通过 applymap 将函数映射到每个数据上:

>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.DataFrame(np.random.randn(5,4) - 1)
>>> obj
          0         1         2         3
0 -0.772463 -1.597008 -3.196100 -1.948486
1 -1.765108 -1.646421 -0.687175 -0.401782
2  0.275699 -3.115184 -1.429063 -1.075610
3 -0.251734 -0.448399 -3.077677 -0.294674
4 -1.495896 -1.689729 -0.560376 -1.808794
>>> 
>>> obj.applymap(lambda x : '%.2f' % x)
       0      1      2      3
0  -0.77  -1.60  -3.20  -1.95
1  -1.77  -1.65  -0.69  -0.40
2   0.28  -3.12  -1.43  -1.08
3  -0.25  -0.45  -3.08  -0.29
4  -1.50  -1.69  -0.56  -1.81

【02x00】排序

【02x01】sort_index() 索引排序

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

在 Series 和 DataFrame 中的基本语法如下:

Series.sort_index(self,
                  axis=0,
                  level=None,
                  ascending=True,
                  inplace=False,
                  kind='quicksort',
                  na_position='last',
                  sort_remaining=True,
                  ignore_index: bool = False)
DataFrame.sort_index(self,
                     axis=0,
                     level=None,
                     ascending=True,
                     inplace=False,
                     kind='quicksort',
                     na_position='last',
                     sort_remaining=True,
                     ignore_index: bool = False)

官方文档:

常用参数描述如下:

参数 描述
axis 指定轴排序,0 or ‘index’1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’
ascending True时升序排序(默认),为 False时降序排序
kind 排序方法,quicksort:快速排序(默认);'mergesort’:归并排序;'heapsort':堆排序;具体可参见 numpy.sort()

在 Series 中的应用(按照索引 index 排序):

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

在 DataFrame 中的应用(可按照索引 index 或列标签 columns 排序):

>>> import pandas as pd
>>> obj = pd.DataFrame(np.arange(8).reshape((2, 4)), index=['three', 'one'], columns=['d', 'a', 'b', 'c'])
>>> obj
       d  a  b  c
three  0  1  2  3
one    4  5  6  7
>>> 
>>> obj.sort_index()
       d  a  b  c
one    4  5  6  7
three  0  1  2  3
>>> 
>>> obj.sort_index(axis=1)
       a  b  c  d
three  1  2  3  0
one    5  6  7  4
>>> 
>>> obj.sort_index(axis=1, ascending=False)
       d  c  b  a
three  0  3  2  1
one    4  7  6  5

【02x02】sort_values() 按值排序

在 Series 和 DataFrame 中的基本语法如下:

Series.sort_values(self,
                   axis=0,
                   ascending=True,
                   inplace=False,
                   kind='quicksort',
                   na_position='last',
                   ignore_index=False)
DataFrame.sort_values(self,
                      by,
                      axis=0,
                      ascending=True,
                      inplace=False,
                      kind='quicksort',
                      na_position='last',
                      ignore_index=False)

官方文档:

常用参数描述如下:

参数 描述
by DataFrame 中的必须参数,指定列的值进行排序,Series 中没有此参数
axis 指定轴排序,0 or ‘index’1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’
ascending True时升序排序(默认),为 False时降序排序
kind 排序方法,quicksort:快速排序(默认);'mergesort’:归并排序;'heapsort':堆排序;具体可参见 numpy.sort()

在 Series 中的应用,按照值排序,如果有缺失值,默认都会被放到 Series 的末尾:

>>> import pandas as pd
>>> obj = pd.Series([4, 7, -3, 2])
>>> obj
0    4
1    7
2   -3
3    2
dtype: int64
>>> 
>>> 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
0    4.0
1    NaN
2    7.0
3    NaN
4   -3.0
5    2.0
dtype: float64
>>> 
>>> obj.sort_values()
4   -3.0
5    2.0
0    4.0
2    7.0
1    NaN
3    NaN
dtype: float64

在 DataFrame 中的应用,有时候可能希望根据一个或多个列中的值进行排序。将一个或多个列的名字传递给 sort_values()by 参数即可达到该目的,当传递多个列时,首先会对第一列进行排序,若第一列有相同的值,再根据第二列进行排序,依次类推:

>>> import pandas as pd
>>> obj = pd.DataFrame({'a': [4, 4, -3, 2], 'b': [0, 1, 0, 1], 'c': [6, 4, 1, 3]})
>>> obj
   a  b  c
0  4  0  6
1  4  1  4
2 -3  0  1
3  2  1  3
>>> 
>>> obj.sort_values(by='c')
   a  b  c
2 -3  0  1
3  2  1  3
1  4  1  4
0  4  0  6
>>> 
>>> obj.sort_values(by='c', ascending=False)
   a  b  c
0  4  0  6
1  4  1  4
3  2  1  3
2 -3  0  1
>>>
>>> obj.sort_values(by=['a', 'b'])
   a  b  c
2 -3  0  1
3  2  1  3
0  4  0  6
1  4  1  4
>>> import pandas as pd
>>> obj = pd.DataFrame({'a': [4, 4, -3, 2], 'b': [0, 1, 0, 1], 'c': [6, 4, 1, 3]}, index=['A', 'B', 'C', 'D'])
>>> obj
   a  b  c
A  4  0  6
B  4  1  4
C -3  0  1
D  2  1  3
>>> 
>>> obj.sort_values(by='B', axis=1)
   b  a  c
A  0  4  6
B  1  4  4
C  0 -3  1
D  1  2  3

【02x03】rank() 返回排序后元素索引

rank() 函数会返回一个对象,对象的值是原对象经过排序后的索引值,即下标。

在 Series 和 DataFrame 中的基本语法如下:

Series.rank(self: ~ FrameOrSeries,
            axis=0,
            method: str = 'average',
            numeric_only: Union[bool, NoneType] = None,
            na_option: str = 'keep',
            ascending: bool = True,
            pct: bool = False)
DataFrame.rank(self: ~ FrameOrSeries,
               axis=0,
               method: str = 'average',
               numeric_only: Union[bool, NoneType] = None,
               na_option: str = 'keep',
               ascending: bool = True,
               pct: bool = False)

官方文档:

常用参数描述如下:

参数 描述
axis 指定轴排序,0 or ‘index’1 or ‘columns’,只有在 DataFrame 中才有 1 or 'columns’
method 有相同值时,如何处理:
‘average’:默认值,去两个相同索引的平均值;‘min’:取两个相同索引的最小值;
‘max’:取两个相同索引的最大值;‘first’:按照出现的先后顺序;
‘dense’:和 'min' 差不多,但是各组之间总是+1的,不太好解释,可以看后面的示例
ascending True时升序排序(默认),为 False时降序排序

在 Series 中的应用,按照值排序,如果有缺失值,默认都会被放到 Series 的末尾:

>>> import pandas as pd
>>> 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.rank()
0    6.5  # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,默认取平均值,即 6.5
1    1.0
2    6.5
3    4.5  # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,默认取平均值,即 4.5
4    3.0
5    2.0
6    4.5
dtype: float64
>>> 
>>> obj.rank(method='first')
0    6.0  # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,按照第一次出现排序,分别为 6 和 7
1    1.0
2    7.0
3    4.0  # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,按照第一次出现排序,分别为 4 和 5
4    3.0
5    2.0
6    5.0
dtype: float64
>>> 
>>> obj.rank(method='dense')
0    5.0  # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,按照最小值排序,但 dense 规定间隔为 1 所以为 5
1    1.0
2    5.0
3    4.0  # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,按照最小值排序,即 4
4    3.0
5    2.0
6    4.0
dtype: float64
>>> 
>>> obj.rank(method='min')
0    6.0  # 第 0 个和第 2 个值从小到大排名分别为 6 和 7,按照最小值排序,即 6
1    1.0
2    6.0
3    4.0  # 第 3 个和第 6 个值从小到大排名分别为 4 和 5,按照最小值排序,即 4
4    3.0
5    2.0
6    4.0
dtype: float64

在 DataFrame 中可以使用 axis 参数来指定轴:

>>> import pandas as pd
>>> obj = pd.DataFrame({'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1], 'c': [-2, 5, 8, -2.5]})
>>> obj
     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
>>> 
>>> obj.rank()
     b    a    c
0  3.0  1.5  2.0
1  4.0  3.5  3.0
2  1.0  1.5  4.0
3  2.0  3.5  1.0
>>> 
>>> obj.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

这里是一段防爬虫文本,请读者忽略。
本文原创首发于 CSDN,作者 TRHX。
博客首页:https://itrhx.blog.csdn.net/
本文链接:https://itrhx.blog.csdn.net/article/details/106758103
未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!

【03x00】层级索引

【03x01】认识层级索引

以下示例将创建一个 Series 对象, 索引 Index 由两个子 list 组成,第一个子 list 是外层索引,第二个 list 是内层索引:

>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])
>>> obj
a  0   -0.201536
   1   -0.629058
   2    0.766716
b  0   -1.255831
   1   -0.483727
   2   -0.018653
c  0    0.788787
   1    1.010097
   2   -0.187258
d  0    1.242363
   1   -0.822011
   2   -0.085682
dtype: float64

【03x02】MultiIndex 索引对象

官方文档:https://pandas.pydata.org/docs/reference/api/pandas.MultiIndex.html

尝试打印上面示例中 Series 的索引类型,会得到一个 MultiIndex 对象,MultiIndex 对象的 levels 属性表示两个层级中分别有那些标签,codes 属性表示每个位置分别是什么标签,如下所示:

>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])
>>> obj
a  0    0.035946
   1   -0.867215
   2   -0.053355
b  0   -0.986616
   1    0.026071
   2   -0.048394
c  0    0.251274
   1    0.217790
   2    1.137674
d  0   -1.245178
   1    1.234972
   2   -0.035624
dtype: float64
>>> 
>>> type(obj.index)
<class 'pandas.core.indexes.multi.MultiIndex'>
>>> 
>>> obj.index
MultiIndex([('a', 0),
            ('a', 1),
            ('a', 2),
            ('b', 0),
            ('b', 1),
            ('b', 2),
            ('c', 0),
            ('c', 1),
            ('c', 2),
            ('d', 0),
            ('d', 1),
            ('d', 2)],
           )
>>> obj.index.levels
FrozenList([['a', 'b', 'c', 'd'], [0, 1, 2]])
>>>
>>> obj.index.codes
FrozenList([[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])

通常可以使用 from_arrays() 方法来将数组对象转换为 MultiIndex 索引对象:

>>> arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']]
>>> pd.MultiIndex.from_arrays(arrays, names=('number', 'color'))
MultiIndex([(1,  'red'),
            (1, 'blue'),
            (2,  'red'),
            (2, 'blue')],
           names=['number', 'color'])

其他常用方法见下表(更多方法参见官方文档):

方法 描述
from_arrays(arrays[, sortorder, names]) 将数组转换为 MultiIndex
from_tuples(tuples[, sortorder, names]) 将元组列表转换为 MultiIndex
from_product(iterables[, sortorder, names]) 将多个可迭代的笛卡尔积转换成 MultiIndex
from_frame(df[, sortorder, names]) 将 DataFrame 对象转换为 MultiIndex
set_levels(self, levels[, level, inplace, …]) 为 MultiIndex 设置新的 levels
set_codes(self, codes[, level, inplace, …]) 为 MultiIndex 设置新的 codes
sortlevel(self[, level, ascending, …]) 根据 level 进行排序
droplevel(self[, level]) 删除指定的 level
swaplevel(self[, i, j]) 交换 level i 与 level i,即交换外层索引与内层索引

【03x03】提取值

对于这种有多层索引的对象,如果只传入一个参数,则会对外层索引进行提取,其中包含对应所有的内层索引,如果传入两个参数,则第一个参数表示外层索引,第二个参数表示内层索引,示例如下:

>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])
>>> obj
a  0    0.550202
   1    0.328784
   2    1.422690
b  0   -1.333477
   1   -0.933809
   2   -0.326541
c  0    0.663686
   1    0.943393
   2    0.273106
d  0    1.354037
   1   -2.312847
   2   -2.343777
dtype: float64
>>> 
>>> obj['b']
0   -1.333477
1   -0.933809
2   -0.326541
dtype: float64
>>>
>>> obj['b', 1]
-0.9338094811708413
>>> 
>>> obj[:, 2]
a    1.422690
b   -0.326541
c    0.273106
d   -2.343777
dtype: float64

【03x04】交换分层与排序

MultiIndex 对象的 swaplevel() 方法可以交换外层与内层索引,sortlevel() 方法会先对外层索引进行排序,再对内层索引进行排序,默认是升序,如果设置 ascending 参数为 False 则会降序排列,示例如下:

>>> import pandas as pd
>>> import numpy as np
>>> obj = pd.Series(np.random.randn(12),index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'], [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]])
>>> obj
a  0   -0.110215
   1    0.193075
   2   -1.101706
b  0   -1.325743
   1    0.528418
   2   -0.127081
c  0   -0.733822
   1    1.665262
   2    0.127073
d  0    1.262022
   1   -1.170518
   2    0.966334
dtype: float64
>>> 
>>> obj.swaplevel()
0  a   -0.110215
1  a    0.193075
2  a   -1.101706
0  b   -1.325743
1  b    0.528418
2  b   -0.127081
0  c   -0.733822
1  c    1.665262
2  c    0.127073
0  d    1.262022
1  d   -1.170518
2  d    0.966334
dtype: float64
>>> 
>>> obj.swaplevel().index.sortlevel()
(MultiIndex([(0, 'a'),
            (0, 'b'),
            (0, 'c'),
            (0, 'd'),
            (1, 'a'),
            (1, 'b'),
            (1, 'c'),
            (1, 'd'),
            (2, 'a'),
            (2, 'b'),
            (2, 'c'),
            (2, 'd')],
           ), array([ 0,  3,  6,  9,  1,  4,  7, 10,  2,  5,  8, 11], dtype=int32))

这里是一段防爬虫文本,请读者忽略。
本文原创首发于 CSDN,作者 TRHX。
博客首页:https://itrhx.blog.csdn.net/
本文链接:https://itrhx.blog.csdn.net/article/details/106758103
未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!