df.values.tolist()将DataFrame转为按列顺序排列的嵌套列表,不保留列名,不处理NaN,性能优于to_dict('records')但依赖列顺序稳定性。

直接用 df.values.tolist() 会丢掉列名,且顺序依赖 df.columns 排序
这个方法本质是把 DataFrame 底层的 NumPy 数组转成 Python 列表,每行一个子列表,元素顺序严格按 df.columns 当前顺序来。不是按你定义时的顺序,也不是按原始读取顺序——如果中间调过 reindex()、drop() 或改过列名,顺序就变了。
常见错误现象:df.values.tolist() 返回的每行数据和你用 df.to_dict('records') 看到的字段对不上,尤其在重排过列或删过列之后。
- 如果只要纯数据、不关心列名,且确认列顺序稳定,它最快
- 如果后续要靠索引位置取值(比如
row[2]表示“年龄”),千万别依赖它——列顺序一变就崩 - 它不处理 NaN:
np.nan会原样变成float('nan'),JSON 序列化时报错
转换特定列推荐用 df[['col1', 'col2']].values.tolist()
比先切片再 .values.tolist() 更安全,因为明确锁定了列集合和顺序。不会受 df.columns 全局变化影响,也避免手误写错列名后返回空或报错(KeyError 比静默错位好)。
使用场景:导出报表、拼接 SQL INSERT 值、喂给 requests.post 的 json= 参数等需要结构确定的场合。
- 列名必须存在,否则抛
KeyError: "['xxx'] not in index" - 支持重复列名:
df[['a', 'a']].values.tolist()会返回两列相同数据 - 性能上比
df.to_dict('records')高约 3–5 倍(百万行级测试),因为绕过了字典构造开销
to_list() 是 Series 方法,DataFrame 上不能直接用
新手常输 df['col'].to_list() 成功,就以为 df.to_list() 也存在——实际会报 AttributeError: 'DataFrame' object has no attribute 'to_list'。这是 Pandas 明确区分的设计:列表化行为只对一维结构(Series、Index)开放。
如果你看到别人写了 df.to_list() 能跑,大概率是用了旧版 Pandas(df.values.tolist()。
- 正确写法只有:
df['col'].to_list()(单列)、df.values.tolist()(全表)、df.values[:, [0,2]].tolist()(指定列位置) -
to_list()比list(series)快,且自动把pd.NA转成None(list()保留pd.NA)
NaN 和 pd.NA 处理不一致,转列表前最好显式填充
df.values.tolist() 对 np.nan 生成 float('nan'),对 pd.NA(字符串/布尔扩展类型)直接报 ValueError: Unable to convert <na> to native types</na>。这不是 bug,是底层类型系统限制。
容易踩的坑:读 CSV 时加了 dtype={'col': 'string'},结果该列含空值就变成 pd.NA,一调 .values.tolist() 就崩。
- 稳妥做法:
df.fillna('').values.tolist()(填空字符串)或df.replace({pd.NA: None}).values.tolist() - 如果列类型混合(比如有 int 和 NaN),
df.astype(object).values.tolist()可兜底,但会损失数值运算能力 - 别用
df.dropna()代替填充——除非你真想丢数据

















