Pandas: Series 入门

最后更新:2026-08-26

Series 是 Pandas 最基础的数据结构——你可以把它想象成"带标签的一维数组"。一个 Series 由两部分组成:数据(NumPy ndarray)和标签(Index)。正是这个 Index 让 Series 超越了普通数组,让数据拥有了"名字"。本节从 Series 的本质出发,带你掌握创建、运算和常用方法。

⚠️ 注意: 以下代码需在本地 Python 环境中运行。

1. 你将学到


2. Alice 的咖啡店销售日记

(1) 痛点:数字没有名字

Alice 经营一家咖啡店,她用 NumPy 记录了一周的每日销售额:

PYTHON
import numpy as np

sales = np.array([320, 280, 350, 410, 390, 520, 480])
# What day is 520? Position 5... but which day?
print(sales[5])  # 520 — but what does this number mean?
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

数字 520 是周五还是周六?sales[5] 没有告诉你。你必须额外维护一份"位置→星期"的对照表。

(2) 解法:Series 让数据自描述

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:Series 带标签的销售额(难度⭐)

PYTHON
import pandas as pd

sales = pd.Series(
    [320, 280, 350, 410, 390, 520, 480],
    index=['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
    name='daily_sales'
)
print(sales)
# Mon    320
# Tue    280
# Wed    350
# Thu    410
# Fri    390
# Sat    520
# Sun    480
# Name: daily_sales, dtype: int64

print(sales['Sat'])  # 520 — label-based access
print(sales.iloc[5])  # 520 — position-based access
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

Series 把数据和标签绑定在一起——sales['Sat']sales[5] 自解释得多。

(3) 收益:Index 就是数据的名片

有了 Index 标签,数据变得自描述:


3. Series 的本质结构

(1) 两大组件:values + index

100%
graph LR
    A[Series] --> B[values: NumPy ndarray]
    A --> C[index: Index object]
    B --> D[320, 280, 350, ...]
    C --> E["Mon, Tue, Wed, ..."]
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
属性 类型 说明
s.values np.ndarray 底层数据数组
s.index pd.Index 行标签
s.name str Series 名称
s.dtype np.dtype 元素数据类型
s.shape tuple 形状(一维,如 (7,))
s.size int 元素个数

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:Series 属性检查(难度⭐)

PYTHON
import pandas as pd
import numpy as np

s = pd.Series([320, 280, 350], index=['Mon', 'Tue', 'Wed'])

print(f"Type of values: {type(s.values)}")  # <class 'numpy.ndarray'>
print(f"Type of index:  {type(s.index)}")   # <class 'pandas.core.indexes.base.Index'>
print(f"dtype: {s.dtype}")   # int64
print(f"shape: {s.shape}")   # (3,)
print(f"size:  {s.size}")    # 3
print(f"name:  {s.name}")    # None
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

(2) Series vs ndarray 对比

特性 NumPy ndarray Pandas Series
标签 无(仅位置) 有(Index)
混合类型 不支持 不推荐但可(object)
缺失值 np.nan(仅浮点) NaN / pd.NA(全覆盖)
运算对齐 按位置 按标签
名称 name 属性
常用统计 np.mean 等 .mean() 等方法链
底层 ndarray ndarray + Index
📌 重点: Series 本质上就是"ndarray + Index + name"。当你只使用 .values 时,它退化为普通 ndarray。


4. 创建 Series 的多种方式

(1) 从列表创建

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:从列表创建 Series(难度⭐)

PYTHON
import pandas as pd

# Default index: 0, 1, 2, ...
s1 = pd.Series([10, 20, 30, 40])
print(s1)
# 0    10
# 1    20
# 2    30
# 3    40

# Custom index
s2 = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
print(s2['b'])  # 20

# With name
s3 = pd.Series([10, 20, 30], name='scores')
print(s3.name)  # scores
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

(2) 从字典创建

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:从字典创建 Series(难度⭐)

PYTHON
import pandas as pd

# Keys become index, values become data
population = pd.Series({
    'Tokyo': 13960000,
    'New York': 8336000,
    'London': 8982000,
    'Paris': 2161000
})
print(population)
# Tokyo      13960000
# New York    8336000
# London      8982000
# Paris       2161000

print(population['London'])  # 8982000
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

字典创建的优势:键自动成为 Index,无需手动指定。

(3) 从 NumPy ndarray 创建

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:从 ndarray 创建 Series(难度⭐)

PYTHON
import numpy as np
import pandas as pd

arr = np.array([3.14, 2.72, 1.41, 1.73])
s = pd.Series(arr, index=['pi', 'e', 'sqrt2', 'sqrt3'])
print(s)
# pi      3.14
# e       2.72
# sqrt2   1.41
# sqrt3   1.73
print(f"Underlying type: {type(s.values)}")  # numpy.ndarray
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

(4) 从标量创建(广播)

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:标量广播创建 Series(难度⭐)

PYTHON
import pandas as pd

# Broadcast scalar to fill all index positions
s = pd.Series(0, index=['A', 'B', 'C', 'D'])
print(s)
# A    0
# B    0
# C    0
# D    0
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

(5) 创建方式对比

方式 语法 Index 来源 适用场景
列表 pd.Series([1,2,3]) 默认 RangeIndex 快速测试
列表+index pd.Series([1,2,3], index=...) 手动指定 需要自定义标签
字典 pd.Series({'a':1, 'b':2}) 字典键 标签-值对应
ndarray pd.Series(np.array(...)) 默认或指定 NumPy 数据转换
标量 pd.Series(0, index=...) 手动指定 初始化填充

5. Series 的访问方式

(1) 标签访问 vs 位置访问

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:两种访问方式(难度⭐⭐)

PYTHON
import pandas as pd

s = pd.Series([320, 280, 350, 410],
              index=['Mon', 'Tue', 'Wed', 'Thu'])

# Label-based access (preferred)
print(s['Tue'])       # 280
print(s.loc['Tue'])   # 280 — explicit label access

# Position-based access
print(s.iloc[1])      # 280 — explicit position access

# Slice by label (INCLUDES endpoint)
print(s['Mon':'Wed'])
# Mon    320
# Tue    280
# Wed    350

# Slice by position (EXCLUDES endpoint, like Python)
print(s.iloc[0:3])
# Mon    320
# Tue    280
# Wed    350
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
🔥 易错: 标签切片包含端点('Mon':'Wed' 包含 Wed),位置切片不包含端点(iloc[0:3] 不包含位置 3)。这是 Pandas 初学者最常见的混淆点。

(2) 访问方式对比

方式 语法 端点 推荐场景
s[label] 简写 单个标签
s.loc[label] 显式标签 含端点 明确意图
s.iloc[pos] 显式位置 不含端点 按位置索引
s[[l1,l2]] 列表选取 多个标签

6. Series 的运算

(1) 向量化运算

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:Series 向量化运算(难度⭐)

PYTHON
import pandas as pd

sales = pd.Series([320, 280, 350, 410],
                  index=['Mon', 'Tue', 'Wed', 'Thu'])

# Arithmetic operations
print(sales * 1.1)      # 10% price increase
# Mon    352.0
# Tue    308.0
# Wed    385.0
# Thu    451.0

# Comparison operations
print(sales > 300)
# Mon     True
# Tue    False
# Wed     True
# Thu     True

# Filter with boolean
print(sales[sales > 300])
# Mon    320
# Wed    350
# Thu    410
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

(2) Index 对齐运算

这是 Series 最重要的特性之一:运算时按 Index 对齐,而非按位置

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:Index 对齐运算(难度⭐⭐)

PYTHON
import pandas as pd

week1 = pd.Series({'Mon': 320, 'Tue': 280, 'Wed': 350})
week2 = pd.Series({'Tue': 310, 'Wed': 370, 'Thu': 400})

# Auto-align by index, non-matching → NaN
total = week1 + week2
print(total)
# Mon      NaN   # only in week1
# Tue    590.0   # 280 + 310
# Wed    720.0   # 350 + 370
# Thu      NaN   # only in week2

# Fill missing with 0 instead of NaN
total_filled = week1.add(week2, fill_value=0)
print(total_filled)
# Mon    320.0
# Tue    590.0
# Wed    720.0
# Thu    400.0
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
💡 提示: 当两个 Series 的 Index 不完全相同时,Pandas 自动对齐——匹配的标签做运算,不匹配的填 NaN。这避免了"位置错位"的隐蔽 bug。使用 .add(fill_value=0) 等方法可替代 + 运算符,指定缺失值填充策略。


7. Series 常用方法

(1) 统计与描述

方法 说明 等价 NumPy
s.mean() 均值 np.mean(arr)
s.median() 中位数 np.median(arr)
s.std() 标准差 np.std(arr)
s.min() / s.max() 最小/最大 np.min() / np.max()
s.sum() 求和 np.sum(arr)
s.describe() 统计摘要
s.value_counts() 频率统计
s.unique() 去重 np.unique(arr)

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:统计方法(难度⭐)

PYTHON
import pandas as pd

scores = pd.Series([85, 92, 78, 95, 88, 92, 78, 85, 90, 92],
                   name='exam_score')

print(scores.describe())
# count    10.000000
# mean     87.500000
# std       5.976143
# min      78.000000
# 25%      85.000000
# 50%      89.000000
# 75%      92.000000
# max      95.000000

print(scores.value_counts())
# 92    3
# 85    2
# 78    2
# 95    1
# 90    1
# 88    1
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

(2) 查看与筛选

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:head / tail / isin(难度⭐)

PYTHON
import pandas as pd

s = pd.Series(range(1, 101))  # 1 to 100

print(s.head())    # first 5
print(s.tail(3))   # last 3

# isin: membership test
fruits = pd.Series(['apple', 'banana', 'cherry', 'apple', 'date'])
print(fruits.isin(['apple', 'cherry']))
# 0     True
# 1    False
# 2     True
# 3     True
# 4    False
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

(3) NaN 处理

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:NaN 处理方法(难度⭐)

PYTHON
import pandas as pd
import numpy as np

s = pd.Series([10, np.nan, 30, np.nan, 50])

print(s.isna())     # detect NaN
# 0    False
# 1     True
# 2    False
# 3     True
# 4    False

print(s.notna())    # detect non-NaN
print(s.dropna())   # remove NaN: [10.0, 30.0, 50.0]
print(s.fillna(0))  # fill NaN with 0
print(s.fillna(s.mean()))  # fill with mean value
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

8. 完整示例:咖啡店一周销售分析

▶ 示例

TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

:咖啡店销售全流程分析(难度⭐⭐⭐)

PYTHON
import pandas as pd
import numpy as np

# ============================================
# Comprehensive example: Coffee shop weekly
# sales analysis using Series
# ============================================

# 1. Create sales data with day labels
sales = pd.Series({
    'Mon': 320, 'Tue': 280, 'Wed': 350,
    'Thu': 410, 'Fri': 390, 'Sat': 520, 'Sun': 480
}, name='daily_sales_USD')

# 2. Basic statistics
print("=== Weekly Sales Report ===")
print(f"Total:      ${sales.sum():,}")
print(f"Daily avg:  ${sales.mean():.0f}")
print(f"Best day:   {sales.idxmax()} (${sales.max():,})")
print(f"Worst day:  {sales.idxmin()} (${sales.min():,})")
print(f"Std dev:    ${sales.std():.0f}")

# 3. Weekend vs weekday analysis
weekday_avg = sales[['Mon','Tue','Wed','Thu','Fri']].mean()
weekend_avg = sales[['Sat','Sun']].mean()
print(f"\nWeekday avg: ${weekday_avg:.0f}")
print(f"Weekend avg: ${weekend_avg:.0f}")
print(f"Weekend boost: {(weekend_avg/weekday_avg - 1)*100:.1f}%")

# 4. Daily change
change = sales.pct_change() * 100
print(f"\nBiggest daily drop: {change.min():.1f}% on {change.idxmin()}")
print(f"Biggest daily gain: {change.max():.1f}% on {change.idxmax()}")

# 5. Cumulative sales
cum_sales = sales.cumsum()
print(f"\nSales target $2,000 reached on: {cum_sales[cum_sales >= 2000].index[0]}")

# 6. Ranking
print(f"\nSales ranking:\n{sales.rank(ascending=False).astype(int)}")
TEXT 📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。

预期输出(节选):

TEXT 📖 仅展示
=== Weekly Sales Report ===
Total:      $2,750
Daily avg:  $393
Best day:   Sat ($520)
Worst day:  Tue ($280)
Std dev:    $82

Weekday avg: $350
Weekend avg: $500
Weekend boost: 42.9%

Biggest daily drop: -12.5% on Tue
Biggest daily gain: 33.3% on Sat

❓ 常见问题

Q Series 和 ndarray 区别是什么?
A Series = ndarray + Index + name。Series 的底层 values 就是 ndarray,但多了标签索引和名称。运算时 Series 按 Index 对齐,ndarray 按位置对齐。当你不需要标签时,用 .values 提取 ndarray 即可。
Q Index 可以重复吗?
A 可以。Pandas 允许重复 Index,但会降低性能且访问重复标签时返回多个值(一个 Series 而非标量)。建议尽量保持 Index 唯一,用 s.index.is_unique 检查。
Q 运算时 NaN 怎么处理?
A 默认 NaN 传播——任何涉及 NaN 的运算结果都是 NaN。使用 s.mean(skipna=True) 等方法自动跳过 NaN(默认行为)。s.dropna() 删除缺失值,s.fillna() 填充缺失值。
Q value_counts 和 unique 区别?
A unique() 返回去重后的数组(不计数),value_counts() 返回每个值出现的频率(降序排列)。统计频率用 value_counts,只需去重列表用 unique。
Q Series 能存不同类型吗?
A 技术上可以(dtype=object),但不推荐。混合类型的 Series 失去向量化运算能力,性能大幅下降。需要混合类型时应该用 DataFrame——每列独立类型。
Q loc 和 iloc 用哪个好?
A 需要按标签访问用 loc,按位置访问用 iloc。推荐用 loc/iloc 显式声明意图,避免 s[...] 的歧义(可能是标签也可能是位置)。
Q s[label] 和 s.loc[label] 区别?
A 对 Series 来说效果相同。但 s[...] 有歧义——可能是标签也可能是位置(当 Index 是整数时)。s.loc[label] 明确表示按标签,s.iloc[pos] 明确表示按位置,推荐显式写法。

📖 小节


📝 作业

  1. 基础题(难度⭐):用 3 种方式创建 Series(列表+index / 字典 / ndarray),分别打印 index 和 values 属性。
  2. 进阶题(难度⭐⭐):创建两个 Index 不完全相同的 Series(如月度销售额),用 add(fill_value=0) 做加法,对比直接用 + 运算的结果差异。
  3. 挑战题(难度⭐⭐⭐):用 Series 模拟一个产品的月度销售数据(12 个月),完成:计算累计销售额 → 找到累计突破 50,000 的月份 → 计算环比增长率 → 找出增长率最高和最低的月份。

← 上一课:Pandas 入门 · 下一课:DataFrame 核心 →

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