• 利用Python进行数据分析-Pandas(第二部分)


    上一个章节中我们主要是介绍了pandas两种数据类型的具体属性,这个章节主要介绍操作Series和DataFrame中的数据的基本手段。

    一、基本功能

    1、重新索引

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

    import pandas as pd
    
    obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
    print(obj)
    d    4.5
    b    7.2
    a   -5.3
    c    3.6
    dtype: float64
    

    用该Series的reindex将会根据新索引进行重排。如果某个索引值当前不存在,就引入缺失值:

    obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
    print(obj2)
    a   -5.3
    b    7.2
    c    3.6
    d    4.5
    e    NaN
    dtype: float64
    

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

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

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

    frame = pd.DataFrame(np.arange(9).reshape(3, 3), index=['a', 'c', 'd'], columns=['Ohio', 'Texas', 'California'])
    print(frame)
       Ohio  Texas  California
    a     0      1           2
    c     3      4           5
    d     6      7           8
    frame2= frame.reindex(['a', 'b', 'c', 'd'])
    print(frame2)
       Ohio  Texas  California
    a   0.0    1.0         2.0
    b   NaN    NaN         NaN
    c   3.0    4.0         5.0
    d   6.0    7.0         8.0
    

    列可以用columns关键字重新索引:

    states = ['Texas', 'Utah', 'California']
    print(frame.reindex(columns=states))
       Texas  Utah  California
    a      1   NaN           2
    c      4   NaN           5
    d      7   NaN           8
    

    如下列出了reindex函数的各参数及说明:

    • index                                                  用作索引的新序列。既可以是index实例,也可以是其他序列类型的Python数据结构。Index会被完全使用,就像没有任何复制一样;
    • method                                                    插值(填充)方式;
    • fill_value                                                  在重新索引的过程中,需要引入缺失值时使用的替代值;
    • limit                                                          前向或后向填充时的最大填充量;
    • tolerance                                                  向前后向后填充时,填充不准确匹配项的最大间距(绝对值距离)
    • level                                                         在MultiIndex的指定级别上匹配简单索引,否则选取其子集;
    • copy                                                         默认为True,无论如何都复制;如果为False,则新旧相等就不复制。

    2、丢弃指定轴上的项

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

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

    删除索引C,并生成新的对象:

    new_obj = obj.drop('c')
    print(new_obj)
    a    0.0
    b    1.0
    d    3.0
    e    4.0
    dtype: float64
    

    删除列表索引,并生成新的对象:

    print(obj.drop(['d', 'c']))
    a    0.0
    b    1.0
    e    4.0
    dtype: float64
    

    对于DataFrame,可以删除任意轴上的索引值。为了演示,先新建一个DataFrame栗子:

    import pandas as pd
    import numpy as np
    data = pd.DataFrame(np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'NewYork'], columns=['one', 'two', 'three', 'four'])
    print(data)
              one  two  three  four
    Ohio        0    1      2     3
    Colorado    4    5      6     7
    Utah        8    9     10    11
    NewYork    12   13     14    15
    

    用标签序列调用drop会从行标签(axis 0)删除值:

    print(data.drop(['Colorado', 'Ohio']))
             one  two  three  four
    Utah       8    9     10    11
    NewYork   12   13     14    15
    

    通过传递axis=1或axis='columns'可以删除列的值:

    print(data.drop('two', axis=1))
              one  three  four
    Ohio        0      2     3
    Colorado    4      6     7
    Utah        8     10    11
    NewYork    12     14    15
    
    print(data.drop(['two', 'four'], axis='columns'))
              one  three
    Ohio        0      2
    Colorado    4      6
    Utah        8     10
    NewYork    12     14
    

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

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

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

    3、索引、选取和过滤 

       Series索引(obj[...])的工作方式类似于NumPy数组的索引,只不过Series的索引值不只是整数。下面是几个例子:

    import pandas as pd
    import numpy as np
    obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd'])
    print(obj)
    a    0.0
    b    1.0
    c    2.0
    d    3.0
    dtype: float64
    

    获得索引为b的数据:

    print(obj['b'])
    1.0
    

    获得自动索引为1的数据:

    print(obj[1])
    1.0
    

    获得自动索引列表[2:4]的数据:

    print(obj[2:4])
    c    2.0
    d    3.0
    dtype: float64
    

    也可以使用自定义索引:

    print(obj[['b', 'a', 'd']])
    b    1.0
    a    0.0
    d    3.0
    dtype: float64
    

    使用自动索引:

    print(obj[[1, 3]])
    b    1.0
    d    3.0
    dtype: float64
    

    可以使用判断切片:

    print(obj[obj < 2])
    a    0.0
    b    1.0
    dtype: float64
    

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

    print(obj['b':'d'])
    b    1.0
    c    2.0
    d    3.0
    dtype: float64
    

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

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

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

    data = pd.DataFrame(np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'NewYork'], columns=['one', 'two', 'three', 'four'])
    print(data)
              one  two  three  four
    Ohio        0    1      2     3
    Colorado    4    5      6     7
    Utah        8    9     10    11
    NewYork    12   13     14    15
    

    使用索引举例:

    print(data['two'])
    Ohio         1
    Colorado     5
    Utah         9
    NewYork     13
    Name: two, dtype: int32
    print(data[['three', 'one']])
              three  one
    Ohio          2    0
    Colorado      6    4
    Utah         10    8
    NewYork      14   12
    

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

    print(data[:2])
              one  two  three  four
    Ohio        0    1      2     3
    Colorado    4    5      6     7 
    print(data[data['three'] > 5])
              one  two  three  four
    Colorado    4    5      6     7
    Utah        8    9     10    11
    NewYork    12   13     14    15
    

    选取行的语法data[:2]十分方便。向[ ]传递单一的元素或列表,就可选择列。另一种用法是通过布尔型DataFrame(比如下面这个由标量比较运算得出的)进行索引:

    print(data < 5)
    data[data < 5] = 0
    print(data)
                one    two  three   four
    Ohio       True   True   True   True
    Colorado   True  False  False  False
    Utah      False  False  False  False
    NewYork   False  False  False  False
              one  two  three  four
    Ohio        0    0      0     0
    Colorado    0    5      6     7
    Utah        8    9     10    11
    NewYork    12   13     14    15
    

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

    4、用loc和iloc进行选取

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

      作为一个初步示例,让我们通过标签选择一行和多列。

    print(data.loc['Colorado', ['two', 'three']])
    two      5
    three    6
    Name: Colorado, dtype: int32
    

    然后用iloc和整数进行行选取:

    print(data.iloc[2, [3, 0, 1]])
    four    11
    one      8
    two      9
    Name: Utah, dtype: int32
    print(data.iloc[2])
    one       8
    two       9
    three    10
    four     11
    Name: Utah, dtype: int32 
    print(data.iloc[[1, 2], [3, 0, 1]])
              four  one  two
    Colorado     7    4    5
    Utah        11    8    9
    

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

    print(data.loc[:'Utah', 'two'])
    Ohio        1
    Colorado    5
    Utah        9
    Name: two, dtype: int32
    print(data.iloc[:, :3][data.three > 5])
              one  two  three
    Colorado    4    5      6
    Utah        8    9     10
    NewYork    12   13     14
    

    所以,在pandas中,有多个方法可以选取和重新组合数据。

     5、整数索引

      处理整数索引的pandas对象常常难住新手,因为它与Python内置的列表和元组的索引语法不同。例如,你可能不认为下面的代码会出处:

    ser = pd.Series(np.arange(3.))
    print(ser[-1])
        return self._engine.get_value(s, k, tz=getattr(series.dtype, "tz", None))
      File "pandas\_libsindex.pyx", line 80, in pandas._libs.index.IndexEngine.get_value
      File "pandas\_libsindex.pyx", line 88, in pandas._libs.index.IndexEngine.get_value
      File "pandas\_libsindex.pyx", line 131, in pandas._libs.index.IndexEngine.get_loc
      File "pandas\_libshashtable_class_helper.pxi", line 992, in pandas._libs.hashtable.Int64HashTable.get_item
      File "pandas\_libshashtable_class_helper.pxi", line 998, in pandas._libs.hashtable.Int64HashTable.get_item
    KeyError: -1
    

    以上执行会报错。已经自动产生了0开头的索引,引用-1时则报错!

    但是对于非整数索引,则不会产生歧义:

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

    为了进行统一,如果轴索引含有整数,数据选取总会使用标签。为了更准确,请使用loc(标签)或iloc(整数):

    ser = pd.Series(np.arange(3.))
    print(ser[:1])
    0    0.0
    dtype: float64 
    print(ser.loc[:1])
    print(ser.iloc[:1])
    0    0.0
    1    1.0
    dtype: float64
    0    0.0
    dtype: float64
    

    6、算术运算和数据对齐

       pandas最重要的一个功能是,它可以对不同索引的对象进行算术运算。在将对象相加时,如果存在不同的索引对,则结果的索引就是该索引对的并集。对于有数据库经验的用户,这就像在索引标签上进行自动外连接:

    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(s2)
    a    7.3
    c   -2.5
    d    3.4
    e    1.5
    dtype: float64
    a   -2.1
    c    3.6
    e   -1.5
    f    4.0
    g    3.1
    dtype: float64
    

    将它们相加就会产生:

    print(s1+s2)
    a    5.2
    c    1.1
    d    NaN
    e    0.0
    f    NaN
    g    NaN
    dtype: float64
    

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

    对于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'])
    print(df1)
    print(df2)
                b    c    d
    Ohio      0.0  1.0  2.0
    Texas     3.0  4.0  5.0
    Colorado  6.0  7.0  8.0
              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
    

    把它们相加后将会返回一个新的DataFrame,其索引和列为原来那两个DataFrame的并集:

    print(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对象中,在结果中以缺省值呈现。行也是同样。

    7、在算术方法中填充值

       在对不同索引的对象进行算术运算时,你可能希望当一个对象中某个轴标签在另一个对象中找不到时填充一个特殊值(比如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
    print(df1)
    print(df2)
       a  b   c   d
    0  0  1   2   3
    1  4  5   6   7
    2  8  9  10  11
        a     b   c   d   e
    0   0   1.0   2   3   4
    1   5   NaN   7   8   9
    2  10  11.0  12  13  14
    3  15  16.0  17  18  19
    

    将它们相加时,没有重叠的位置就会产生NA值:

    print(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参数:

    print(df1.add(df2, fill_value=0))
          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开头,它会翻转参数。因此这两个语句是等价的:

    print(1/df1)
           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
    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方法
    方法 说明
    add,radd 用于加法(+)的方法
    sub,rsub 用于减法(—)的方法
    div,rdiv 用于除法(/)的方法
    floordiv,rfloordiv 用于底除(//)的方法
    mul,rmul 用于乘法(*)的方法
    pow,rpow 用于指数(**)的方法

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

    print(df1.reindex(columns=df2.columns, fill_value=0))
       a  b   c   d  e
    0  0  1   2   3  0
    1  4  5   6   7  0
    2  8  9  10  11  0
    

    8、DataFrame和Series之间的运算

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

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

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

    frame = pd.DataFrame(np.arange(12.).reshape(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])
    series = frame.iloc[0]
    print(frame)
    print(series)
              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
    b    0.0
    d    1.0
    e    2.0
    Name: Utah, dtype: float64
    

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

    print(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的索引中找不到,则参与运算的两个对象就会被重新索引以形成并集:

    series2 = pd.Series(range(3), index=['b', 'e', 'f'])
    print(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
    

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

    series3 = frame['d']
    print(series3)
    print(frame.sub(series3, axis='index'))
    Utah       1.0
    Ohio       4.0
    Texas      7.0
    Oregon    10.0
    Name: d, dtype: float64
              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
    

    传入的轴号就是希望匹配的轴。在本例中,我们的目的是匹配DataFrame的行索引(axis=‘index’ or axis=0)并进行广播。

    9、函数应用和映射

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

    frame = pd.DataFrame(np.random.rand(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])
    print(frame)
    print(np.abs(frame))
                   b         d         e
    Utah    0.064023  0.692445  0.397648
    Ohio    0.307545  0.700493  0.054521
    Texas   0.790282  0.857526  0.176732
    Oregon  0.845433  0.030763  0.197624
                   b         d         e
    Utah    0.064023  0.692445  0.397648
    Ohio    0.307545  0.700493  0.054521
    Texas   0.790282  0.857526  0.176732
    Oregon  0.845433  0.030763  0.197624
    

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

    f = lambda x: x.max() - x.min()
    print(frame.apply(f))
    b    0.628426
    d    0.228863
    e    0.327750
    dtype: float64
    

    这里的函数f,计算了一个Series的最大值和最小值的差,在frame的每列都执行了一次。结果是一个series,使用frame的列作为索引。

    如果传递axis='columns'到apply,这个函数会在每行执行:

    print(frame.apply(f, axis=1))
    Utah      0.632225
    Ohio      0.165264
    Texas     0.829253
    Oregon    0.035064
    dtype: float64
    

    许多最为常见的数组统计功能都被实现成DataFrame的方法(如sum和mean),因此无需使用apply方法。

    传递到apply的函数不是必须返回一个标量,还可以返回由多个值祖晨给的Series:

    def f(x):
        return pd.Series([x.min(), x.max()], index=['min', 'max'])
    
    
    print(frame.apply(f))
                b         d         e
    min  0.126930  0.002095  0.107104
    max  0.847219  0.816830  0.932785
    

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

    print(frame.applymap(format))
                              b                    d                     e
    Utah     0.6798017353255632    0.597186588130127   0.19187846531150032
    Ohio     0.5847604949858233   0.5343443064790626    0.7629954378984624
    Texas   0.16706070519049687  0.29479050054459943    0.6530392097716237
    Oregon   0.8484367833746287   0.5218312157057384  0.021621564616659317
    

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

    print(frame['e'].map(format))
    Utah        0.4383346697291973
    Ohio        0.7597781582580012
    Texas     0.011837912674436457
    Oregon      0.4294773649163831
    Name: e, dtype: object
    

    说明:因为是随机函数,因此产生的值有可能不一样,如要一致,请定义随机种子数。

    10、排序和排名

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

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

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

    frame = pd.DataFrame(np.arange(8.).reshape((2, 4)), index=['three', 'one'], columns=['d', 'a', 'b', 'c'])
    print(frame.sort_index())
             d    a    b    c
    one    4.0  5.0  6.0  7.0
    three  0.0  1.0  2.0  3.0
    print(frame.sort_index(axis=1))
             a    b    c    d
    three  1.0  2.0  3.0  0.0
    one    5.0  6.0  7.0  4.0
    

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

    print(frame.sort_index(axis=1, ascending=False))
             d    c    b    a
    three  0.0  3.0  2.0  1.0
    one    4.0  7.0  6.0  5.0
    

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

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

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

    obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])
    print(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选项即可达到该目的:

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

    要根据多个列进行排序,传入名称的列表即可:

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

    排名会从1开始一直到数组中有效数据的数量。接下来介绍Series和DataFrame的rank方法。默认情况下,rank是通过“为各组分配一个平均排名”的方式破坏平级关系的:

    obj = pd.Series([7, -5, 7, 4, 2, 0, 4])
    print(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
    

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

    print(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没有使用平均排名6.5,它们被设成了6和7,因为数据中标签0位于标签2的前面。

    也可以按降序进行排名:

    print(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可以在行或列上计算排名:

    frame = pd.DataFrame({'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1], 'c': [-2, 5, 8, -2.5]})
    print(frame)
    print(frame.rank(axis='columns'))
         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
         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,而不是组中相同的元素数

    11、带有重复标签的轴索引

       直到目前为止,所介绍的所有栗子都有着唯一的轴标签(索引值)。虽然许多pandas函数(如reindex)都要求标签唯一,但这并不是强制性的。我们来看看下面这个简单的带有重复索引值的Series:

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

    索引的is_unique属性可以告诉你它的值是否是唯一的:

    print(obj.index.is_unique)
    False
    

    对于带有重复值的索引,数据选取的行为将会有些不同。如果某个索引对应多个值,则返回一个Series;而对应单个值的,则返回一个标量值:

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

    这样会使代码边复杂,因为索引的输出类型会根据标签是否有重复发生变化。

    对DataFrame的行进行索引时也是如此:

    df = pd.DataFrame(np.random.randn(4, 3), index=['a', 'a', 'b', 'b'])
    print(df)
    print(df.loc['b'])
              0         1         2
    a  1.256824  1.291061 -0.685927
    a -0.407044 -0.353979 -1.864022
    b  0.037937  0.517678  0.680367
    b  3.037344 -0.065109  0.588987
              0         1         2
    b  0.037937  0.517678  0.680367
    b  3.037344 -0.065109  0.588987

    二、汇总和计算描述统计

    12、汇总和计算描述统计

       pandas对象拥有一组常用的数学和统计方法。它们大部分都属于约简和汇总统计,用于从Series中提取单个值(如sum或mean)或从DataFrame的行或列中提取一个Series。跟对应的NumPy数组方法相比,它们都是基于没有缺失数据的假设而构建的。

    df = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'], columns=['one', 'two'])
    print(df)
        one  two
    a  1.40  NaN
    b  7.10 -4.5
    c   NaN  NaN
    d  0.75 -1.3
    

    调用DataFrame的sum方法将返回一个含有列的和的Series:

    print(df.sum())
    one    9.25
    two   -5.80
    dtype: float64 

    传入axis='columns'或axis=1将会按行进行求和运算:

    print(df.sum(axis=1))
    a    1.40
    b    2.60
    c    0.00
    d   -0.55
    dtype: float64
    

    NA值会自动被排除,除非整个切片(这里指的是行或列)都是NA。通过skipna选项可以禁用该功能:

    print(df.mean(axis=1, skipna=False))
    a      NaN
    b    1.300
    c      NaN
    d   -0.275
    dtype: float64
    

    如下列出了这些约简方法的常用选项:

    选项 说明
    axis 约简的轴。由DataFrame的行用0,列用1
    skipna 排除缺失值,默认值为True
    level 如果轴是层次化索引的(即MultiIndex),则根据level分组约简

    有些方法(如idxmin和idxmax)返回的是间接统计(比如达到最小值或最大值的索引):

    print(df.idxmax())
    one    b
    two    d
    dtype: object
    

    另一些方法则是累计型的:

    print(df.cumsum())
        one  two
    a  1.40  NaN
    b  8.50 -4.5
    c   NaN  NaN
    d  9.25 -5.8
    

    还有一种方法,它就不是约简型也不是累计型。describe就是一个栗子,它用于一次性产生多个汇总统计:

    print(df.describe())
               one       two
    count  3.000000  2.000000
    mean   3.083333 -2.900000
    std    3.493685  2.262742
    min    0.750000 -4.500000
    25%    1.075000 -3.700000
    50%    1.400000 -2.900000
    75%    4.250000 -2.100000
    max    7.100000 -1.300000
    

    对于非数值型数据,describe会产生另外一种汇总统计:

    obj = pd.Series(['a', 'a', 'b', 'c']*4)
    print(obj.describe())
    count     16
    unique     3
    top        a
    freq       8
    dtype: object
    

    如下列表列出了所有与描述统计相关的方法:

     表:描述和汇总统计

    方法 说明
    count 非NA值的数量
    describe 针对Series或各DataFrame列计算汇总统计
    min、max 计算最小值和最大值
    argmin、argmax 计算能够获取到最小值和最大值的索引位置(整数)
    idxmin、idxmax 计算能够获取到最小值和最大值的索引值
    quantile 计算样本的分位数(0到1)
    sum 值的总和
    mean 值的平均数
    median 值的算术中位数(50%分位数)
    mad 根据平均值计算平均绝对离差
    var 样本值的方差
    std 样本值的标准差
    skew 样本值的偏度(三阶矩)
    kurt 样本值的峰度(四阶矩)
    cumsum 样本值的累计和
    cummin、cummax 样本值的累计最大值和累计最小值
    cumprod 样本值的累计积
    diff 计算一阶差分(对时间序列很有用)
    pct_change 计算百分数变化

    13、相关系数与协方差

      有些汇总统计(如相关系数和协方差)是通过参数对计算出来的。我们来看几个DataFrame,它们的数据来自Yahoo!Finance的股票价格和成交量,使用的是pandas-datareader包(可以用conda或pip安装):

    import pandas_datareader.data as web
    
    all_data = {ticker: web.get_data_yahoo(ticker) for ticker in ['AAPL', 'IBM', 'MSFT', 'GOOG']}
    price = pd.DataFrame({ticker: data['Adj Close'] for ticker, data in all_data.items()})
    volume = pd.DataFrame({ticker: data['Volume'] for ticker, data in all_data.items()})
    returns = price.pct_change()
    print(returns.tail())
                    AAPL       IBM      MSFT      GOOG
    Date                                              
    2019-11-22 -0.000878  0.003736  0.000736 -0.004618
    2019-11-25  0.017534  0.012133  0.010963  0.008762
    2019-11-26 -0.007809 -0.006472  0.005290  0.005250
    2019-11-27  0.013432 -0.009771  0.001908 -0.000426
    2019-11-29 -0.002203  0.005083 -0.006171 -0.006116
    

    Series的corr方法用于计算两个Series中重叠的、非NA的、按索引对齐的值的相关系数。与此类似,cov用于计算协方差:

    print(returns['MSFT'].corr(returns['IBM']))
    0.48748863221002536
    print(returns['MSFT'].cov(returns['IBM']))
    9.403469349907563e-05
    

    因为MSFT是一个合理的Python属性,我们还可以用更简洁的语法选择列:

    print(returns.MSFT.corr(returns.IBM))
    0.48748863221002536
    

    另一方面,DataFrame的corr和cov方法将以DataFrame的形式返回完整的相关系数或协方差矩阵:

    相关系数:

    print(returns.corr())
              AAPL       IBM      MSFT      GOOG
    AAPL  1.000000  0.406404  0.575217  0.523380
    IBM   0.406404  1.000000  0.487489  0.414135
    MSFT  0.575217  0.487489  1.000000  0.660486
    GOOG  0.523380  0.414135  0.660486  1.000000
    

    协方差矩阵:

    print(returns.cov())
              AAPL       IBM      MSFT      GOOG
    AAPL  0.000246  0.000083  0.000133  0.000125
    IBM   0.000083  0.000170  0.000094  0.000082
    MSFT  0.000133  0.000094  0.000218  0.000148
    GOOG  0.000125  0.000082  0.000148  0.000231
    

    利用DataFrame的corrwith方法,你可以计算其列或行跟另一个Series或DataFrame之间的相关系数。传入一个Series将会返回一个相关系数值Series(针对各列进行计算):

    print(returns.corrwith(returns.IBM))
    AAPL    0.406404
    IBM     1.000000
    MSFT    0.487489
    GOOG    0.414135
    dtype: float64
    

    传入一个DataFrame则会计算按列名配对的相关系数。这里,计算百分比变化与成交量的相关系数:

    print(returns.corrwith(volume))
    AAPL   -0.119077
    IBM    -0.133046
    MSFT   -0.085162
    GOOG   -0.005952
    dtype: float64
    

    传入axis='columns'即可按行进行计算。无论如何,在计算相关系数之前,所有的数据项都会按标签对齐。

    14、唯一值、值计数以及成员资格

      还有一类方法可以从一维Series的值中抽取信息。

    obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
    uniques = obj.unique()
    print(uniques)
    ['c' 'a' 'd' 'b']
    

    返回的唯一值是未排序的,如果需要的话,可以对结果再次进行排序(uniques.sort())。相似的,value_counts用于计算一个Series中各值出现的频率:

    print(obj.value_counts())
    a    3
    c    3
    b    2
    d    1
    dtype: int64
    

    为了便于查看,结果Series是按值频率降序排列的。value_counts还是一个顶级pandas方法,可用于任何数组或序列:

    print(pd.value_counts(obj.values, sort=False))
    d    1
    c    3
    b    2
    a    3
    dtype: int64
    

    isin用于判断矢量集合的成员资格,可用于过滤Series中或DataFrame列中数据的子集:

    mask = obj.isin(['b', 'c'])
    print(mask)
    0     True
    1    False
    2    False
    3    False
    4    False
    5     True
    6     True
    7     True
    8     True
    dtype: bool
    

    与isin类似的是Index.get_indexer方法,它可以给你一个索引数组,从可能包含重复值的数组到另一个不同值的数组:

    print(pd.Index(unique_vals).get_indexer(to_match))
    [0 2 1 1 0 2]
    

    如下表给出了这几个方法的一些参考信息:

    方法 说明
    isin 计算一个表示'Series各值是否包含于传入的值序列中'的布尔型数组
    match 计算一个数组中的各值到另一个不同值数组的整数索引;对于数据对齐和连接类型的操作十分有用
    unique 计算Series中的唯一值数组,按发现的顺序返回
    value_counts 返回一个Series,其索引为唯一值,其值为频率,按计数值降序排列

    有时,你可能希望得到DataFrame中多个相关列的一张柱状图。例如:

    data = pd.DataFrame({'Qul': [1, 3, 4, 3, 4], 'Qu2': [2, 3, 1, 2, 3], 'Qu3': [1, 5, 2, 4, 4]})
    print(data)
       Qul  Qu2  Qu3
    0    1    2    1
    1    3    3    5
    2    4    1    2
    3    3    2    4
    4    4    3    4
    

    将pandas.value_counts传给该DataFrame的apply函数,就会出现:

    result = data.apply(pd.value_counts).fillna(0)
    print(result)
       Qul  Qu2  Qu3
    1  1.0  1.0  1.0
    2  0.0  2.0  1.0
    3  2.0  2.0  0.0
    4  2.0  0.0  2.0
    5  0.0  0.0  1.0
    

    这里,结果中的行标签是所有列的唯一值。后面的频率是每个列中这些值的相应计数。

                  
    申明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    DEDE后台登录提示成功但是一下子就弹出重新登录
    商务通对话窗口左侧图片广告
    html文档类型能直接改成html5吗?
    <meta http-equiv="pragma" content="no-cache"/>是什么意思?
    <meta name="location" content="province=湖北;city=襄阳;coord=112.167975,32.047654">
    取消百度转码<head></head>
    <base target=_blank>
    把数据保存到数据库主表 `#@__archives` 时出错
    DEDECMS后台文章编辑内容框消失解决方法
    【转】vs 常用快捷键
  • 原文地址:https://www.cnblogs.com/lsyb-python/p/11958734.html
Copyright © 2020-2023  润新知