一、loc、iloc函数

Pandas 中两种主要的索引方法:.loc.iloc。理解它们的关键在于记住它们名字的由来:

  • .loc: 全称 location,意为 “位置”,但它是基于 标签(Label) 进行索引的。
  • .iloc: 全称 integer location,意为 “整数位置”,它是基于 数字索引(Position) 进行索引的。

1.核心区别对比

特性 .loc .iloc
索引依据 标签 (Label)(行索引的名称、列名) 整数位置 (Position)(从 0 开始的索引)
索引方式 支持标签、布尔数组、条件表达式 支持整数、整数数组、切片
切片操作 包含结束边界 不包含结束边界
适用场景 按行名、列名查找数据 按数据的物理位置查找数据
import pandas as pd

data = {'A': [1, 2, 3, 4], 'B': [10, 20, 30, 40], 'C': [100, 200, 300, 400]}
df = pd.DataFrame(data, index=['a', 'b', 'c', 'd'])
print(df)

输出:

   A   B    C
a  1  10  100
b  2  20  200
c  3  30  300
d  4  40  400
1) .loc 的用法

通过行标签列名来索引数据。

  • 单个元素
print(df.loc['b', 'B'])  # 输出: 20
  • 一行数据
print(df.loc['c'])
# 输出:
# A      3
# B     30
# C    300
# Name: c, dtype: int64
  • 多行数据
print(df.loc[['a', 'd']])
# 输出:
#    A   B    C
# a  1  10  100
# d  4  40  400
  • 一列 / 多列数据
print(df.loc[:, ['A', 'C']])
# 输出:
#    A    C
# a  1  100
# b  2  200
# c  3  300
# d  4  400
  • 切片(包含结束标签)
print(df.loc['b':'d', 'A':'B'])
# 输出:
#    A   B
# b  2  20
# c  3  30
# d  4  40
  • 条件索引
print(df.loc[df['B'] > 20])
# 输出:
#    A   B    C
# c  3  30  300
# d  4  40  400
2) .iloc 的用法

通过整数索引(从 0 开始)来索引数据,类似 Python 列表的索引方式。

  • 单个元素
print(df.iloc[1, 1])  # 输出: 20

  • 一行数据
print(df.iloc[2])
# 输出:
# A      3
# B     30
# C    300
# Name: c, dtype: int64

  • 多行数据
print(df.iloc[[0, 3]])
# 输出:
#    A   B    C
# a  1  10  100
# d  4  40  400

  • 一列 / 多列数据
print(df.iloc[:, [0, 2]])
# 输出:
#    A    C
# a  1  100
# b  2  200
# c  3  300
# d  4  400

  • 切片(不包含结束索引)
print(df.iloc[1:3, 0:2])
# 输出:
#    A   B
# b  2  20
# c  3  30

注意:

  • .loc 当你知道行或列的名称时。
  • .iloc 当你知道行或列的位置时。
  • .loc 切片是闭区间(包含结束值),而 .iloc 是半开区间(不包含结束值)

二、分组与聚合

我们来简单总结一下 Pandas 的分组聚合。

一句话概括: 分组聚合是指先根据一个或多个键将数据分成若干个小组,然后对每个小组独立应用一个聚合函数(如求和、求平均等),最后将结果组合起来的过程。

分组聚合是数据分析中最核心的操作之一,它模拟了 SQL 中的 GROUP BY 语句,核心思想是:拆分 -> 应用 -> 合并

  1. 拆分 (Split):按照指定的键将 DataFrame 分割成若干个小组(Group)。
  2. 应用 (Apply):对每个小组独立地应用一个或多个函数(聚合函数)。
  3. 合并 (Combine):将每个小组的计算结果合并成一个新的 DataFrame 或 Series。

1.分组 (Grouping):groupby() 的详细用法

groupby() 是实现分组的核心方法。它的灵活性非常高,可以根据多种方式进行分组。

1) 按列名分组 (最常用)

这是最直接的方式,指定一个或多个列名,Pandas 会根据这些列的唯一组合来创建分组。

import pandas as pd
import numpy as np

