索引(Indexing)与选择数据:`loc`, `iloc`, `at`, `iat` 的精确使用

各位亲爱的编程冒险家们,晚上好!欢迎来到“索引与选择数据:loc, iloc, at, iat 的奇幻漂流”讲座现场!我是今晚的船长,哦不,是讲师,名叫“数据老司机”。今天,咱们不聊枯燥的语法,不背生硬的公式,而是要一起扬帆起航,探索 Pandas 库中索引与选择数据的那些事儿,让 loc, iloc, at, iat 这四位“护法”助你披荆斩棘,在数据的大海上乘风破浪!

准备好了吗?让我们解开缆绳,起航喽! 🚢

第一章:索引的艺术,犹如寻宝的地图

想象一下,数据就像一座埋藏着宝藏的小岛,而索引就是指引你找到宝藏的地图。没有地图,你只能像无头苍蝇一样乱撞,最终空手而归。在 Pandas 中,索引就是定位和访问数据的关键。

Pandas 提供了两种主要的索引方式:

  • 标签索引 (Label-based Indexing): 使用行或列的标签(名称)来定位数据。就像在地图上查找“海盗湾”一样,你知道明确的目标地点。
  • 位置索引 (Integer-based Indexing): 使用行或列的整数位置来定位数据。就像在地图上查找“东经120度,北纬30度”一样,你知道具体的坐标。

明白了吧?标签索引是“指名道姓”,位置索引是“按图索骥”。

第二章:四大护法登场:loc, iloc, at, iat

现在,让我们隆重介绍今晚的主角,四位身怀绝技的“护法”:

  • loc (Location): 标签索引的守护者,认标签不认人(位置)。
  • iloc (Integer Location): 位置索引的忠实拥趸,认位置不认标签。
  • at (Access at Label): loc 的精简版,专攻单个元素的标签索引,速度更快。
  • iat (Access at Integer Location): iloc 的精简版,专攻单个元素的位置索引,同样追求速度。

可以把 lociloc 看作是“全能选手”,既可以访问单个元素,也可以访问数据切片。而 atiat 则是“短跑健将”,只擅长访问单个元素,但速度更快,更适合对性能有要求的场景。

第三章:loc 护法:标签索引的王者

loc 护法是标签索引的专家,它只认标签,不认位置。想象一下,你手里拿着一张写着“幸福大街1号”的纸条,loc 护法会帮你找到“幸福大街1号”对应的房子,而不会管它是这条街上的第几栋房子。

语法:

dataframe.loc[row_label, column_label]

其中:

  • row_label: 行标签,可以是单个标签、标签列表或标签切片。
  • column_label: 列标签,可以是单个标签、标签列表或标签切片。

举个栗子 🌰:

import pandas as pd

data = {'姓名': ['张三', '李四', '王五', '赵六'],
        '年龄': [25, 30, 28, 32],
        '城市': ['北京', '上海', '广州', '深圳']}
df = pd.DataFrame(data, index=['A', 'B', 'C', 'D']) # 自定义索引

print(df)
# 输出:
#   姓名  年龄  城市
# A  张三  25  北京
# B  李四  30  上海
# C  王五  28  广州
# D  赵六  32  深圳

# 1. 访问单行数据:
print(df.loc['B'])
# 输出:
# 姓名    李四
# 年龄    30
# 城市    上海
# Name: B, dtype: object

# 2. 访问单列数据:
print(df.loc[:, '年龄']) # 访问所有行的 '年龄' 列
# 输出:
# A    25
# B    30
# C    28
# D    32
# Name: 年龄, dtype: int64

# 3. 访问特定行和列的数据:
print(df.loc['C', '城市']) # 访问 'C' 行的 '城市' 列
# 输出:
# 广州

# 4. 使用标签切片:
print(df.loc['B':'D', '姓名':'城市']) # 访问 'B' 到 'D' 行,'姓名' 到 '城市' 列
# 输出:
#   姓名  年龄  城市
# B  李四  30  上海
# C  王五  28  广州
# D  赵六  32  深圳

# 5. 使用标签列表:
print(df.loc[['A', 'C'], ['姓名', '年龄']]) # 访问 'A' 和 'C' 行的 '姓名' 和 '年龄' 列
# 输出:
#   姓名  年龄
# A  张三  25
# C  王五  28

# 6. 使用布尔索引 (Boolean Indexing):
print(df.loc[df['年龄'] > 28]) # 访问年龄大于 28 的行
# 输出:
#   姓名  年龄  城市
# B  李四  30  上海
# D  赵六  32  深圳

注意事项:

  • 在使用标签切片时,loc 包含切片的结束标签 (inclusive)。
  • 如果使用的标签不存在,loc 会抛出 KeyError 异常。

第四章:iloc 护法:位置索引的先锋

iloc 护法是位置索引的专家,它只认位置,不认标签。想象一下,你手里拿着一张写着“第 3 排,第 2 个座位”的票,iloc 护法会帮你找到电影院里第 3 排的第 2 个座位,而不会管这个座位上写着什么名字。

语法:

dataframe.iloc[row_position, column_position]

其中:

  • row_position: 行位置,可以是单个整数、整数列表或整数切片。
  • column_position: 列位置,可以是单个整数、整数列表或整数切片。

举个栗子 🌰:

import pandas as pd

