Pandas: DataFrame 核心
最后更新:2026-08-26
DataFrame 是 Pandas 的核心数据结构——它是一张"带标签的二维表格",每一列是一个 Series,拥有独立的类型和名称。你可以把 DataFrame 想象成代码里的 Excel 表或 SQL 表,但它更强大:可编程、可扩展、可版本控制。本节带你深入理解 DataFrame 的本质结构。
⚠️ 注意: 以下代码需在本地 Python 环境中运行。
1. 你将学到
- ❶ DataFrame 的本质(Series 的集合)
- ❷ 行列索引体系(Index + Columns)
- ❸ 创建 DataFrame 的多种方式
- ❹ 查看数据(info / describe / head / tail)
- ❺ 核心属性(shape / index / columns / dtypes / values)
2. Charlie 的电商商品表
(1) 痛点:多列数据怎么一起管理
Charlie 经营一家电商网站,他需要管理商品数据:名称、类别、价格、库存、评分——5 列不同类型的数据。用 Series 的话,他需要维护 5 个独立的 Series 并确保它们的 Index 对齐。
PYTHON
import pandas as pd
# 5 separate Series — must keep index aligned manually
names = pd.Series(['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard'])
categories = pd.Series(['Electronics', 'Electronics', 'Electronics', 'Electronics', 'Accessories'])
prices = pd.Series([999.99, 699.99, 349.99, 449.99, 79.99])
stocks = pd.Series([50, 120, 80, 35, 200])
ratings = pd.Series([4.7, 4.5, 4.3, 4.6, 4.2])
# Which price goes with which product? Hope the index stays aligned!
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) 解法:DataFrame 把列绑在一起
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:DataFrame 管理商品数据(难度⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard'],
'category': ['Electronics', 'Electronics', 'Electronics', 'Electronics', 'Accessories'],
'price': [999.99, 699.99, 349.99, 449.99, 79.99],
'stock': [50, 120, 80, 35, 200],
'rating': [4.7, 4.5, 4.3, 4.6, 4.2]
})
print(df)
# name category price stock rating
# 0 Laptop Electronics 999.99 50 4.7
# 1 Phone Electronics 699.99 120 4.5
# 2 Tablet Electronics 349.99 80 4.3
# 3 Monitor Electronics 449.99 35 4.6
# 4 Keyboard Accessories 79.99 200 4.2
print(df['name']) # a Series
print(df.loc[0]) # first row as a Series
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
5 列数据绑定在一个 DataFrame 中,列名自描述,行自动对齐。
(3) 收益:DataFrame 是"列的集合"
DataFrame 不是"二维 ndarray",而是"Series 的有序字典"——每一列是独立的 Series,有自己的类型,但共享同一个行 Index。
3. DataFrame 的本质结构
(1) 内部结构图解
graph TB
subgraph DataFrame
direction TB
COL["Columns Index<br/>(name, category, price, stock, rating)"]
ROW["Row Index<br/>(0, 1, 2, 3, 4)"]
S1["Series: name<br/>dtype: object"]
S2["Series: category<br/>dtype: object"]
S3["Series: price<br/>dtype: float64"]
S4["Series: stock<br/>dtype: int64"]
S5["Series: rating<br/>dtype: float64"]
end
ROW --> S1
ROW --> S2
ROW --> S3
ROW --> S4
ROW --> S5
COL --> S1
COL --> S2
COL --> S3
COL --> S4
COL --> S5
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
| 概念 | 说明 | 类比 |
|---|---|---|
| 行 Index | 所有列共享的行标签 | Excel 行号 |
| 列 Columns | 每列的名称标签 | Excel 列头 |
| 列 Series | 每列独立的 Series | Excel 单列 |
| values | 底层 2D ndarray | 原始数据矩阵 |
(2) DataFrame vs ndarray 2D
| 特性 | NumPy 2D ndarray | Pandas DataFrame |
|---|---|---|
| 类型约束 | 全局同一 dtype | 每列独立 dtype |
| 行标签 | 无(整数位置) | Index(可自定义) |
| 列标签 | 无(整数位置) | Columns(列名) |
| 列选取 | arr[:, 2] |
df['price'] |
| 行选取 | arr[0, :] |
df.loc[0] |
| 混合类型 | 不支持 | 原生支持 |
| 缺失值 | np.nan(仅浮点) | NaN / NaT / pd.NA |
📌 重点: DataFrame 的
values 属性返回 2D ndarray,但当你有混合类型时它会变成 object 类型——性能会大幅下降。需要纯数值运算时,先选取数值列再做 .values。
4. 创建 DataFrame 的多种方式
(1) 从字典创建(最常用)
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:字典创建 DataFrame(难度⭐)
PYTHON
import pandas as pd
# Dict of lists: keys = column names, values = column data
df = pd.DataFrame({
'product': ['Coffee', 'Tea', 'Juice', 'Water'],
'price': [4.50, 3.80, 5.20, 1.50],
'calories': [5, 2, 120, 0]
})
print(df)
# product price calories
# 0 Coffee 4.50 5
# 1 Tea 3.80 2
# 2 Juice 5.20 120
# 3 Water 1.50 0
# Custom row index
df2 = pd.DataFrame({
'product': ['Coffee', 'Tea', 'Juice'],
'price': [4.50, 3.80, 5.20]
}, index=['A001', 'A002', 'A003'])
print(df2.index) # Index(['A001', 'A002', 'A003'])
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) 从列表的列表创建
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:列表的列表创建 DataFrame(难度⭐)
PYTHON
import pandas as pd
# List of lists: each inner list = one row
data = [
['Coffee', 4.50, 5],
['Tea', 3.80, 2],
['Juice', 5.20, 120],
['Water', 1.50, 0]
]
df = pd.DataFrame(data, columns=['product', 'price', 'calories'])
print(df)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(3) 从字典列表创建
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:字典列表创建 DataFrame(难度⭐)
PYTHON
import pandas as pd
# List of dicts: each dict = one row
data = [
{'product': 'Coffee', 'price': 4.50, 'calories': 5},
{'product': 'Tea', 'price': 3.80, 'calories': 2},
{'product': 'Juice', 'price': 5.20, 'calories': 120}
]
df = pd.DataFrame(data)
print(df)
# Missing keys become NaN
data2 = [
{'product': 'Coffee', 'price': 4.50},
{'product': 'Tea', 'calories': 2}
]
df2 = pd.DataFrame(data2)
print(df2)
# product price calories
# 0 Coffee 4.50 NaN
# 1 Tea NaN 2.0
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(4) 从 NumPy ndarray 创建
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:从 ndarray 创建 DataFrame(难度⭐)
PYTHON
import numpy as np
import pandas as pd
arr = np.random.randn(4, 3) # 4 rows, 3 columns of random numbers
df = pd.DataFrame(arr, columns=['A', 'B', 'C'])
print(df.shape) # (4, 3)
print(df.dtypes) # all float64
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(5) 创建方式对比
| 方式 | 语法 | 特点 | 适用场景 |
|---|---|---|---|
| 字典 | pd.DataFrame({'col': [data]}) |
列优先,最自然 | 最常用 |
| 列表列表 | pd.DataFrame([[r1c1, ...], ...]) |
行优先 | 逐行构建 |
| 字典列表 | pd.DataFrame([{'col': val, ...}, ...]) |
行优先,缺失自动NaN | API/JSON数据 |
| ndarray | pd.DataFrame(np.array(...)) |
同质数据 | NumPy数据转换 |
| read_csv | pd.read_csv('file.csv') |
从文件加载 | 实际项目最常用 |
5. 查看与探查数据
(1) 快速查看:head / tail / sample
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:查看 DataFrame(难度⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard',
'Mouse', 'Headset', 'Speaker', 'Camera', 'Charger'],
'price': [999.99, 699.99, 349.99, 449.99, 79.99,
29.99, 149.99, 89.99, 599.99, 19.99],
'stock': [50, 120, 80, 35, 200, 300, 150, 180, 25, 500]
})
print(df.head()) # first 5 rows
print(df.head(3)) # first 3 rows
print(df.tail(2)) # last 2 rows
print(df.sample(3)) # random 3 rows (for inspection)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) 数据概览:info
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:info 方法详解(难度⭐⭐)
PYTHON
import pandas as pd
import numpy as np
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie', 'Carol', 'David'],
'age': [28, 34, 25, 30, 45],
'salary': [75000.0, 92000.0, np.nan, 88000.0, 105000.0],
'department': ['Sales', 'Engineering', 'Marketing', 'Sales', 'Management']
})
df.info()
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 5 entries, 0 to 4
# Data columns (total 4 columns):
# # Column Non-Null Count Dtype
# --- ------ -------------- -----
# 0 name 5 non-null object
# 1 age 5 non-null int64
# 2 salary 4 non-null float64 ← 1 missing value!
# 3 department 5 non-null object
# dtypes: float64(1), int64(1), object(2)
# memory usage: 288.0+ bytes
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
info() 是数据分析的第一步——它告诉你:有多少行、每列的类型、是否有缺失值、内存占用。
(3) 统计摘要:describe
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:describe 统计摘要(难度⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'price': [999.99, 699.99, 349.99, 449.99, 79.99],
'stock': [50, 120, 80, 35, 200],
'rating': [4.7, 4.5, 4.3, 4.6, 4.2]
})
# Numeric columns only (default)
print(df.describe())
# price stock rating
# count 5.00 5.00 5.00
# mean 515.79 97.00 4.46
# std 347.31 69.72 0.21
# min 79.99 35.00 4.20
# 25% 349.99 50.00 4.30
# 50% 449.99 80.00 4.50
# 75% 699.99 120.00 4.60
# max 999.99 200.00 4.70
# Include all columns
print(df.describe(include='all'))
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
| 方法 | 显示内容 | 适用场景 |
|---|---|---|
df.head() |
前 5 行 | 快速查看数据格式 |
df.info() |
行数/列类型/缺失值/内存 | 第一步必看 |
df.describe() |
数值列统计摘要 | 了解分布 |
df.shape |
(行数, 列数) | 数据规模 |
df.dtypes |
每列类型 | 类型检查 |
6. DataFrame 核心属性
(1) 属性速查表
| 属性 | 返回类型 | 说明 | 示例 |
|---|---|---|---|
df.shape |
tuple | (行数, 列数) | (5, 4) |
df.index |
Index | 行标签 | RangeIndex(0, 5) |
df.columns |
Index | 列名 | Index(['name', 'age', ...]) |
df.dtypes |
Series | 每列类型 | name: object, age: int64 |
df.values |
ndarray | 底层数据 | 2D array |
df.ndim |
int | 维度数 | 2 |
df.size |
int | 元素总数 | 20 (5行4列) |
df.T |
DataFrame | 转置 | 行列互换 |
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:核心属性一览(难度⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'age': [28, 34, 25],
'salary': [75000.0, 92000.0, 68000.0]
})
print(f"Shape: {df.shape}") # (3, 3)
print(f"Index: {df.index}") # RangeIndex(0, 3)
print(f"Columns: {df.columns}") # Index(['name', 'age', 'salary'])
print(f"Dtypes:\n{df.dtypes}")
print(f"Size: {df.size}") # 9
print(f"Ndim: {df.ndim}") # 2
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(2) 列选取与添加
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:列操作(难度⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'age': [28, 34, 25],
'salary': [75000.0, 92000.0, 68000.0]
})
# Select single column → Series
print(type(df['name'])) # <class 'pandas.core.series.Series'>
# Select multiple columns → DataFrame
print(df[['name', 'salary']])
# Add new column
df['bonus'] = df['salary'] * 0.1
df['level'] = df['age'].apply(lambda x: 'Senior' if x >= 30 else 'Junior')
print(df)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
(3) 转置
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:DataFrame 转置(难度⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'Q1': [320, 280, 350],
'Q2': [410, 390, 420]
}, index=['Product A', 'Product B', 'Product C'])
print(df.T)
# Product A Product B Product C
# Q1 320 280 350
# Q2 410 390 420
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
7. 完整示例:电商商品表全流程
▶ 示例
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
:商品数据创建与探查(难度⭐⭐⭐)
PYTHON
import pandas as pd
import numpy as np
# ============================================
# Comprehensive example: E-commerce product
# table creation and exploration
# ============================================
# 1. Create DataFrame
products = pd.DataFrame({
'name': ['Laptop', 'Phone', 'Tablet', 'Monitor', 'Keyboard',
'Mouse', 'Headset', 'Speaker'],
'category': ['Electronics', 'Electronics', 'Electronics',
'Electronics', 'Accessories', 'Accessories',
'Accessories', 'Accessories'],
'price': [999.99, 699.99, 349.99, 449.99, 79.99,
29.99, 149.99, 89.99],
'stock': [50, 120, 80, 35, 200, 300, 150, 180],
'rating': [4.7, 4.5, 4.3, 4.6, 4.2, 4.0, 4.4, 4.1]
})
# 2. Overview
print("=== Product Catalog Overview ===")
print(f"Products: {len(products)}")
print(f"Categories: {products['category'].unique().tolist()}")
print(f"Columns: {products.columns.tolist()}")
# 3. Data types and memory
print(f"\n=== Data Types ===")
print(products.dtypes)
print(f"\nMemory usage: {products.memory_usage(deep=True).sum() / 1024:.1f} KB")
# 4. Quick statistics
print(f"\n=== Price Statistics ===")
print(products['price'].describe())
# 5. Inventory value per product
products['inventory_value'] = products['price'] * products['stock']
print(f"\n=== Top 3 by Inventory Value ===")
print(products.nlargest(3, 'inventory_value')[['name', 'inventory_value']])
# 6. Category breakdown
print(f"\n=== Category Summary ===")
cat_summary = products.groupby('category').agg(
count=('name', 'count'),
avg_price=('price', 'mean'),
total_stock=('stock', 'sum')
)
print(cat_summary)
TEXT
📖 仅展示
> **输出:** 在本地 Python 环境(pandas 2.x)运行。Piston 服务器未预装 pandas,请在本机安装(`pip install pandas`)后实操对照。实际数值会因 pandas 版本略有差异。
预期输出(节选):
TEXT
📖 仅展示
=== Product Catalog Overview ===
Products: 8
Categories: ['Electronics', 'Accessories']
Columns: ['name', 'category', 'price', 'stock', 'rating']
=== Price Statistics ===
count 8.00
mean 349.99
std 339.32
min 29.99
max 999.99
=== Top 3 by Inventory Value ===
name inventory_value
0 Laptop 49999.50
1 Phone 83998.80
3 Monitor 15749.65
=== Category Summary ===
count avg_price total_stock
category
Accessories 4 87.24 830
Electronics 4 624.99 285
❓ 常见问题
Q DataFrame 和 Series 什么关系?
A DataFrame 是 Series 的有序集合——每一列是一个 Series,所有列共享同一个行 Index。取单列返回 Series,取多列返回 DataFrame。取单行也返回 Series(列名作为 Index)。
Q 列能用数字索引吗?
A 可以。如果列名是整数(如
0, 1, 2),用 df[0] 访问会歧义——Pandas 把它当列名而非位置。此时必须用 df.iloc[:, 0] 按位置访问或 df.loc[:, 0] 按标签访问。建议列名用字符串避免混淆。Q info 和 describe 区别?
A info 显示结构信息(行数/列类型/缺失值/内存),describe 显示统计摘要(均值/标准差/分位数/极值)。info 是"数据长什么样",describe 是"数值分布如何"。两者互补,首次接触数据时都应查看。
Q 如何添加/删除列?
A 添加列用
df['new_col'] = values(添加到末尾)或 df.insert(pos, 'new_col', values)(指定位置)。删除列用 df.drop('col', axis=1) 或 del df['col']。drop 返回新 DataFrame(不修改原数据),del 直接修改。Q values 返回什么?
A
df.values 返回底层 2D NumPy ndarray。如果 DataFrame 有混合类型(如 object + int64),ndarray 的 dtype 会升级为 object,丧失向量化性能。纯数值 DataFrame 的 values 保持数值 dtype。Q DataFrame 如何转置?
A 用
df.T 或 df.transpose()。转置后行变列、列变行。注意:转置后如果原 DataFrame 有混合类型,所有列会变为 object 类型(因为 ndarray 要求同质)。Q 创建 DataFrame 用字典还是列表?
A 字典最自然(键=列名,值=列数据),推荐日常使用。字典列表适合逐行构建(如从 API 获取 JSON 数据)。ndarray 适合纯数值数据。实际项目中 80% 的情况用
pd.read_csv() 从文件加载。📖 小节
- DataFrame 本质是 Series 的有序集合,每列独立类型,共享行 Index
- 行 Index + 列 Columns 构成二维标签体系,数据自描述
- 创建方式:字典(最常用)/ 列表列表 / 字典列表 / ndarray / read_csv
- 数据探查三件套:head() 看格式 → info() 看结构 → describe() 看分布
- 核心属性:shape / index / columns / dtypes / values / T
- 列选取:
df['col']返回 Series,df[['c1','c2']]返回 DataFrame - 添加列用
df['new'] = ...,删除列用df.drop('col', axis=1)
📝 作业
- 基础题(难度⭐):用 3 种方式创建学生表(name / math / english / science),打印 info 和 describe 结果。
- 进阶题(难度⭐⭐):创建一个含缺失值的员工表(name / age / salary / department,其中 salary 有 2 个 NaN),完成:info 检查缺失值 → 计算每列非空比例 → 添加一列 salary_level(salary>80000 为 High 否则 Low,NaN 为 Unknown)。
- 挑战题(难度⭐⭐⭐):从字典列表构建 DataFrame(5 条记录,部分键缺失),完成:检查缺失 → 用每列均值/众数填充 → 计算每行的非空字段数 → 添加一列 completeness(非空比例),最终输出完整的 describe 报告。