# 示例数据
data = {
    'Category': ['Electronics', 'Electronics', 'Clothing', 'Clothing', 'Electronics'],
    'Product': ['Phone', 'Laptop', 'Shirt', 'Pants', 'Tablet'],
    'Region': ['North', 'South', 'North', 'South', 'North'],
    'Sales': [1000, 1500, 500, 750, 800],
    'Quantity': [2, 1, 5, 3, 4]
}
df = pd.DataFrame(data)
print("--- 原始数据 ---")
print(df)
print("\n")

# 1. 按单个列分组
grouped_by_category = df.groupby('Category')
# grouped_by_category 是一个 GroupBy 对象,它本身不显示数据,只是一个分组结构
print("--- 按 'Category' 分组后的 GroupBy 对象 ---")
print(grouped_by_category)

# 你可以查看分组的键
print("\n--- 分组的键 ---")
print(grouped_by_category.groups.keys())

# 你可以查看某个具体的组
print("\n--- 查看 'Electronics' 组的数据 ---")
print(grouped_by_category.get_group('Electronics'))

# 2. 按多个列分组
grouped_by_category_region = df.groupby(['Category', 'Region'])
print("\n--- 按 'Category' 和 'Region' 分组后的 GroupBy 对象 ---")
print(grouped_by_category_region)
print("\n--- 分组的键 (是元组) ---")
print(grouped_by_category_region.groups.keys())

2) 对分组后的结果进行迭代

你可以像遍历字典一样遍历 GroupBy 对象,获取每个组的名称和对应的数据。

print("--- 迭代 GroupBy 对象 ---")
for group_name, group_data in grouped_by_category:
    print(f"\nGroup Name: {group_name}")
    print("-" * 20)
    print(group_data)

2.聚合 (Aggregation):对分组结果应用函数

分组之后,最重要的就是对每个组进行计算。Pandas 提供了多种方式来实现聚合。

1) 使用预定义的聚合方法

GroupBy 对象有许多内置的聚合方法,可以直接调用。

# 按 'Category' 分组后,计算 'Sales' 列的总和
sales_sum_by_category = df.groupby('Category')['Sales'].sum()
print("\n--- 按类别分组后的销售额总和 ---")
print(sales_sum_by_category)
print(type(sales_sum_by_category)) # 结果是一个 Series

# 计算多个列的多个统计量
# 方法一:对所有数值列计算多种统计
stats_by_category = df.groupby('Category').agg(['sum', 'mean', 'count'])
print("\n--- 按类别分组后,所有数值列的 sum, mean, count ---")
print(stats_by_category)
print(type(stats_by_category)) # 结果是一个 DataFrame,列是 MultiIndex

# 方法二:对不同的列应用不同的聚合函数 (推荐,更灵活)
custom_agg_by_category = df.groupby('Category').agg(
    总销售额=('Sales', 'sum'),
    平均销量=('Quantity', 'mean'),
    产品种类数=('Product', 'count') # 或者 'nunique'
)
print("\n--- 按类别分组后,自定义的聚合 ---")
print(custom_agg_by_category)

注意aggaggregate 的别名,用法完全一样。

3. 使用自定义函数进行聚合 (apply)

如果预定义的函数不能满足需求,你可以定义自己的函数,然后使用 .apply() 方法应用到每个组。

.apply() 会将每个组的 DataFrame 作为参数传递给你的自定义函数。

# 定义一个自定义函数
def calculate_profit_margin(group_df):
    """
    假设利润率 = (销售额总和 - 成本) / 销售额总和
    这里为了演示,我们假设成本是销售额的一个固定比例,比如60%
    """
    total_sales = group_df['Sales'].sum()
    cost = total_sales * 0.6
    profit = total_sales - cost
    profit_margin = profit / total_sales
    return profit_margin

# 应用自定义函数
profit_margins = df.groupby('Category').apply(calculate_profit_margin)
print("\n--- 按类别分组后,使用自定义函数计算利润率 ---")
print(profit_margins)

