You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Python xlwings写入pandas df到Excel时启用skip_blanks跳过空值

xlwings写入带NaN的DataFrame时跳过空值保留Excel原有内容

问题描述

我的Python脚本生成了一个包含若干NaN值的pandas DataFrame,样例数据如下:

A         B         C         D
0.351741  NaN       0.238705  NaN     
0.950817  0.665594  0.671151  NaN     
NaN       0.442725  0.658816  NaN     
0.155604  0.567044  NaN       0.666576
NaN       0.751562  NaN       0.597252
0.577770  NaN       NaN       0.123392

核心需求:使用xlwings将该DataFrame写入Excel工作表时,跳过值为NaN的单元格,保留Excel中对应位置的原有内容——待保留的内容可能是实时Excel公式、已存储数值,甚至是空单元格。

目标Excel区域原有内容如下:

A         B         C         D
Excel A1  Excel B1  Excel C1  Excel D1 
Excel A2  Excel B2  Excel C2  Excel D2 
Excel A3  Excel B3  Excel C3  Excel D3 
Excel A4  Excel B4  Excel C4  Excel D4
Excel A5  Excel B5  Excel C5  Excel D5
Excel A6  Excel B6  Excel C6  Excel D6

写入后期望得到的输出结果为:

A         B         C         D
0.351741  Excel B1  0.238705  Excel D1
0.950817  0.665594  0.671151  Excel D2
Excel A3  0.442725  0.658816  Excel D3
0.155604  0.567044  Excel C4  0.666576
Excel A5  0.751562  Excel C5  0.597252
0.577770  Excel B6  Excel C6  0.123392

常规写入代码如下:

r = 'A1:D6'
sht.range(r).options(index=False, header=False).value = df

该写法的问题是NaN值会将对应Excel单元格覆盖为空值,原有内容丢失,错误写入结果如下:

A         B         C         D
0.351741  BLANK     0.238705  BLANK   
0.950817  0.665594  0.671151  BLANK   
BLANK     0.442725  0.658816  BLANK   
0.155604  0.567044  BLANK     0.666576
BLANK     0.751562  BLANK     0.597252
0.577770  BLANK     BLANK     0.123392

查阅xlwings官方文档与源码后发现,skip_blanks参数目前仅在paste()函数中实现,默认值为False。当前找到的临时方案需要借助临时工作表,代码如下:

tmp_sht.range(r).options(index=False, header=False).value = df 
tmp_sht.range(r).copy(destination=None)
sht.range(r).paste(paste='values', skip_blanks=True) 

该方案需要额外创建临时工作表,期望能实现直接写入时跳过空值,类似如下写法:

sht.range(r).options(index=False, header=False, skip_blanks=True).value = df

实现方案

不需要等待官方为options()新增skip_blanks参数,也不需要使用临时工作表,以下两种方案可直接实现需求:

  • 方案1:逐非空单元格写入(适合小数据量场景)
    遍历DataFrame所有值,仅对非NaN的对应单元格赋值,完全不触碰NaN位置的原有内容:

    import pandas as pd
    
    r = 'A1:D6'
    # 获取写入区域的起始坐标
    start_row = sht.range(r).row
    start_col = sht.range(r).column
    
    # 遍历写入非空值
    for row_idx in range(df.shape[0]):
        for col_idx in range(df.shape[1]):
            cell_val = df.iat[row_idx, col_idx]
            if not pd.isna(cell_val):
                sht.cells(start_row + row_idx, start_col + col_idx).value = cell_val
    
    • 优势:逻辑简单,完整保留原有单元格的公式、格式,不操作剪贴板
    • 劣势:逐单元格调用COM接口,数据量较大时写入速度慢
  • 方案2:掩码合并后批量写入(适合大数据量场景,性能最优)
    先读取目标区域原有内容,用原有内容填充DataFrame中的NaN位置,再一次性批量写入,写入性能和原生直接写入几乎一致:

    import pandas as pd
    import numpy as np
    
    r = 'A1:D6'
    target_range = sht.range(r)
    # 读取目标区域原有内容:如果要保留公式,加value=False参数读取公式本身
    original_data = np.array(
        target_range.options(ndim=2, value=False).value,
        dtype=object
    )
    # 合并数据:用原有内容填充df中的NaN
    df_data = df.to_numpy(dtype=object)
    nan_mask = pd.isna(df_data)
    df_data[nan_mask] = original_data[nan_mask]
    # 一次性批量写入
    target_range.options(index=False, header=False).value = df_data
    
    • 优势:批量写入性能极高,不需要临时表、不占用剪贴板,可选择保留原有公式或计算结果
    • 注意:需保证DataFrame的形状和目标写入区域的形状完全一致

截止xlwings 0.31.x稳定版本,Range.options()暂未内置写入时的skip_blanks参数,上述两种方案可完全替代临时工作表方案。

内容的提问来源于stack exchange,提问作者Romain Capron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 13:27:22