Pandas 数据结构 – Series
Pandas Series 数据结构详解
1. Series 概述
Series 是 Pandas 的一维带标签数组,类似于带名字的列或字典:
- 数据:任意类型(数值、字符串、Python 对象等)
- 索引:整数、字符串、时间戳等标签
- 单一数据类型:每个 Series 元素类型一致(底层基于 NumPy)
import pandas as pd
import numpy as np
# 基本创建
s = pd.Series([1, 3, 5, np.nan, 6, 8])
print(s)
2. 创建 Series
2.1 从列表或数组创建
# 整数索引(默认)
s1 = pd.Series([10, 20, 30, 40])
print(s1)
# 0 10
# 1 20
# 2 30
# 3 40
# 自定义索引
s2 = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
print(s2)
# a 10
# b 20
# c 30
# d 40
2.2 从字典创建
# 字典自动成为索引
data = {'a': 1, 'b': 2, 'c': 3}
s3 = pd.Series(data)
print(s3)
# a 1
# b 2
# c 3
2.3 从标量创建
# 标量广播到所有索引
s4 = pd.Series(5, index=['a', 'b', 'c'])
print(s4)
# a 5
# b 5
# c 5
2.4 指定数据类型
# 强制类型转换
s5 = pd.Series([1, 2, 3], dtype='float32')
s6 = pd.Series(['a', 'b', 'c'], dtype='category')
print(s5.dtype) # float32
print(s6.dtype) # category
3. Series 属性和方法
3.1 核心属性
s = pd.Series([1, 3, 5, np.nan, 6, 8], index=['a', 'b', 'c', 'd', 'e', 'f'])
print(f"值: {s.values}") # numpy 数组
print(f"索引: {s.index}") # Index 对象
print(f"数据类型: {s.dtype}") # dtype
print(f"形状: {s.shape}") # 元组 (n,)
print(f"大小: {s.size}") # 元素个数
print(f"索引名称: {s.index.name}") # 索引名
print(f"是否有 NaN: {s.hasnans}") # bool
3.2 基本信息
print(f"长度: {len(s)}")
print(f"空值数量: {s.isnull().sum()}")
print(f"非空数量: {s.notnull().sum()}")
4. 索引和切片
4.1 位置索引(iloc)
s = pd.Series([10, 20, 30, 40, 50], index=['a', 'b', 'c', 'd', 'e'])
# 按位置访问
print(s.iloc[0]) # 10 (第一个元素)
print(s.iloc[1:3]) # Series([20, 30])
print(s.iloc[[0, 2, 4]]) # 多位置选择
4.2 标签索引(loc)
# 按标签访问
print(s.loc['a']) # 10
print(s.loc['b':'d']) # Series(['b':20, 'c':30, 'd':40])
print(s.loc[['a', 'c', 'e']])
4.3 混合索引(混合使用)
# 布尔索引
print(s[s > 25]) # 选择大于25的元素
# 条件索引
mask = s.index.str.startswith('a')
print(s[mask])
4.4 Fancy Indexing
# 多维索引
indices = ['a', 'c', 'e']
print(s.loc[indices])
print(s.iloc[[0, 2, 4]])
5. 数据操作
5.1 赋值和修改
s = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])
# 单个元素赋值
s.loc['a'] = 10
s.iloc[1] = 20
# 批量赋值
s.loc[['b', 'c']] = [200, 300]
s.iloc[0:2] = [100, 200]
print(s)
5.2 数学运算
s1 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
s2 = pd.Series([4, 5, 6], index=['a', 'b', 'd'])
# 对齐运算(按索引对齐)
print(s1 + s2)
# a 5.0
# b 7.0
# c NaN
# d NaN
# 标量运算
print(s1 * 2)
5.3 统计方法
s = pd.Series([1, 3, 5, np.nan, 6, 8])
print(f"平均值: {s.mean()}") # 4.6
print(f"中位数: {s.median()}") # 5.0
print(f"标准差: {s.std()}")
print(f"最小值: {s.min()}")
print(f"最大值: {s.max()}")
print(f"分位数: {s.quantile(0.75)}")
# 描述性统计
print(s.describe())
6. 缺失数据处理
6.1 检测缺失值
s = pd.Series([1, np.nan, 3, np.nan, 5])
print(s.isnull()) # True/False 数组
print(s.notnull()) # 反向
print(s.isna().sum()) # 缺失值数量
6.2 填充缺失值
# 前向填充
s_filled = s.fillna(method='ffill')
# 后向填充
s_bfill = s.fillna(method='bfill')
# 指定值填充
s_value = s.fillna(0)
# 均值填充
s_mean = s.fillna(s.mean())
# 删除缺失值
s_drop = s.dropna()
6.3 插值
# 线性插值
s_interp = s.interpolate(method='linear')
7. 排序和唯一值
7.1 排序
s = pd.Series([3, 1, 4, 1, 5], index=['d', 'a', 'b', 'c', 'e'])
# 按值排序
s_sorted = s.sort_values()
print(s_sorted)
# 按索引排序
s_idx_sorted = s.sort_index()
print(s_idx_sorted)
# 降序
s_desc = s.sort_values(ascending=False)
7.2 唯一值和计数
s = pd.Series(['apple', 'banana', 'apple', 'cherry', 'banana'])
print(s.unique()) # 唯一值数组
print(s.value_counts()) # 频数统计
print(s.nunique()) # 唯一值数量
8. 字符串操作
s = pd.Series(['Apple', 'Banana', 'Cherry', 'apple'])
# 字符串方法(需访问 .str)
print(s.str.lower()) # 转小写
print(s.str.upper()) # 转大写
print(s.str.len()) # 字符串长度
print(s.str.startswith('A')) # 以A开头
print(s.str.contains('app')) # 包含子串
9. 时间序列 Series
# 创建日期索引
dates = pd.date_range('20230101', periods=6)
ts = pd.Series(np.random.randn(6), index=dates)
print(ts)
print(ts.index) # DatetimeIndex
# 时间操作
print(ts['2023-01-02']) # 按日期访问
print(ts['2023-01']) # 按月访问
10. 与 NumPy 的关系
# Series 是 NumPy 数组的增强版
s = pd.Series(np.array([1, 2, 3]))
print(type(s.values)) # <class 'numpy.ndarray'>
print(s.values + 1) # NumPy 向量化运算
# 通用函数兼容
print(np.sin(s))
print(np.exp(s))
11. 实际应用示例
11.1 销售数据分析
# 创建销售数据
sales = pd.Series({
'2023-01': 1000,
'2023-02': 1200,
'2023-03': 900,
'2023-04': 1500,
'2023-05': np.nan,
'2023-06': 1800
}, dtype=float)
# 数据分析
print(f"总销售额: {sales.sum()}")
print(f"平均销售额: {sales.mean()}")
print(f"最大月: {sales.idxmax()}")
# 缺失值处理
sales_filled = sales.fillna(method='ffill')
print(f"填补后总销售额: {sales_filled.sum()}")
11.2 学生成绩分析
scores = pd.Series([85, 92, 78, 95, 88, np.nan, 91],
index=['张三', '李四', '王五', '赵六', '孙七', '周八', '吴九'])
# 及格率
pass_rate = (scores >= 60).mean()
print(f"及格率: {pass_rate:.1%}")
# 排名
scores_ranked = scores.rank(ascending=False)
print("成绩排名:\n", scores_ranked)
# 填补缺失值(用平均分)
scores_filled = scores.fillna(scores.mean())
print(f"平均分: {scores_filled.mean():.1f}")
12. 性能注意事项
# 避免链式索引(性能差)
s = pd.Series([1, 2, 3])
# 差:s['a'][0] = 10 # SettingWithCopyWarning
# 好:s.loc['a'] = 10
# 大数据量操作
large_s = pd.Series(np.random.randn(1000000))
%timeit large_s.mean() # 向量化操作很快
13. 常见错误和解决方案
13.1 SettingWithCopyWarning
# 错误写法
df = pd.DataFrame({'A': [1, 2]})
view = df[df['A'] > 1]
view['A'] = 10 # Warning!
# 正确写法
df.loc[df['A'] > 1, 'A'] = 10
# 或
df_copy = df.copy()
df_copy.loc[df_copy['A'] > 1, 'A'] = 10
Series 是 Pandas 数据处理的基础,掌握其索引、操作和方法是学习 DataFrame 的前提。通过练习不同场景的创建和操作,可以快速上手 Pandas 的核心功能。