# .apply() 也可以返回一个 Series,从而生成一个有多个列的 DataFrame
def complex_calculation(group_df):
    return pd.Series({
        '总销售额': group_df['Sales'].sum(),
        '最高单价': group_df['Sales'].max() / group_df['Quantity'].max(), # 一个简单的估算
        '商品数量': group_df['Product'].nunique()
    })

complex_results = df.groupby('Category').apply(complex_calculation)
print("\n--- 按类别分组后,使用自定义函数进行复杂计算 ---")
print(complex_results)

3.分组聚合的进阶技巧

1) transform() 方法

transform() 也会对每个组应用一个函数,但它会将计算结果 ** 广播(broadcast)** 回原来的索引位置,最终返回一个与原始 DataFrame 大小相同的 Series 或 DataFrame。这在需要根据组内统计量创建新列时非常有用。

# 计算每个类别内的销售额占比
df['类别总销售额'] = df.groupby('Category')['Sales'].transform('sum')
df['销售额占比'] = df['Sales'] / df['类别总销售额']

print("\n--- 使用 transform 添加新列 ---")
print(df)

2) filter() 方法

filter() 用于根据组的聚合结果来筛选整个组。它接收一个函数,该函数对每个组的 DataFrame 进行计算并返回一个布尔值。如果返回 True,则保留该组;如果返回 False,则丢弃该组。

# 筛选出总销售额大于 2000 的类别
filtered_df = df.groupby('Category').filter(lambda x: x['Sales'].sum() > 2000)

print("\n--- 使用 filter 筛选组 ---")
print("总销售额大于 2000 的组的数据:")
print(filtered_df)

四、总结

方法 作用 输入 输出 核心用途
.groupby() 分组 列名或函数 GroupBy 对象 将数据拆分为多个小组。
.agg() / .aggregate() 聚合 字典、列表或函数 SeriesDataFrame 对每个组计算汇总统计量(如 sum, mean)。
.apply() 应用 自定义函数 标量、SeriesDataFrame 对每个组执行任意复杂的操作和计算。
.transform() 转换 函数 SeriesDataFrame (与原数据同形) 根据组内统计量创建新的列,用于数据标准化、归一化等。
.filter() 筛选 返回布尔值的函数 DataFrame 根据组的整体情况过滤掉整个组。
  • 对于简单的聚合(求和、平均等),优先使用 .agg(),因为它语法简洁且效率高。
  • 当需要进行复杂的、无法用简单聚合函数组合完成的计算时,使用 .apply()
  • 当需要将组统计量广播回原始数据行时,使用 .transform()
  • 当需要根据组的属性(如大小、总和)来筛选数据时,使用 .filter()

三、绘图

Pandas 基础绘图是数据分析中快速可视化数据的重要工具,它基于 Matplotlib 实现,语法简洁、集成度高,能直接对 DataFrame/Series 进行绘图操作。以下从核心逻辑、常用图表类型、基本用法、定制化技巧四方面简单总结:

一、核心逻辑

Pandas 绘图的核心是 “数据优先”:直接调用 DataFrame/Series 的 .plot() 方法,无需手动传递 x/y 数据(默认以索引为 x 轴、列值为 y 轴),一键生成基础图表,大幅简化 Matplotlib 的繁琐配置。

  • 关键依赖:需安装 matplotlib(Pandas 绘图的底层引擎),安装命令:pip install matplotlib
  • 基本语法:
# Series 绘图(默认索引为 x,值为 y)
s.plot(kind="图表类型", ...)

# DataFrame 绘图(默认索引为 x,各列为 y 系列)
df.plot(kind="图表类型", x="指定x列", y=["指定y列1", "指定y列2"], ...)

二、常用图表类型及用途

通过 kind 参数指定图表类型,以下是最常用的 6 种:

图表类型(kind 值) 核心用途 适用数据场景
line(默认) 展示趋势变化 时间序列数据(如每日销量)
bar/barh 对比不同类别数据 分类统计(如各产品销售额)
hist 展示数据分布 连续数据的分布特征(如身高)
pie 展示占比关系 整体中各部分占比(如市场份额)
scatter 展示变量相关性 两个数值变量的关联(如身高 - 体重)
box 展示数据离散程度 异常值检测(如成绩分布)

