这是关于如何从pandas DataFrame或Series中选择数据子集的四部分系列的开始。Pandas为子集选择提供了多种选择,这需要多篇文章。本系列分为以下四个主题。
这些系列文章假定您不了解Pandas,但是您了解Python编程语言的基础。它还假定您已在计算机上安装了Pandas。
将Pandas与Python和其他主要科学计算库结合使用的最简单方法是安装Miniconda发行版(请参阅完整的教程的链接)。
您可能想知道,为什么有那么多关于选择数据子集的文章。这个主题对pandas来说非常重要,很遗憾它很复杂,因为在实际分析中子集选择经常发生。由于您经常选择子集,因此需要掌握它才能使pandas变得更轻松。
有关索引和选择数据的官方pandas文档也涵盖了本文中的材料。我强烈建议您与本教程一起阅读文档的该部分。实际上,文档是掌握pandas的主要手段之一。我写了一篇循序渐进的文章“ 如何学习pandas”,其中提供了有关如何在掌握pandas的同时使用文档的建议。
pandas库具有两个主要的数据容器:DataFrame和Series。使用Pandas时,几乎所有的时间都花在处理这两个对象上。DataFrame的使用比Series更多,因此让我们首先看一下它的图像。
此图像带有一些附加的插图,以突出显示其组件。乍一看,DataFrame看起来就像您看到的任何其他二维数据表一样。它有行,有列。从技术上讲,DataFrame具有三个主要组件。
DataFrame由三个不同的组件组成:索引,列和数据。数据也称为值。
索引表示DataFrame最左侧的值序列。索引中的所有值都在粗字体。索引的每个单独的值称为标签。有时,该索引称为行标签。在上面的示例中,行标签不是很有趣,只是从0到n-1的整数,其中n是表中的行数。pandas默认使用此简单索引作为DataFrames。
这些列是DataFrame顶部的值序列。它们也以粗体显示。列的每个单独的值都称为列,但也可以称为列名或列标签。
其他所有非粗体字都是数据或值。有时您会听到被称为表格数据的DataFrames 。这只是具有行和列的矩形表数据的另一个名称。将行或列称为轴也是常见的术语。统称为“ 轴”。因此,一行是一个轴,一列是另一个轴。
从DataFrame解剖结构中得出的主要结论是,每行都有一个标签,每列都有一个标签。这些标签用于引用DataFrame中的特定行或列。这与人类如何使用名称来指代特定的人一样。
在开始选择子集之前,最好定义一下子集。子集选择只是从DataFrame(或Series)中选择数据的特定行和列。这可能意味着选择所有行和一些列,选择一些行和所有列,或者选择每个行和列。
让我们看一些子集选择的图像。我们将首先查看带有伪数据的示例DataFrame。
比方说,我们要选择的只是列color,age和height但保留所有行。
我们最终的DataFrame如下所示:
我们还可以进行选择,仅选择一些行。我们选择带有标签的行Aaron,并Dean连同所有的列:
我们最终的DataFrame希望:
让我们从上面结合选择和选择的列color,age以及height只带标签的行Aaron和Dean。
我们最终的DataFrame如下所示:
我们已经提到过,每一行和每一列都有一个可用来引用它们的特定标签。这在DataFrame中以粗体显示。
但是,没有提到的是,每一行和每一列也可以由整数引用。我称这个整数位置。对于每一行和每一列,整数位置从0开始,以n-1结束。再次在上方查看我们的示例DataFrame。
带标签的行Aaron和Dean还可以通过它们各自的整数位置2和4类似地,列中引用color,age并且height可以通过它们的整数位置1,图3和4中被引用。
该文档将整数位置称为position。我不特别喜欢这种术语,因为它不像整数位置那样明确。这里的关键术语是整数。
该文档经常使用术语索引。这个术语本质上只是一个单字短语,用来表示“子集选择”。我更喜欢术语子集选择,因为它再次描述了实际发生的事情。索引也是官方Python文档中使用的术语。
选择数据子集的方法有很多,但是在本文中,我们仅介绍方括号([])**.loc**和的用法**.iloc**。它们统称为索引器。到目前为止,这些是选择数据的最常用方法。本系列的不同部分将讨论一些可用于进行子集选择的方法。
如果您有一个DataFrame,则df您的子集选择将类似于以下内容:
df []
df.loc []
df.iloc []
实际的子集选择将在方括号内包含一些内容。本文中的所有选择都将在这些方括号内进行。
请注意,方括号也位于.loc和之后.iloc。Python中的所有索引都发生在这些方括号内。
让我们开始使用熊猫读取DataFrame,然后从那里单独使用索引运算符选择数据子集。这些教程的所有数据都在数据目录中。
我们将使用该read_csv 函数将数据读入DataFrame。我们将路径传递到文件作为函数的第一个参数。我们还将使用该index_col`参数选择数据的第一列作为索引(稍后会对此进行更多介绍)。
>>> import pandas as pd
>>> import numpy as np>>> df = pd.read_csv('data/sample_data.csv', index_col=0)
>>> df
之前,我们提到了DataFrame的三个组件。索引,列和数据(值)。我们可以将每个组件提取到它们自己的变量中。让我们这样做,然后检查它们:
>>> index = df.index
>>> columns = df.columns
>>> values = df.values
>>> index
Index(['Jane', 'Niko', 'Aaron', 'Penelope', 'Dean', 'Christina',
'Cornelia'], dtype='object')
>>> columns
Index(['state', 'color', 'food', 'age', 'height', 'score'],
dtype='object')
>>> values
array([['NY', 'blue', 'Steak', 30, 165, 4.6],
['TX', 'green', 'Lamb', 2, 70, 8.3],
['FL', 'red', 'Mango', 12, 120, 9.0],
['AL', 'white', 'Apple', 4, 80, 3.3],
['AK', 'gray', 'Cheese', 32, 180, 1.8],
['TX', 'black', 'Melon', 33, 172, 9.5],
['TX', 'red', 'Beans', 69, 150, 2.2]], dtype=object)
让我们输出每个组件的类型,以准确了解它们是什么类型的对象。
>>> type(index)
pandas.core.indexes.base.Index
>>> type(columns)
pandas.core.indexes.base.Index
>>> type(values)
numpy.ndarray
有趣的是,索引和列都是同一类型。它们都是pandasIndex对象。该对象本身功能非常强大,但是现在您可以将其视为行或列的标签序列。
这些值是NumPy `ndarray,代表n维数组,并且是NumPy库中数据的主要容器。Pandas直接建立在NumPy之上,正是这个数组负责大部分工作量。
我们将仅通过在DataFrame上使用索引运算符来开始选择子集的过程。其主要目的是选择单列或多列数据。
>>> df['food']
Jane Steak
Niko Lamb
Aaron Mango
Penelope Apple
Dean Cheese
Christina Melon
Cornelia Beans
Name: food, dtype: object
选择单列数据将返回另一个pandas数据容器系列。系列是标记数据的一维序列。系列有两个主要组成部分,即索引和数据(或值)。系列中没有列。
系列的视觉显示只是纯文本,而不是DataFrames的样式表。左边的人名的顺序是索引。右边的实例顺序是数值。
您还将在系列底部注意到另外两个数据。系列的名称变为旧列名称。您还将看到数据类型或**dtype**系列数据。您现在可以忽略这两个项目。
选择多个列将返回一个DataFrame。实际上,您可以选择一个列作为具有一个项目列表的DataFrame:
df [['food']]
尽管这与上面的Series很像,但从技术上讲它是一个DataFrame,是一个不同的对象。
选择多个列时,可以按选择的任何顺序选择它们。它的顺序不必与原始DataFrame相同。例如,让我们选择height和color。
`df [['height','color']]`
仅使用索引运算符进行选择时,会出现几个常见的例外。
>>> df['hight']
KeyError: 'hight'
>>> df['color', 'age'] # should be: df[['color', 'age']]
KeyError: ('color', 'age')
该**.loc**索引中选择不仅仅是索引操作方式不同的数据。它可以选择行或列的子集。它还可以同时选择行和列的子集。最重要的是,它仅根据行和列的标签选择数据。
**.loc**当给定单行标签时,索引器将返回一行作为系列。让我们选择的行**Niko**。
>>> df.loc['Niko']
state TX
color green
food Lamb
age 2
height 70
score 8.3
Name: Niko, dtype: object
要选择多行,请将您要选择的所有行标签放在列表中,然后将其传递给**.loc**。让我们选择Niko和Penelope。
>>> df.loc [['Niko','Penelope']]
可以.loc通过使用切片符号来“切片” DataFrame的行。切片符号使用冒号分隔开始,停止和步进值。例如,我们可以选择所有的行Niko经过Dean是这样的:
>>> df.loc ['Niko':'Dean']
请注意,标有的行Dean已保留。在其他数据容器(如Python列表)中,最后一个值被排除。
您可以像使用列表一样使用切片符号。让我们从头开始切开Aaron:
>>> df.loc [:'Aaron']
>>> df.loc ['Niko':'Christina':2]
>>> df.loc ['Dean':]
### 同时选择行和列 .loc
与仅索引运算符不同,可以与同时选择行和列.loc。通过用逗号分隔行和列的选择来完成此操作。它看起来像这样:
>>> df.loc [行选择,列选择]
举例来说,如果我们想要选择的行Dean和Cornelia与列一起age,state和score我们这样做:
>>> df.loc [['Dean','Cornelia'],['age','state','score']]
正如我们已经看到的,行或列的选择可以是以下任意一种:
我们可以使用来将这三个中的任何一个用于行或列选择**.loc**。让我们看一些例子。
>>> df.loc[['Dean', 'Aaron'], 'food']
Dean Cheese
Aaron Mango
Name: food, dtype: object
>>> df.loc ['Jane':'Penelope',['state','color']]
>>> df.loc ['Jane','age']
30
>>> df.loc [:'Dean','height':]
可以使用单个冒号选择所有行。然后,您可以照常选择列:
>>> df.loc [:, ['food','color']]
>>> df.loc [['Penelope','Cornelia'],:]
但是,正如我们所见,这不是必需的,因此您可以省略最后一个冒号:
>>> df.loc [['Penelope','Cornelia']]
在使用之前,将行和列选择分配给变量可能会更容易.loc。如果要选择许多行或列,这将很有用:
>>> rows = ['Jane', 'Niko', 'Dean', 'Penelope', 'Christina']
>>> cols = ['state', 'age', 'height', 'score']
>>> df.loc[rows, cols]
该.iloc索引是非常相似的.loc,但只使用整数位置做出选择。该词.iloc本身代表整数位置,因此应有助于记住它的作用。
通过将单个整数传递给.iloc,它将选择一行作为系列:
>>> df.iloc[3]
state AL
color white
food Apple
age 4
height 80
score 3.3
Name: Penelope, dtype: object
使用整数列表选择多行:
>>> df.iloc[[5, 2, 4]] # remember, don't do df.iloc[5, 2, 4]
切片符号的作用类似于此实例中的列表,并且不包括最后一个元素
>>> df.iloc [3:5]
>>> df.iloc [3:]
>>> df.iloc [3 :: 2]
就像.iloc单个整数的任何组合一样,整数或切片的列表可用于同时选择行和列。只需记住用逗号分隔选择即可。
>>> df.iloc [[2,3],[0,4]]
>>> df.iloc [3:6,[1,4]]
>>> df.iloc [2:5,2:5]
>>> df.iloc [0,2]
'Steak'
>>> df.iloc[:, 5]
Jane 4.6
Niko 8.3
Aaron 9.0
Penelope 3.3
Dean 1.8
Christina 9.5
Cornelia 2.2
Name: score, dtype: float64
在pandas发展的早期,存在另一个索引器**ix**。该索引器能够通过标签和整数位置进行选择。尽管它用途广泛,但由于不明确,引起了很多混乱。有时,整数也可以作为行或列的标签。因此,在某些情况下它是模棱两可的。
您仍然可以拨打电话**.ix**,但是该电话已被弃用,因此请不要使用它。
当然,我们也可以使用系列进行子集选择。早些时候,我建议仅使用索引运算符在DataFrame上进行列选择。由于Series没有列,我建议仅使用**.loc**和**.iloc**。您可以只使用索引运算符,但是它含糊不清,因为它可以同时使用标签和整数。在本教程的结尾,我将回到这一点。
通常,您将通过从DataFrame中选择单个列来创建一个Series。让我们选择**food**列:
>>> food = df['food']
>>> food
Jane Steak
Niko Lamb
Aaron Mango
Penelope Apple
Dean Cheese
Christina Melon
Cornelia Beans
Name: food, dtype: object
系列选择.loc非常简单,因为我们只处理一个维度。您可以再次使用单个行标签,行标签列表或行标签切片来进行选择。让我们看几个例子。
>>> food.loc ['Aaron']
'Mango'
选择三个不同的值。这将返回一个Series:
>>> food.loc[['Dean', 'Niko', 'Cornelia']]
Dean Cheese
Niko Lamb
Cornelia Beans
Name: food, dtype: object
切片从Niko到Christina-包括最后一个索引:
>>> food.loc['Niko':'Christina']
Niko Lamb
Aaron Mango
Penelope Apple
Dean Cheese
Christina Melon
Name: food, dtype: object
从头到尾切片Penelope:
>>> food.loc['Penelope':]
Penelope Apple
Dean Cheese
Christina Melon
Cornelia Beans
Name: food, dtype: object
在列表中选择一个返回序列的值:
>>> food.loc[['Aaron']]
Aaron Mango
Name: food, dtype: object
序列子集的选择与**.iloc**发生类似,**.loc**只不过它使用整数位置。您可以使用单个整数,整数列表或整数切片。让我们看一些例子。
选择一个值:
>>> food.iloc[0]
'Steak'
使用整数列表选择多个值:
>>> food.iloc[[4, 1, 3]]
Dean Cheese
Niko Lamb
Penelope Apple
Name: food, dtype: object
使用切片-不包括最后一个整数
>>> food.iloc[4:6]
Dean Cheese
Christina Melon
Name: food, dtype: object
将pandas根据标签和整数位置进行选择的能力与Python列表和字典的选择能力进行比较可能会有所帮助。
您可以使用单个整数或切片符号来进行选择,但不能使用整数列表。
让我们看一下使用整数的列表子集选择的示例:
>>> some_list = ['a','two',10,4,0,'asdf','mgmt',
434,99
]
>>> some_list [5]
'asdf'
>>> some_list [-1]
99
>>> some_list [:4]
['a','two',
10,4
]
>>> some_list [3:]
[
4,0
,'asdf','mgmt',
434,99
]
>>> some_list [2:6:3]
[10,'asdf']
每个字典中的所有值都用键标记。
我们使用此键进行单个选择。词典仅允许使用单个标签进行选择。标签的切片和列表均不允许。
>>> d = {'a':1,'b':2,'t':20,'z':26,'A':27}
>>> d ['a']
1
>>> d ['A']
27
DataFrame和Series可以使用整数(如列表)和标签(如字典)进行选择。
上面,我仅使用索引运算符从DataFrame中选择一列或多列。但是,它也可以用于使用slice选择行。我认为这种行为非常令人困惑。传递切片时,整个操作将完全更改。
让我们使用整数切片作为第一个示例:
>>> df [3:6]
了增加这种混乱,您还可以按标签切片。
>>> df ['Aaron':'Christina']
此功能不会被弃用,并且完全取决于您是否要使用它。但是,我非常希望不要以这种方式选择行,因为这样可能会造成歧义,尤其是在索引中包含整数的情况下。
使用**.iloc**和**.loc**是明确的,可以清楚地告诉阅读代码的人将会发生什么。让我们使用**.iloc**和重写上面的内容**.loc**。
>>> df.iloc[3:6] # More explicit that df[3:6]
>>> df.loc['Aaron':'Christina']
如果尝试仅使用索引运算符同时选择行和列,则会引发异常。您必须使用**.loc**或**.iloc**这样做。
>>> df[3:6, 'Aaron':'Christina']
TypeError: unhashable type: 'slice'
您也可以仅将索引运算符与系列一起使用。同样,这令人困惑,因为它可以接受整数或标签。让我们看一些例子
>>> food
Jane Steak
Niko Lamb
Aaron Mango
Penelope Apple
Dean Cheese
Christina Melon
Cornelia Beans
Name: food, dtype: object>>> food[2:4]
Aaron Mango
Penelope Apple
Name: food, dtype: object>>> food['Niko':'Dean']
Niko Lamb
Aaron Mango
Penelope Apple
Dean Cheese
Name: food, dtype: object
Since Series don’t have columns you can use a single label and list of labels to make selections as well
>>> food['Dean']
'Cheese'>>> food[['Dean', 'Christina', 'Aaron']]
Dean Cheese
Christina Melon
Aaron Mango
Name: food, dtype: object
Again, I recommend against doing this and always use **.iloc** or **.loc**
我们通过选择第一列作为带有函数**index_col**参数的索引来导入数据**read_csv**。通常,这不是将大多数DataFrame读入pandas的方式。
通常,csv文件中的所有列都将成为DataFrame列。熊猫将使用0到n-1之间的整数作为标签。请参见下面的示例数据,其中的数据集略有不同:
>>> df2 = pd.read_csv('data / sample_data2.csv')
>>> df2
如果您在第一次读取数据时未将列指定为索引,则熊猫将使用0到n-1之间的整数作为索引。从技术上讲,这会创建一个**RangeIndex**对象。让我们来看看它。
>>> df2.index
RangeIndex(start=0, stop=7, step=1)
This object is similar to Python **range** objects. Let's create one:
>>> range(7)
range(0, 7)
Converting both of these objects to a list produces the exact same thing:
>>> list(df2.index)
[0, 1, 2, 3, 4, 5, 6]
>>> list(range(7))
[0, 1, 2, 3, 4, 5, 6]
目前,拥有一点都不重要**RangeIndex**。与**.loc**和的选择相同**.iloc**。让我们看一些例子。
df2.loc [[2,4,5],['food','color']]
>>> df2.iloc [[2,4,5],[3,2]]
>>> df2.iloc [:3]`
>>> df2.loc [:3]
常见的情况是看到熊猫代码读取带有RangeIndex的DataFrame,然后将索引设置为列之一。通常使用以下**set_index**方法完成此操作:
>>> df2_idx = df2.set_index('Names')
>>> df2_idx
请注意,此DataFrame与本教程开头的第一个看起来并不完全相同。索引正上方是黑体字**Names**。从技术上讲,这是索引的名称。我们原始的DataFrame没有为其索引命名。您现在可以忽略此小细节。子集选择将以相同的方式发生。
Pandas允许您使用点符号选择一个列作为“系列” 。这也称为属性访问。您只需将列名放在圆点和DataFrame之后,而不用引号,如下所示:
>>> df.state
Jane NY
Niko TX
Aaron FL
Penelope AL
Dean AK
Christina TX
Cornelia TX
Name: state, dtype: object
>>> df.age
Jane 30
Niko 2
Aaron 12
Penelope 4
Dean 32
Christina 33
Cornelia 69
Name: age, dtype: int64
选择这样的列的最大好处是,在选择后链接方法时会获得帮助。例如,如果您在列名后放置另一个点并按tab,则所有Series方法的列表将出现在弹出菜单中。它看起来像这样:
仅使用索引运算符时,此帮助将消失:
最大的缺点是您不能选择空格或其他字符无效的列作为Python标识符(变量名)。
这很奇怪,但是实际上您可以多次选择同一列:
df [['age','age','age']]
我们涵盖了不可思议的领域。让我们总结所有要点:
本文转载自:好好先生,如有侵权请联系删除
知乎原文链接:好好先生:Pandas 操作数据集(最全总结之一)