NumPy 与 pandas 的数据结构与相互转换
1. 定义
做数据分析时最核心的三个数据结构:
np.ndarray(NumPy):n 维数组,纯数值、无标签,计算快pd.Series(pandas):带标签的一维数组(= ndarray + index)pd.DataFrame(pandas):带行列标签的二维表(= 多个共享 index 的 Series 拼起来)
一句话关系:DataFrame 的每一列是一个 Series,Series 的底层数据是一个 ndarray。 三者层层包装,理解这个包含关系,转换就通了。
2. 三者的关系(层层包装)
DataFrame(二维表)
├── index(行标签)
├── columns(列标签)
└── 每一列 = Series ──┐
│
Series(一维带标签)
├── index(标签)
└── .values = ndarray ──┐
│
ndarray(纯数值,无标签)
├── dtype(元素类型)
└── shape(形状)
- ndarray:只有数据和形状,没有”名字/标签”
- Series:给 ndarray 的每个元素配了一个 index 标签,还有个
name - DataFrame:把多个 Series 按列拼起来,共享同一套行 index,每列有自己的列名
3. dtype(数据类型)对照
| 说明 | 例子 | |
|---|---|---|
| ndarray | 整个数组单一 dtype | int64、float64、bool、<U5(字符串) |
| Series | 一个 Series 单一 dtype | 同上,另有 object(存字符串/混合)、datetime64、category |
| DataFrame | 每列各自一种 dtype | 用 df.dtypes 看每列类型 |
import numpy as np, pandas as pd
arr = np.array([1, 2, 3])
arr.dtype # dtype('int64')
s = pd.Series([1, 2, 3])
s.dtype # dtype('int64')
df = pd.DataFrame({"a": [1, 2], "b": ["x", "y"]})
df.dtypes # a: int64 ; b: object(字符串在 pandas 里是 object)关键:ndarray/Series 是”一整块单一类型”,混入字符串会全变
object;DataFrame 是”按列各管各的类型”,所以一张表能同时有数值列和文本列。
4. 创建
import numpy as np, pandas as pd
# ── ndarray ──
np.array([1, 2, 3])
np.array([[1, 2], [3, 4]])
# ── Series(一维 + 标签)──
pd.Series([10, 20, 30]) # 默认 index 0,1,2
pd.Series([10, 20, 30], index=["a", "b", "c"]) # 自定义标签
pd.Series({"a": 10, "b": 20}) # 从 dict,key 成 index
# ── DataFrame(二维表)──
pd.DataFrame({"name": ["Alice", "Bob"], "age": [25, 30]}) # 从 dict(列名→列数据)
pd.DataFrame([[1, 2], [3, 4]], columns=["x", "y"]) # 从二维 list
pd.DataFrame(np.random.randn(3, 2), columns=["a", "b"]) # 从 ndarray5. 相互转换(重点)
ndarray ⇄ Series
arr = np.array([1, 2, 3])
s = pd.Series(arr) # ndarray → Series(加上默认 index)
arr2 = s.values # Series → ndarray(推荐,取底层数组)
arr3 = s.to_numpy() # 同上,官方更推荐的写法ndarray ⇄ DataFrame
arr2d = np.array([[1, 2], [3, 4]])
df = pd.DataFrame(arr2d, columns=["a", "b"]) # ndarray → DataFrame
arr_back = df.to_numpy() # DataFrame → ndarray(丢掉行列标签)
arr_back = df.values # 同上(老写法)Series ⇄ DataFrame
s = pd.Series([1, 2, 3], name="score")
df = s.to_frame() # Series → 单列 DataFrame
df = pd.DataFrame(s) # 同上
col = df["score"] # DataFrame 取一列 → Series
row = df.iloc[0] # DataFrame 取一行 → 也是 Series(列名变成 index)与 Python 原生类型互转
s.tolist() # Series → list
df.to_dict() # DataFrame → dict
arr.tolist() # ndarray → 嵌套 list
df.to_dict("records") # → [{列:值,...}, ...] 每行一个 dict(常用)转换关系速查表
| 从 \ 到 | ndarray | Series | DataFrame | list/dict |
|---|---|---|---|---|
| ndarray | — | pd.Series(a) | pd.DataFrame(a) | a.tolist() |
| Series | s.to_numpy() | — | s.to_frame() | s.tolist() |
| DataFrame | df.to_numpy() | df["col"] | — | df.to_dict() |
6. 各自的常用基本函数
# ── ndarray(数值计算,见 numpy-basics.md)──
arr.shape, arr.dtype, arr.reshape(...), arr.sum(axis=0), arr @ arr.T
# ── Series(带标签的一维)──
s.head(), s.tail() # 前/后几个
s.value_counts() # 每个值出现次数(超常用)
s.unique() # 去重后的值
s.map(lambda x: x*2) # 逐元素变换
s.isna() # 哪些是缺失值
s.astype(float) # 转 dtype
# ── DataFrame(二维表)──
df.head(), df.info() # 预览、看结构和 dtype
df.describe() # 数值列统计摘要(均值/分位数等)
df.shape, df.columns, df.index, df.dtypes
df["col"] # 取列(→ Series)
df.groupby("k").mean() # 分组聚合
df.sort_values("age") # 按列排序
df.dropna(), df.fillna(0) # 处理缺失值
df.apply(func) # 按列/行应用函数7. 关键区别:为什么要有 Series/DataFrame,不直接用 ndarray?
| 维度 | ndarray | Series / DataFrame |
|---|---|---|
| 标签 | 无,只能用位置 | 有 index/列名,可按标签取 |
| 类型 | 整体单一 | DataFrame 每列可不同类型 |
| 缺失值 | 不擅长(NaN 混算) | 原生支持 NaN、dropna/fillna |
| 数据对齐 | 无 | 运算按 index 自动对齐 |
| 场景 | 纯数值/矩阵计算、喂给模型 | 带标签的真实数据集、清洗分析 |
典型分工:用 pandas 读数据、清洗、探索(DataFrame)→ 训练前
df.to_numpy()转成 ndarray 喂给 NumPy/sklearn/PyTorch。
8. 常见坑
Series运算按 index 对齐:两个 index 不同的 Series 相加,对不上的位置变NaN——不是按位置加!要按位置就先.to_numpy()df.valuesvsdf.to_numpy():功能类似,官方推荐to_numpy();混合类型的 DataFrame 转出来的 ndarray 会变成objectdtype- 取一行也是 Series:
df.iloc[0]返回的 Series,原来的列名变成了它的 index,dtype 可能被统一(混合类型行会变 object) - 字符串列是
object不是 str:pandas 里文本列 dtype 显示object,判断时注意 - ndarray → DataFrame 丢标签:反向
to_numpy()会丢掉行列标签,只剩纯数据 - 视图 vs 副本:
s.values可能返回底层 ndarray 的视图,改它可能影响原 Series;要独立数据用.copy() - 一维 ndarray 转 DataFrame 是一列还是一行:
pd.DataFrame([1,2,3])是 3 行 1 列;想要 1 行用pd.DataFrame([[1,2,3]])
9. 延伸阅读 / 关联概念
- NumPy 基础(数组创建/运算/axis):见
numpy-basics.md - pandas loc/iloc(行列索引):见
pandas-loc-iloc.md - 矩阵运算 / 广播:ndarray 的运算规则;见
matrix-operations.md、broadcasting.md - sklearn / PyTorch:训练前常把 DataFrame
to_numpy()再喂进去;见sklearn.md、torch.md - Index 对象 — Series/DataFrame 的行列标签本身也是一种数据结构(
pd.Index) - 官方文档:https://pandas.pydata.org/docs/user_guide/dsintro.html