三、基础用法示例(带输出说明)

假设我们有一个销售数据集 df

import pandas as pd
import matplotlib.pyplot as plt

# 示例数据:日期、产品A销量、产品B销量、利润
df = pd.DataFrame({
    "date": pd.date_range("2024-01-01", periods=5),
    "sales_A": [100, 120, 90, 150, 130],
    "sales_B": [80, 110, 140, 120, 160],
    "profit": [20, 25, 18, 30, 28]
})
df = df.set_index("date")  # 以日期为索引(方便时间序列绘图)

1. 折线图(趋势)
# 绘制A/B产品销量趋势(默认line类型)
df[["sales_A", "sales_B"]].plot(
    title="产品销量趋势图",  # 标题
    xlabel="日期",          # x轴标签
    ylabel="销量",          # y轴标签
    grid=True              # 显示网格
)
plt.show()  # 弹出图表窗口(必须调用才会显示)

输出:一条包含两条线的折线图,清晰展示 5 天内 A/B 产品销量的起伏趋势。

2. 柱状图(对比)
# 绘制单日利润柱状图(指定x为日期,y为利润)
df.plot(
    kind="bar", 
    x="date", 
    y="profit", 
    color="skyblue",  # 柱子颜色
    rot=45            # x轴标签旋转45度(避免重叠)
)
plt.title("每日利润对比")
plt.show()

输出:5 个蓝色柱子,分别对应 5 天的利润,直观对比每日利润差异。

3. 直方图(分布)
# 绘制A产品销量的分布直方图
df["sales_A"].plot(
    kind="hist", 
    bins=3,  # 分3个区间( bins越多,区间越细)
    edgecolor="black"  # 柱子边框颜色(区分区间)
)
plt.title("产品A销量分布")
plt.xlabel("销量区间")
plt.ylabel("频次")
plt.show()

输出:3 个柱子,展示 A 产品销量在不同区间的出现次数(如 100-120 区间出现 2 次)。

4. 饼图(占比)
# 绘制A/B产品总销量占比(需指定y为销量列,autopct显示百分比)
df[["sales_A", "sales_B"]].sum().plot(
    kind="pie", 
    autopct="%1.1f%%",  # 显示百分比(保留1位小数)
    labels=["产品A", "产品B"],  # 自定义标签
    startangle=90       # 饼图起始角度(90度更美观)
)
plt.title("产品销量占比")
plt.ylabel("")  # 隐藏y轴标签(饼图无需y轴)
plt.show()

输出:一个饼图,显示产品 A(约 48.1%)和产品 B(约 51.9%)的总销量占比。

5. 散点图(相关性)
# 绘制销量A与利润的散点图(看相关性)
df.plot(
    kind="scatter", 
    x="sales_A", 
    y="profit", 
    color="red", 
    s=50  # 点的大小
)
plt.title("销量A与利润的相关性")
plt.show()

输出:红色散点,若点呈右上趋势,说明销量 A 越高,利润越高(正相关)。

四、关键定制化技巧

  1. 子图布局:多个图表并排显示,用 subplots=True + layout=(行数, 列数)
df.plot(
    kind="line", 
    subplots=True,  # 每个列单独绘图
    layout=(2, 2),  # 2行2列布局
    figsize=(12, 8) # 整体图大小
)
plt.tight_layout()  # 自动调整子图间距(避免标签重叠)
plt.show()

  1. 样式美化:通过 style 参数指定 Matplotlib 样式(如 seaborn-darkgrid):
plt.style.use("seaborn-v0_8-darkgrid")  # 全局设置样式
df["sales_A"].plot(kind="line", color="orange")
plt.show()

  1. 保存图片:用 plt.savefig() 保存图表(需在 plt.show() 之前调用):
df.plot(kind="bar", y="profit")
plt.title("每日利润")
plt.savefig("profit_bar.png", dpi=300, bbox_inches="tight")  # dpi=分辨率,bbox_inches避免标签被截断
plt.show()

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