数据科学 IPython 笔记本 7.5 数据索引和选择

作者: 布客飞龙 | 来源:发表于2019-01-13 21:54 被阅读6次

    7.5 数据索引和选择

    原文:Data Indexing and Selection

    译者:飞龙

    协议:CC BY-NC-SA 4.0

    本节是《Python 数据科学手册》(Python Data Science Handbook)的摘录。

    在第二章中,我们详细介绍了在 NumPy 数组中访问,设置和修改值的方法和工具。这些包括索引(例如,arr[2,1]),切片(例如,arr[:, 1:5]),掩码(例如,arr[arr > 0] ),花式索引(例如,arr[0, [1, 5]])及其组合(例如,arr[:, [1, 5]])。

    在这里,我们将看看在 Pandas SeriesDataFrame对象中,访问和修改值的类似方法。如果你使用过 NumPy 模式,Pandas 中的相应模式将会非常熟悉,尽管有一些需要注意的怪异之处。

    我们将从一维Series对象的简单情况开始,然后转向更复杂的二维DataFrame对象。

    序列中的数据选择

    我们在上一节中看到,Series对象在很多方面都像一维 NumPy 数组,并且在许多方面像标准的 Python 字典。如果我们记住这两个重叠的类比,它将帮助我们理解这些数组中的数据索引和选择的模式。

    作为字典的序列

    像字典一样,Series对象提供从一组键到一组值的映射:

    import pandas as pd
    data = pd.Series([0.25, 0.5, 0.75, 1.0],
                     index=['a', 'b', 'c', 'd'])
    data
    
    '''
    a    0.25
    b    0.50
    c    0.75
    d    1.00
    dtype: float64
    '''
    
    data['b']
    
    # 0.5
    

    我们还可以使用字典式的 Python 表达式和方法,来检查键/索引和值:

    'a' in data
    
    # True
    
    data.keys()
    
    # Index(['a', 'b', 'c', 'd'], dtype='object')
    
    list(data.items())
    
    # [('a', 0.25), ('b', 0.5), ('c', 0.75), ('d', 1.0)]
    

    Series对象甚至可以用类字典语法来修改。就像你可以通过为新键赋值来扩展字典,你可以通过为新索引赋值来扩展Series

    data['e'] = 1.25
    data
    
    '''
    a    0.25
    b    0.50
    c    0.75
    d    1.00
    e    1.25
    dtype: float64
    '''
    

    对象的这种容易修改的特性,是一个方便的特性:在其背后,Pandas 正在决定可能需要执行的内存布局和数据复制;用户通常不需要担心这些问题。

    作为一维数组的序列

    Series建立字典式接口上,并通过与 NumPy 数组相同的基本机制,提供数组式的项目选择,即切片,掩码和花式索引。这些例子如下:

    # 按照显式下标来切片
    data['a':'c']
    
    '''
    a    0.25
    b    0.50
    c    0.75
    dtype: float64
    '''
    
    # 按照隐式下标来切片
    data[0:2]
    
    '''
    a    0.25
    b    0.50
    dtype: float64
    '''
    
    # 掩码
    data[(data > 0.3) & (data < 0.8)]
    
    '''
    b    0.50
    c    0.75
    dtype: float64
    '''
    
    # 花式索引
    data[['a', 'e']]
    
    '''
    a    0.25
    e    1.25
    dtype: float64
    '''
    

    其中,切片可能是混乱的根源。注意,当使用显式索引进行切片时(即data['a':'c']),切片中包含最终索引,而在使用隐式索引进行切片时(即data[0:2]),最终索引从切片中排除。

    索引器:lociloc,和ix

    这些切片和索引惯例可能会引起混淆。例如,如果你的Series拥有显式的整数索引,那么索引操作如data[1]将使用显式索引,而切片操作如data[1:3]将使用隐式的 Python 风格索引。

    data = pd.Series(['a', 'b', 'c'], index=[1, 3, 5])
    data
    
    '''
    1    a
    3    b
    5    c
    dtype: object
    '''
    
    # 索引的时候是显式索引
    data[1]
    
    # 'a'
    
    # 切片的时候是隐式索引
    data[1:3]
    
    '''
    3    b
    5    c
    dtype: object
    '''
    

    由于在整数索引的情况下存在这种潜在的混淆,Pandas 提供了一些特殊的索引器属性,这些属性明确地提供了特定的索引方案。这些不是函数方法而是属性,它们将特定切片接口提供给Series中的数组。

    首先,loc属性让索引和切片始终引用显式索引:

    data.loc[1]
    
    # 'a'
    
    data.loc[1:3]
    
    '''
    1    a
    3    b
    dtype: object
    '''
    

    iloc属性让索引和切片始终引用隐式的 Python 风格索引:

    data.iloc[1]
    
    # 'b'
    
    data.iloc[1:3]
    
    '''
    3    b
    5    c
    dtype: object
    '''
    

    第三个索引属性ix是两者的混合,对Series对象来说,相当于标准的[]风格的索引。在DataFrame对象的上下文中,ix索引器的目的将变得更加明显,我们将在稍后讨论。

    Python 代码的一个指导原则是“显式优于隐式”。lociloc的显式特性,使它们在维护清晰可读的代码时非常有用;特别是在整数索引的情况下,我建议使用这两者,来使代码更容易阅读和理解,并防止由于混合索引/切片约定而导致的细微错误。

    数据帧中的数据选择

    回想一下,DataFrame在很多方面都类似二维或结构化数组,在其它方面莱斯共享相同索引的Series结构的字典。在我们探索此结构中的数据选择时,记住些类比是有帮助的。

    作为字典的数据帧

    我们将考虑的第一个类比是,DataFrame作为相关Series对象的字典。让我们回到我们的州人口和面积的例子:

    area = pd.Series({'California': 423967, 'Texas': 695662,
                      'New York': 141297, 'Florida': 170312,
                      'Illinois': 149995})
    pop = pd.Series({'California': 38332521, 'Texas': 26448193,
                     'New York': 19651127, 'Florida': 19552860,
                     'Illinois': 12882135})
    data = pd.DataFrame({'area':area, 'pop':pop})
    data
    
    area pop
    California 423967 38332521
    Florida 170312 19552860
    Illinois 149995 12882135
    New York 141297 19651127
    Texas 695662 26448193

    构成DataFrame列的单个Series,可以通过列名称的字典式索引来访问:

    data['area']
    
    '''
    California    423967
    Florida       170312
    Illinois      149995
    New York      141297
    Texas         695662
    Name: area, dtype: int64
    '''
    

    同样,我们可以使用列名的字符串和属性风格来访问:

    data.area
    
    '''
    California    423967
    Florida       170312
    Illinois      149995
    New York      141297
    Texas         695662
    Name: area, dtype: int64
    '''
    

    属性风格的列访问,与字典风格的访问,实际上访问了完全相同的对象:

    data.area is data['area']
    
    # True
    

    虽然这是一个有用的简写,但请记住,它并不适用于所有情况!例如,如果列名不是字符串,或者列名与DataFrame的方法冲突,则无法进行属性风格的访问。例如,DataFramepop()方法,所以data.pop将指向它而不是pop列:

    data.pop is data['pop']
    
    # False
    

    特别是,你应该避免尝试通过属性对列赋值(即使用data['pop'] = z而不是data.pop = z)。

    与前面讨论的Series对象一样,这种字典式语法也可用于修改对象,在这里添加一个新列:

    data['density'] = data['pop'] / data['area']
    data
    
    area pop density
    California 423967 38332521 90.413926
    Florida 170312 19552860 114.806121
    Illinois 149995 12882135 85.883763
    New York 141297 19651127 139.076746
    Texas 695662 26448193 38.018740

    这显示了Series对象之间的逐元素算术的直接语法;我们将在“使用 Pandas 中的数据进行操作”中深入研究它。

    作为二维数组的数据帧

    如前所述,我们还可以将DataFrame视为扩展的二维数组。我们可以使用values属性检查原始底层数据数组:

    data.values
    
    '''
    array([[  4.23967000e+05,   3.83325210e+07,   9.04139261e+01],
           [  1.70312000e+05,   1.95528600e+07,   1.14806121e+02],
           [  1.49995000e+05,   1.28821350e+07,   8.58837628e+01],
           [  1.41297000e+05,   1.96511270e+07,   1.39076746e+02],
           [  6.95662000e+05,   2.64481930e+07,   3.80187404e+01]])
    '''
    

    考虑到这一点,许多熟悉的数组式观测,可以在DataFrame本身上执行。例如,我们可以转置完整的DataFrame来交换行和列:

    data.T
    
    California Florida Illinois New York Texas
    area 4.239670e+05 1.703120e+05 1.499950e+05 1.412970e+05 6.956620e+05
    pop 3.833252e+07 1.955286e+07 1.288214e+07 1.965113e+07 2.644819e+07
    density 9.041393e+01 1.148061e+02 8.588376e+01 1.390767e+02 3.801874e+01

    然而,当谈到DataFrame对象的索引时,很明显列的字典式索引,让我们不能将其简单地视为 NumPy 数组。特别是,将单个索引传递给数组会访问一行:

    data.values[0]
    
    '''
    array([  4.23967000e+05,   3.83325210e+07,   9.04139261e+01])
    '''
    

    将单个“索引”传递给DataFrame会访问一列:

    data['area']
    
    '''
    California    423967
    Florida       170312
    Illinois      149995
    New York      141297
    Texas         695662
    Name: area, dtype: int64
    '''
    

    因此,对于数组风格的索引,我们需要另一个惯例。在这里,Pandas 再次使用前面提到的locilocix索引器。使用iloc索引器,我们可以索引底层数组,好像它是一个简单的 NumPy 数组(使用隐式的 Python 风格索引),但结果中保留了DataFrame索引和列标签:

    data.iloc[:3, :2]
    
    area pop
    California 423967 38332521
    Florida 170312 19552860
    Illinois 149995 12882135

    与之类似,使用loc索引器,我们可以用数组风格索引底层数据,但是使用显式索引和列名称:

    data.loc[:'Illinois', :'pop']
    
    area pop
    California 423967 38332521
    Florida 170312 19552860
    Illinois 149995 12882135

    ix索引器是这两种方法的混合:

    data.ix[:3, :'pop']
    
    area pop
    California 423967 38332521
    Florida 170312 19552860
    Illinois 149995 12882135

    请记住,对于整数索引,ix索引器具有与整数索引的Series对象相同的潜在混淆。

    任何熟悉的 NumPy 风格的数据访问模式,都可以在这些索引器中使用。例如,在loc索引器中,我们可以组合掩码和花式索引,如下所示:

    data.loc[data.density > 100, ['pop', 'density']]
    
    pop density
    Florida 19552860 114.806121
    New York 19651127 139.076746

    任何这些索引惯例也可用于设置或修改值;你可能习惯使用 NumPy 的标准方式完成它们:

    data.iloc[0, 2] = 90
    data
    
    area pop density
    California 423967 38332521 90.000000
    Florida 170312 19552860 114.806121
    Illinois 149995 12882135 85.883763
    New York 141297 19651127 139.076746
    Texas 695662 26448193 38.018740

    为了提高你对 Pandas 数据操作的流畅性,我建议花一些时间使用简单的DataFrame,并探索各种索引方法所允许的索引,切片,掩码和花式索引。

    额外的索引惯例

    有一些额外的索引约定可能与前面的讨论不一致,但在实践中可能非常有用。首先,索引引用列,切片引用行:

    data['Florida':'Illinois']
    
    area pop density
    Florida 170312 19552860 114.806121
    Illinois 149995 12882135 85.883763

    这样的切片也可以通过数字而不是索引来引用行:

    data[1:3]
    
    area pop density
    Florida 170312 19552860 114.806121
    Illinois 149995 12882135 85.883763

    与之类似,直接掩码操作也是按行而不是按列解释的:

    data[data.density > 100]
    
    area pop density
    Florida 170312 19552860 114.806121
    New York 141297 19651127 139.076746

    这两个惯例在语法上类似于 NumPy 数组上的惯例,虽然这些惯例可能不完全符合 Pandas 惯例,但它们在实践中非常有用。

    相关文章

      网友评论

        本文标题:数据科学 IPython 笔记本 7.5 数据索引和选择

        本文链接:https://www.haomeiwen.com/subject/tmxrdqtx.html