引言
Python 列表可以说是数据科学领域中最通用、最常用的数据结构之一。它就像一把瑞士军刀,不仅灵活,还提供了丰富的内置方法来帮助我们高效地处理数据。在日常工作中,使用 Pandas 处理数据是我们的家常便饭,但你可能已经注意到了,虽然访问单列数据(作为 Pandas Series)非常简单直接,但要想将 DataFrame 中的完整的行提取出来并放入一个列表中,往往需要一些特定的技巧。
你是否曾遇到过这样的场景:你需要将清洗好的数据传递给一个只接受原生 Python 列表的 API?或者你需要将每一行数据作为一个单独的单元进行迭代处理?这时候,将 DataFrame 转换为列表就显得尤为重要。
在这篇文章中,我们将深入探讨几种实现这一目标的不同方法。不仅会看代码怎么写,还会探讨每种方法背后的原理、性能差异以及最佳实践场景。特别是在 2026 年的今天,随着 AI 辅助编程的普及,我们不仅要写出能跑的代码,还要写出符合“AI 原生”标准的高可维护性代码。让我们准备好你的 Jupyter Notebook,一起开始这段探索之旅吧!
目录
为什么我们需要将 DataFrame 转换为列表?
在开始之前,让我们先达成一个共识:虽然 Pandas 的 DataFrame 功能强大,但它并不是万能的。在以下几种情况下,将其转换为列表是更优的选择:
- API 交互:许多外部库或 REST API 并不直接支持 Pandas DataFrame 或 NumPy 数组,它们通常期望接收原生的 Python 列表或字典列表。
- 类型兼容性:在与其他不依赖科学计算栈的纯 Python 代码集成时,列表是通用的“货币”。
- 数据序列化:虽然 JSON 支持类似结构,但在进行某些特定格式的序列化时,列表往往比 DataFrame 对象更容易处理。
- 2026年的新视角:随着 AI Agent(代理智能)的兴起,我们的代码常常需要作为 Prompt 的一部分传递给 LLM,或者被 AI Agent 调用。原生的 Python 列表(尤其是字典列表)具有更好的“可读性”和“可解释性”,这符合现代 AI 友好型代码的发展趋势。
方法一:使用 values.tolist() 的高效转换
这是我们最常推荐的方法之一,特别是在对性能有较高要求的场景下。这个方法的逻辑非常清晰:它首先利用 INLINECODE5414d0a6 属性提取出 DataFrame 的底层 NumPy 数组,然后直接调用 NumPy 数组的 INLINECODEa253b7e3 方法。
代码示例
让我们来看一个实际的例子。假设我们正在处理一个包含活动日期、名称和成本的表格。
import pandas as pd
import numpy as np
# 创建 DataFrame
df = pd.DataFrame({
‘Date‘: [‘10/2/2011‘, ‘11/2/2011‘, ‘12/2/2011‘, ‘13/2/2011‘],
‘Event‘: [‘Music‘, ‘Poetry‘, ‘Theatre‘, ‘Comedy‘],
‘Cost‘: [10000, 5000, 15000, 2000]
})
# 将 DataFrame 转换为列表
# 注意:这里的 df.values 实际上返回的是 NumPy ndarray
res = df.values.tolist()
print("转换后的列表:")
print(res)
输出:
[[‘10/2/2011‘, ‘Music‘, 10000], [‘11/2/2011‘, ‘Poetry‘, 5000], [‘12/2/2011‘, ‘Theatre‘, 15000], [‘13/2/2011‘, ‘Comedy‘, 2000]]
当你运行 INLINECODE7cab5b47 时,Pandas 实际上是在视图上操作,这意味着在某些情况下它非常快,因为它不一定会立即复制内存(直到你真正修改它)。随后调用的 INLINECODEb7ee9159 会将这个二维数组转换为纯粹的 Python 列表对象列表。
重要提示:这种方法非常直接,但它有一个特点:它会丢失列名索引。你得到的只是纯粹的数据值的组合。如果你不在乎列名,只在乎数据本身,这是最快的方法。
方法二:使用 to_numpy().tolist() 的现代方式
随着 Pandas 的不断发展,INLINECODEc83eae25 属性逐渐被视为一种“遗留”访问方式。为了明确意图并保持代码的现代性,官方推荐使用 INLINECODEa0827f72 方法。虽然在使用 INLINECODEf2acb174 的结果上,两者几乎没有区别,但 INLINECODEe9527fc6 提供了更好的灵活性,比如可以轻松指定数据类型。
代码示例
import pandas as pd
# 创建 DataFrame
data = {
‘Name‘: [‘Tom‘, ‘Jerry‘, ‘Mickey‘],
‘Age‘: [20, 22, 21],
‘Score‘: [85.5, 90.0, 88.0]
}
df = pd.DataFrame(data)
# 推荐的现代方式:先转为 NumPy 数组,再转为列表
# 我们可以显式定义 dtype,这在处理混合数据时非常有用
res = df.to_numpy(dtype=object).tolist()
print("结果列表:")
for row in res:
print(row)
最佳实践
当你需要显式地控制转换过程,或者你的代码库需要与最新版本的 Pandas 保持兼容时,请优先选择这种方法。它的可读性更好——我们明确地在说“把它变成 NumPy 数组,然后变成列表”。
方法三:保留列名的结构化数据 to_dict(orient=‘records‘)
前两种方法返回的是“列表的列表”,这在数据量大的时候很高效,但它的缺点是可读性差。如果你拿到的是 [‘Tom‘, 20, 85.5],你很难瞬间反应过来 20 代表的是年龄还是分数。
这时候,INLINECODEbcc83220 方法就派上用场了。特别是当我们使用 INLINECODEd4e84bef 参数时,每一行会被转换为一个字典,其中键是列名,值是对应的数据。
代码示例
import pandas as pd
import json
# 创建一个包含产品信息的 DataFrame
df = pd.DataFrame({
‘Product_ID‘: [101, 102, 103],
‘Product_Name‘: [‘Laptop‘, ‘Mouse‘, ‘Keyboard‘],
‘Price‘: [1200, 25, 50]
})
# 转换为字典列表,保留列名
# 这是在构建 API 响应时的黄金标准
res = df.to_dict(orient=‘records‘)
print("转换为字典列表(结构化数据):")
print(json.dumps(res, indent=4))
输出:
转换为字典列表(结构化数据):
[
{"Product_ID": 101, "Product_Name": "Laptop", "Price": 1200},
{"Product_ID": 102, "Product_Name": "Mouse", "Price": 25},
{"Product_ID": 103, "Product_Name": "Keyboard", "Price": 50}
]
什么时候使用这个?
- 构建 JSON API 响应:如果你正在使用 Flask 或 FastAPI 构建 API,通常直接返回这种结构是最方便的。
- AI 上下文构建:在 2026 年,我们经常需要将数据喂给 LLM。字典列表的结构化语义比单纯的数值列表更能帮助 AI 理解数据含义。
方法四:使用 itertuples() 处理大规模数据
如果你的 DataFrame 非常大(例如数百万行),使用 INLINECODE51416ca6 或 INLINECODE4a5e218f 可能会瞬间消耗大量的内存,因为它们会一次性生成所有对象。为了解决这个问题,我们需要一种“惰性”的方法。
itertuples() 是一个迭代器,它一次只生成一行数据,并且是以 命名元组 的形式。这非常高效,因为元组比列表或字典占用更少的内存。
代码示例
import pandas as pd
# 创建一个较大的 DataFrame 示例(这里仅用少量数据演示语法)
df = pd.DataFrame({
‘x‘: [1, 2, 3],
‘y‘: [4, 5, 6]
})
# 使用列表推导式结合 itertuples
# index=False 表示我们不把行索引(0, 1, 2...)包含在元组中
res = [list(row) for row in df.itertuples(index=False)]
print("使用 itertuples 优化的结果:")
print(res)
2026年深度指南:生产环境中的复杂场景与陷阱
在我们最近的项目中,随着数据量的爆炸式增长和对系统稳定性的要求提高,简单的转换往往是不够的。让我们深入探讨几个生产环境中的关键问题,这些是在基础教程中很少提及,但却是构建健壮系统的核心。
场景一:处理包含混合类型的数据与 Pandas 3.0 兼容性
如果你的 DataFrame 中某一列是字符串,另一列是整数,直接使用 INLINECODE7bf65315 通常没问题,因为 Python 列表可以容纳混合类型。但是,如果你尝试将其转换为 NumPy 数组而不指定 INLINECODEb19b3fa4,可能会导致数据类型被强制统一(例如所有东西变成字符串)。
在 Pandas 3.0(2026年标准版本)中,对数据类型的检查变得更加严格。解决方法是在转换前确保数据一致性,或者在 INLINECODE13a769c1 中显式指定 INLINECODE56fd6dc4。这在处理从 CSV 读取的脏数据时尤为重要。对于 AI 工程师来说,干净的数据类型转换是防止模型推理时出现类型错误的“左移”实践。
场景二:处理 NaN(缺失值)与 JSON 序列化陷阱
这是一个非常棘手的问题。在 Pandas 中,缺失值是 INLINECODE37271ee6(Float 类型),但在 Python 列表中,我们通常更倾向于看到 INLINECODEad033ed3。
如果你直接使用 INLINECODEc77d685a,INLINECODE38ec32b3 会被保留为 INLINECODEfc933a25。这可能会导致后续的 JSON 序列化失败(因为标准的 JSON 不支持 INLINECODEf8e96a64,它不是有效的 JSON)。如果你正在构建一个后端服务,这直接会导致 API 500 错误。
解决方案:
import pandas as pd
import numpy as np
import json
# 包含 NaN 的 DataFrame
df = pd.DataFrame({‘A‘: [1, np.nan], ‘B‘: [‘x‘, ‘y‘]})
# 错误示范:直接转换会导致 JSON 序列化报错
# res = df.values.tolist()
# json.dumps(res) # TypeError: Object of type float is not JSON serializable
# 正确的生产级解决方案:
# 1. 使用 to_dict(‘records‘),它会自动处理 NaN -> null
data_for_api = df.to_dict(orient=‘records‘)
print(json.dumps(data_for_api))
# 2. 或者在使用 NumPy 方法前,显式替换
df_clean = df.astype(object).where(pd.notnull(df), None)
res = df_clean.values.tolist()
print(res)
# 输出:[[1.0, ‘x‘], [None, ‘y‘]]
2026 开发工作流:让 AI 成为你的搭档
现在,让我们换个角度。在 2026 年,我们如何使用像 Cursor 或 GitHub Copilot 这样的 AI 工具来编写、优化并审查这段代码呢?这就是我们所说的“Vibe Coding”(氛围编程)。
AI 辅助的性能基准测试
当我们面对一个大型 DataFrame(例如 1000 万行)时,我们需要选择最快的方法。在以前,我们需要写一端 timeit 代码。现在,我们可以直接与 AI 结对编程来验证。
假设我们在 Cursor 编辑器中,我们可以这样要求 AI:“比较 INLINECODE1a889939 和 INLINECODE88afe7c4 在处理 500 万行数据时的内存消耗和速度差异。”
AI 会不仅生成测试代码,还会给出基于 2026 硬件环境的建议:
-
itertuples():内存占用最低,速度极快,适合循环处理。在边缘计算设备(如 Raspberry Pi 或 Jetson)上处理传感器数据流时,这是首选。 - INLINECODEf6bf215d / INLINECODE6009295d:速度非常快,适合需要一次性获取所有数据的场景,但会有内存峰值。
-
to_dict(orient=‘records‘):最慢,因为要构建大量的字典对象和哈希表,但提供了最佳的数据语义。
使用 LLM 进行代码审查
在提交代码前,我们可以将转换逻辑片段发送给 LLM,并提示:“作为一名高级 Python 工程师,审查这段 Pandas 转换代码是否存在潜在的内存泄漏或性能瓶颈。”
AI 可能会指出,如果你在循环中不断进行列表追加而不是使用预分配或列表推导式,可能会导致不必要的内存重分配。这种即时反馈循环是现代开发流程的核心。
实战案例:AI Agent 上下文构建
让我们思考一个具体的前沿场景:RAG(检索增强生成)系统。
假设我们正在构建一个 AI Agent,它需要读取用户的历史交易 DataFrame,并将其作为上下文传递给 LLM 以生成财务建议。
import pandas as pd
def prepare_context_for_llm(df: pd.DataFrame) -> str:
"""
将 DataFrame 转换为 AI 友好的文本上下文。
使用字典列表可以保留语义,让 LLM 更好地理解字段。
"""
# 我们选择 to_dict(‘records‘) 而不是 tolist()
# 因为 [{‘Amount‘: 100, ‘Type‘: ‘Food‘}] 比 [100, ‘Food‘] 对 AI 来说更清晰
records = df.to_dict(orient=‘records‘)
# 将其转换为结构化的 JSON 字符串作为 Prompt 的一部分
# 这是一种 Prompt Engineering 技术:结构化上下文
return str(records)
df_transactions = pd.DataFrame({
‘Date‘: [‘2026-05-01‘, ‘2026-05-02‘],
‘Amount‘: [-150.00, 2000.00],
‘Category‘: [‘Groceries‘, ‘Salary‘]
})
context = prepare_context_for_llm(df_transactions)
print(f"提供给 LLM 的上下文:
{context}")
在这个案例中,如果我们使用了无结构的列表,LLM 可能会混淆数字和类别的含义。结构化列表(字典列表)不仅易于人类调试,更符合 LLM 的训练数据分布,从而提高了推理的准确性。
总结与展望
在这篇文章中,我们深入探讨了如何将 Pandas DataFrame 的行转换为列表。这是一个看似简单,实则包含多种最佳实践的话题。
- 如果你追求极致的速度和原始数据,请使用
df.to_numpy().tolist()。 - 如果你需要结构化的数据以便于 API 返回或 LLM 上下文构建,请使用
df.to_dict(‘records‘)。 - 如果你正在处理海量数据或在边缘设备上运行,请务必考虑使用
itertuples()来节省内存。
2026 年的编程已经不仅仅是关于语法,更是关于选择正确的工具以适应 AI 原生架构。希望这些技巧能帮助你在数据处理的道路上更加得心应手。下次当你面对一个 DataFrame 需要转换时,你可以自信地选择最适合当前业务场景的那种方法,并善用你的 AI 副驾驶来验证你的选择。