我们在学习Pandas时,最让人困惑的事情之一就是 .loc
和 .iloc
之间的区别。
让我们结束这种困惑,澄清这两种方法之间的差异。我将提供大量示例,希望到这篇博客结束时,区别会更加清晰。
在Pandas中,什么是 .loc 和 .iloc?
.loc
和 .iloc
都是Pandas DataFrame的重要属性,均用于选择特定的数据子集。它们的目的是访问并能够操作DataFrame的特定部分,而不是整个DataFrame。
特性 |
.loc |
.iloc |
语法 |
df.loc[row_indexer, column_indexer] |
df.iloc[row_indexer, column_indexer] |
索引方法 |
基于标签的索引 |
基于位置的索引 |
用于参考 |
行和列标签(名称) |
行和列的数字索引(从0开始) |
从表中可以看出,语法看起来非常相似。不同之处在于如何使用row_indexer
和column_indexer
参数。这是因为这两种方法提供了不同的数据索引方式:而.loc
基于标签名称进行索引,.iloc
则将行和列的数字位置索引作为参数。
让我们逐一详细研究这两种方法,从.loc
开始。
使用.loc:按标签进行选择
为了说明这些概念,让我们考虑一个由这个名为df
的DataFrame表示的假想客户数据库,其中Customer ID
表示行索引:
Customer ID |
姓名 |
国家 |
地区 |
年龄 |
C123 |
约翰·多 |
美国 |
北美洲 |
67 |
C234 |
佩特拉·穆勒 |
德国 |
欧洲 |
51 |
C345 |
Ali Khan |
Pakistan |
Asia |
19 |
C456 |
Maria Gonzalez |
Mexico |
North America |
26 |
C567 |
David Lee |
China |
Asia |
40 |
有四种使用.loc
选择行的主要方法:
- 选择单行
- 选择多个行
- 选择行的切片
- 条件行选择
使用 .loc 选择单行
要选择单行,我们使用要检索的行的标签作为 row_indexer
。因此,语法如下: df.loc['row_label']
。让我们用这个来显示我们客户 Ali Khan 的所有信息:
df.loc['C345']
C345 |
|
姓名 |
阿里·汗 |
国家 |
巴基斯坦 |
地区 |
亚洲 |
年龄 |
19 |
使用.loc选择多行
如果我们想选择不一定按顺序排列的多行,我们必须将它们的行标签列表作为row_indexer
参数传递。这意味着我们需要使用不止一对而是两对方括号:一对用于常规.loc
语法,另一对用于标签列表。
代码df.loc[['row_label_1', 'row_label_2']]
将返回指定列表中的df
数据框的两行。假设我们想知道的不仅是Ali Khan的信息,还包括David Lee的信息:
df.loc[['C345', 'C567']]
客户ID |
姓名 |
国家 |
地区 |
年龄 |
C345 |
阿里·汗 |
巴基斯坦 |
亚洲 |
19 |
C567 |
大卫·李 |
中国 |
亚洲 |
40 |
使用.loc选择行的一部分
我们可以通过传递第一个和最后一个行标签并用冒号分隔来选择一系列行:df.loc['row_label_start':'row_label_end']
。我们可以这样显示数据框的前四行:
df.loc['C123' : 'C456']
客户ID |
姓名 |
国家 |
地区 |
注册日期 |
C123 |
约翰·杜 |
美国 |
北美洲 |
67 |
C234 |
彼得拉·穆勒 |
德国 |
欧洲 |
51 |
C345 |
阿里·汗 |
巴基斯坦 |
亚洲 |
19 |
C456 |
玛丽亚·冈萨雷斯 |
墨西哥 |
北美洲 |
26 |
这里有两件事需要记住:
- 输出包括在
row_label_end
中指定的行。这与.iloc
不同,我们稍后会讨论。 - 我们只使用一对方括号,尽管我们想检索多行。我们不使用列表来指定各行,因此使用两个方括号将返回
SyntaxError
。
使用.loc进行条件选择行
我们还可以根据条件表达式返回行。我们可以通过是否满足某个条件来过滤所有行,仅显示满足条件的行。
对应的语法是df.loc[conditional_expression]
,其中conditional_expression
是关于特定列中允许值的语句。
对于包含非数字数据的列(如 姓名
或 国家
),该语句只能使用等于或不等于运算符,因为值之间没有顺序。例如,我们可以返回所有不来自亚洲的客户的行:
df.loc[df['Region'] != 'Asia']
客户ID |
姓名 |
国家 |
地区 |
年龄 |
C123 |
约翰·多 |
美国 |
北美 |
67 |
C234 |
彼得拉·穆勒 |
德国 |
欧洲 |
51 |
C456 |
玛利亚·冈萨雷斯 |
墨西哥 |
北美洲 |
26 |
使用 .loc 选择单列
要选择列,我们需要指定 column_indexer
参数,该参数在 row_indexer
参数之后。如果我们只想指定 column_indexer
,我们需要以某种方式标记我们想要返回所有行并仅对列进行过滤。让我们看看如何做到这一点!
选择单列可以通过指定相应列的 column_indexer
来完成。要检索所有行,我们需要使用简单的冒号指定 row_indexer
。我们得到了一个看起来像这样语法: df.loc[:, 'column_name']
.
让我们显示每位客户的 姓名
:
df.loc[:, 'Name']
客户ID |
姓名 |
C123 |
约翰·杜 |
C234 |
彼特拉·穆勒 |
C345 |
阿里·汗 |
C456 |
玛丽亚·冈萨雷斯 |
C567 |
大卫·李 |
使用.loc选择多列
与选择多行类似,如果我们想要返回数据框中不一定按顺序排列的多列,我们需要传递一个列标签的列表:df.loc[:, [col_label_1, 'col_label_2']]
。
假设我们想要将所有客户的年龄
添加到我们的最终输出中,可以这样操作:
df.loc[:, ['Name', 'Age']]
客户ID |
姓名 |
年龄 |
C123 |
约翰·杜 |
67 |
C234 |
彼特拉·穆勒 |
51 |
C345 |
Ali Khan |
19 |
C456 |
Maria Gonzalez |
26 |
C567 |
David Lee |
40 |
使用.loc选择列的切片
在两个指定列标签之间使用冒号将选择这两列之间的所有列。它包括最后一列,这意味着列名为col_end
也会在标准语法中被选择,即:df.loc[:, 'col_start':'col_end']
。
如果我们对客户的姓名
、国家
和地区
感兴趣,我们的代码行可以是:
df.loc[:, 'Name':'Region']
客户ID |
姓名 |
国家 |
地区 |
C123 |
约翰·道 |
美国 |
北美洲 |
C234 |
佩特拉·穆勒 |
德国 |
欧洲 |
C345 |
阿里·汗 |
巴基斯坦 |
亚洲 |
C456 |
玛丽亚·冈萨雷斯 |
墨西哥 |
北美洲 |
C567 |
大卫·李 |
中国 |
亚洲 |
结合行和列的选择使用 .loc
也可以同时指定 row_indexer
和 column_indexer
。这可以用来检索单个信息,即来自 DataFrame 的一个单元格。为此,我们使用语法 df.loc['row_label', 'column_name']
指定一行和一列。
更有用的情况是返回一个子 DataFrame,专注于我们感兴趣的行和列集合。可以使用方括号将两个索引器指定为列表,或使用冒号指定为切片,甚至可以结合条件表达式进行行选择。
以下是一个示例,返回每位年龄超过 30 岁的客户的 Name
、Country
和 Region
:
df.loc[df['Age'] > 30, 'Name':'Region']
客户 ID |
姓名 |
国家 |
地区 |
C123 |
约翰·多 |
美国 |
北美 |
C234 |
佩特拉·穆勒 |
德国 |
欧洲 |
C567 |
大卫·李 |
中国 |
亚洲 |
使用 .iloc:按整数位置选择
.iloc
按位置而不是标签选择。这是使用 .iloc
的标准语法:df.iloc[row_indexer, column_indexer]
。需要注意两件特别的事情:
- 从 0 开始计数:第一行和第一列的索引是 0,第二个是 1,依此类推。
- 范围结束值的排他性:使用切片时,冒号后指定的行或列不包括在选择中。
使用 .iloc 选择单行
可以使用表示行索引号的整数作为 row_indexer
选择单行。我们不需要引号,因为我们输入的是整数而不是标签字符串,正如我们使用 .loc
时那样。要返回名为 df
的 DataFrame 的第一行,输入 df.iloc[0]
。
在我们的示例 DataFrame 中,这一行代码返回约翰·多的信息:
df.iloc[0]
C123 |
|
姓名 |
约翰·多 |
国家 |
美国 |
地区 |
北美 |
年龄 |
67 |
使用 .iloc 选择多行
使用 .iloc
选择多行的方式与 .loc
相同——我们在一个带方括号的列表中输入行索引整数。语法如下: df.iloc[[0, 3, 4]]
。
在我们的客户表中可以看到相应的输出如下:
df.iloc[[0, 3, 4]]
客户ID |
姓名 |
国家 |
地区 |
年龄 |
C123 |
约翰·多 |
美国 |
北美洲 |
67 |
C456 |
玛丽亚·冈萨雷斯 |
墨西哥 |
北美洲 |
26 |
C567 |
大卫·李 |
中国 |
亚洲 |
40 |
使用 .iloc 选择行切片
要选择一段行,我们在两个指定的行索引整数之间使用冒号。现在,我们必须注意前面提到的排他性。
我们可以将 df.iloc[1:4]
这一行作为例子来说明这个概念。索引号 1 意味着第二行,因此我们的切片从这里开始。索引整数 4 代表第五行——但由于 .iloc
在切片选择中不包括最后一个,因此我们的输出将包括所有行,直到这一行之前的最后一行。因此,它将返回第二、第三和第四行。
让我们证明这一行的效果是正确的:
df.iloc[1:4]
客户ID |
姓名 |
国家 |
地区 |
年龄 |
C234 |
佩特拉·穆勒 |
德国 |
欧洲 |
51 |
C345 |
阿里·汗 |
巴基斯坦 |
亚洲 |
19 |
C456 |
玛利亚·冈萨雷斯 |
墨西哥 |
北美 |
26 |
选择单列使用.iloc
使用.iloc
选择列的逻辑遵循我们迄今为止学到的内容。让我们看看如何对单个列、多个列和列切片进行操作。
就像使用.loc
一样,重要的是在继续进行column_indexer
之前指定row_indexer
。要检索df
的第三列的每一行的值,我们输入df.iloc[:, 2]
。
因为Region
是我们DataFrame中的第三列,所以它将作为该行代码的结果被检索出来:
df.iloc[:, 2]
Customer ID |
Region |
C123 |
North America |
C234 |
Europe |
C345 |
Asia |
C456 |
North America |
C567 |
Asia |
使用 .iloc 选择多个列
要选择不一定是连续的多个列,我们可以再次输入一个包含整数的列表作为 column_indexer
。代码 df.iloc[:, [0, 3]]
返回第一列和第四列。
在我们的例子中,显示的信息是每位客户的 姓名
和 年龄
:
df.iloc[:, [0, 3]]
客户ID |
姓名 |
年龄 |
C123 |
约翰·多 |
67 |
C234 |
佩特拉·穆勒 |
51 |
C345 |
阿里·汗 |
19 |
C456 |
玛利亚·冈萨雷斯 |
26 |
C567 |
大卫·李 |
40 |
使用 .iloc 选择列的切片
使用 .iloc
进行切片选择时,column_indexer
的逻辑与 row_indexer
相同。冒号后的整数所代表的列不包含在输出中。要检索第二和第三列,代码行应如下所示:df.iloc[:, 1:3]
。
下面这行代码返回我们关于客户的所有地理信息:
df.iloc[:, 1:3]
客户ID |
国家 |
地区 |
C123 |
美国 |
北美 |
C234 |
德国 |
欧洲 |
C345 |
巴基斯坦 |
亚洲 |
C456 |
墨西哥 |
北美洲 |
C567 |
中国 |
亚洲 |
使用 .iloc 进行行列组合选择
我们可以将关于 .iloc
的学习结合起来,以组合行和列的选择。同样,可以返回单个单元格或子数据框。要返回行 3 和列 4 的交集单元格,我们输入 df.iloc[2, 3]
。
就像使用 .loc
一样,我们可以使用方括号将两个索引器指定为列表,或使用冒号指定为切片。如果我们想使用条件表达式选择行,技术上使用 .iloc
也是可能的,但不推荐。使用标签名称和 .loc
通常更直观且不易出错。
这个最后的例子显示了我们数据框中第一、第二和第五行的 国家
、地区
和 年龄
:
df.iloc[[0,1,4], 1:4]
客户ID |
国家 |
地区 |
年龄 |
C123 |
美国 |
北美洲 |
67 |
C234 |
德国 |
欧洲 |
51 |
C567 |
中国 |
亚洲 |
40 |
.iloc vs .loc:何时使用哪个
通常,有一个简单的经验法则,方法的选择取决于您对数据框的了解程度:
- 当您知道行/列的标签(名称)时,请使用
.loc
。 - 当您知道行/列的整数位置时,请使用
.iloc
。
某些情况下,根据其性质会更倾向于使用.loc
或.iloc
。例如,使用整数迭代行或列比使用标签更容易和直观。正如我们已经提到的,基于列值条件过滤行时,使用列标签名称更不容易出错。
偏向于使用.loc的情况 |
偏向于使用.iloc的情况 |
您的DataFrame具有有意义的索引/列名称。 |
您正在按照它们的位置迭代行/列。 |
您需要根据列值的条件进行筛选。 |
索引/列名称与您的任务无关。 |
使用.loc和.iloc时的KeyError、NameError和Index Error
让我们看看可能出现的问题。在使用.loc
时的一个常见问题是遇到KeyError
。当我们尝试访问不存在于DataFrame中的行或列标签时会出现此错误。为了避免这种情况,我们必须始终确保我们使用的标签是准确的,并且它们与DataFrame中现有的标签匹配,并且要仔细检查是否存在拼写错误。
此外,始终使用引号括起使用.loc
指定的标签非常重要。忘记引号将导致NameError
。
当使用 .iloc
时,如果我们指定的整数位置超出了 DataFrame 索引的有效范围,就会发生 IndexError
。当您尝试访问的索引不存在时,就会发生这种情况,可能是因为它超出了 DataFrame 的行数或列数,或者因为它是一个负值。为防止此错误,请检查 DataFrame 的维度,并在有效范围内使用适当的索引值。
结论
我希望这篇博客对您有所帮助,并且现在您对 .loc
和 .iloc
之间的区别有了清晰的认识。要了解更多,以下是一些好的后续步骤: