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整个数组单一 dtypeint64float64bool<U5(字符串)
Series一个 Series 单一 dtype同上,另有 object(存字符串/混合)、datetime64category
DataFrame每列各自一种 dtypedf.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 是”一整块单一类型”,混入字符串会全变 objectDataFrame 是”按列各管各的类型”,所以一张表能同时有数值列和文本列。

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"])     # 从 ndarray

5. 相互转换(重点)

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(常用)

转换关系速查表

从 \ 到ndarraySeriesDataFramelist/dict
ndarraypd.Series(a)pd.DataFrame(a)a.tolist()
Seriess.to_numpy()s.to_frame()s.tolist()
DataFramedf.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?

维度ndarraySeries / DataFrame
标签无,只能用位置有 index/列名,可按标签取
类型整体单一DataFrame 每列可不同类型
缺失值不擅长(NaN 混算)原生支持 NaNdropna/fillna
数据对齐运算按 index 自动对齐
场景纯数值/矩阵计算、喂给模型带标签的真实数据集、清洗分析

典型分工:用 pandas 读数据、清洗、探索(DataFrame)→ 训练前 df.to_numpy() 转成 ndarray 喂给 NumPy/sklearn/PyTorch。

8. 常见坑

  • Series 运算按 index 对齐:两个 index 不同的 Series 相加,对不上的位置变 NaN——不是按位置加!要按位置就先 .to_numpy()
  • df.values vs df.to_numpy():功能类似,官方推荐 to_numpy();混合类型的 DataFrame 转出来的 ndarray 会变成 object dtype
  • 取一行也是 Seriesdf.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.mdbroadcasting.md
  • sklearn / PyTorch:训练前常把 DataFrame to_numpy() 再喂进去;见 sklearn.mdtorch.md
  • Index 对象 — Series/DataFrame 的行列标签本身也是一种数据结构(pd.Index
  • 官方文档:https://pandas.pydata.org/docs/user_guide/dsintro.html