data = {'姓名': ['张三', '李四', '王五', '赵六'],
        '年龄': [25, 30, 28, 32],
        '城市': ['北京', '上海', '广州', '深圳']}
df = pd.DataFrame(data) # 使用默认整数索引

print(df)
# 输出:
#   姓名  年龄  城市
# 0  张三  25  北京
# 1  李四  30  上海
# 2  王五  28  广州
# 3  赵六  32  深圳

# 1. 访问单行数据:
print(df.iloc[1]) # 访问第 1 行(索引为 1)
# 输出:
# 姓名    李四
# 年龄    30
# 城市    上海
# Name: 1, dtype: object

# 2. 访问单列数据:
print(df.iloc[:, 1]) # 访问所有行的第 1 列(索引为 1)
# 输出:
# 0    25
# 1    30
# 2    28
# 3    32
# Name: 年龄, dtype: int64

# 3. 访问特定行和列的数据:
print(df.iloc[2, 0]) # 访问第 2 行的第 0 列
# 输出:
# 王五

# 4. 使用整数切片:
print(df.iloc[1:3, 0:2]) # 访问第 1 到 2 行,第 0 到 1 列
# 输出:
#   姓名  年龄
# 1  李四  30
# 2  王五  28

# 5. 使用整数列表:
print(df.iloc[[0, 2], [0, 2]]) # 访问第 0 和 2 行的第 0 和 2 列
# 输出:
#   姓名  城市
# 0  张三  北京
# 2  王五  广州

注意事项:

  • 在使用整数切片时,iloc 不包含切片的结束位置 (exclusive)。
  • 如果使用的位置超出范围,iloc 会抛出 IndexError 异常。

第五章:atiat 护法:速度的化身

atiat 护法是 lociloc 的精简版,它们只用于访问单个元素,但速度更快。它们就像数据访问领域的“闪电侠”,能够在眨眼间找到目标。

语法:

dataframe.at[row_label, column_label] # 基于标签
dataframe.iat[row_position, column_position] # 基于位置

举个栗子 🌰:

import pandas as pd

data = {'姓名': ['张三', '李四', '王五', '赵六'],
        '年龄': [25, 30, 28, 32],
        '城市': ['北京', '上海', '广州', '深圳']}
df = pd.DataFrame(data, index=['A', 'B', 'C', 'D'])

# 使用 at 访问单个元素:
print(df.at['B', '年龄']) # 访问 'B' 行的 '年龄' 列
# 输出:
# 30

# 使用 iat 访问单个元素:
print(df.iat[2, 0]) # 访问第 2 行的第 0 列
# 输出:
# 王五

何时使用 atiat

当需要频繁访问 DataFrame 中的单个元素时,例如在循环中,使用 atiat 可以显著提高性能。

第六章:实战演练:数据分析小案例

让我们用一个实际的例子来巩固一下所学知识。假设我们有一个销售数据表,记录了不同产品的销售额。

import pandas as pd

sales_data = {'产品': ['A', 'B', 'C', 'D', 'E'],
              '地区': ['北京', '上海', '广州', '深圳', '北京'],
              '销售额': [100, 150, 80, 120, 90]}
df_sales = pd.DataFrame(sales_data)

print(df_sales)
# 输出:
#   产品  地区  销售额
# 0  A  北京   100
# 1  B  上海   150
# 2  C  广州    80
# 3  D  深圳   120
# 4  E  北京    90

# 1. 找到上海地区的销售额:
shanghai_sales = df_sales.loc[df_sales['地区'] == '上海', '销售额'].values[0] # 使用 .values[0] 获取单个值
print(f"上海地区的销售额: {shanghai_sales}")

# 2. 找到销量最高的产品的名称:
max_sales_product = df_sales.loc[df_sales['销售额'] == df_sales['销售额'].max(), '产品'].values[0]
print(f"销量最高的产品: {max_sales_product}")

# 3. 将北京地区的销售额增加 10%:
df_sales.loc[df_sales['地区'] == '北京', '销售额'] = df_sales.loc[df_sales['地区'] == '北京', '销售额'] * 1.1
print(df_sales)

第七章:总结与注意事项

恭喜各位,我们已经完成了这次索引与选择数据的奇幻漂流!让我们来回顾一下今天学到的知识:

  • loc: 标签索引,认标签不认位置。
  • iloc: 位置索引,认位置不认标签。
  • at: loc 的精简版,访问单个元素,速度更快。
  • iat: iloc 的精简版,访问单个元素,速度更快。

注意事项:

  • 明确你的目标:你是想基于标签索引,还是基于位置索引?
  • 区分切片:loc 包含结束标签,iloc 不包含结束位置。
  • 处理异常:注意 KeyErrorIndexError 异常。
  • 性能优化:在频繁访问单个元素时,考虑使用 atiat
  • 灵活运用布尔索引,可以进行更复杂的数据筛选。

表格总结:

方法 索引类型 访问对象 切片包含结束值 速度
loc 标签 行、列 较慢
iloc 位置 行、列 较慢
at 标签 单个元素 N/A
iat 位置 单个元素 N/A

希望今天的讲座能够帮助大家更好地掌握 Pandas 中索引与选择数据的技巧。记住,熟能生巧,多多练习,你也能成为数据分析的专家! 💪

现在,是提问环节,大家有什么问题吗? 如果没有,就让我们下次再见! 拜拜! 👋

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注