You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Polars读取Excel文件时,将数值列转换为String(Utf8)类型如何保留所有小数位数

使用Polars读取Excel文件时,将数值列转换为String(Utf8)类型如何保留所有小数位数

我完全理解你的困扰——前端明明显示的是12位小数的精确数值,后端用Polars读取时,哪怕指定了列类型为Utf8,结果还是被截断了。这背后的原因其实很关键:

Polars默认依赖的Excel读取引擎(比如openpyxl)会先把Excel的数值单元格解析为Python浮点数,而浮点数本身的精度限制会导致小数位丢失,之后再转成字符串就已经是截断后的结果了——哪怕你提前用schema_overrides指定了Utf8类型也没用,因为精度丢失发生在Polars处理之前。

下面给你提供两种解决方案,推荐第一种,能彻底解决问题:

方案一:直接读取Excel单元格的显示文本(推荐)

要完全保留前端看到的精确小数位数,我们需要绕过浮点数解析,直接读取Excel单元格的显示文本内容(也就是前端xlsx库读到的那个原始字符串)。可以用openpyxl直接读取单元格文本,再构建Polars DataFrame:

  1. 确保安装了openpyxl(Polars读取xlsx文件默认依赖它)
pip install openpyxl
  1. 修改后端的parse_user_data函数:
from io import BytesIO
from openpyxl import load_workbook
import polars as pl

def parse_user_data(contents: bytes):
    buffer = BytesIO(contents)
    
    # 用openpyxl加载Excel文件,保留单元格对象而非直接取值
    wb = load_workbook(buffer, data_only=True)
    sheet = wb.active  # 取第一个工作表,和你之前pl.read_excel的逻辑一致
    
    # 遍历所有行,读取每个单元格的显示文本(和前端看到的完全一致)
    rows_data = []
    for row in sheet.iter_rows(values_only=False):
        # 把每个单元格的显示文本转成字符串,空单元格设为None
        row_str = [cell.text.strip() if cell.value is not None else None for cell in row]
        rows_data.append(row_str)
    
    # 构建Polars DataFrame,列名规则和pl.read_excel(has_header=False)一致:column_0, column_1...
    df_raw = pl.DataFrame(
        rows_data,
        schema=[f"column_{i}" for i in range(len(rows_data[0]))] if rows_data else []
    )
    
    # 处理column_5:转小写,和你之前的逻辑保持一致
    df_raw = df_raw.with_columns(pl.col("column_5").str.to_lowercase())
    
    print(df_raw.select(pl.col("column_5")).head(20))

这个方法的核心是cell.text——它会直接返回Excel单元格显示的原始文本内容,也就是前端看到的12位小数的精确字符串,完全绕过了浮点数解析的精度丢失问题。生成的Polars DataFrame列类型默认是Utf8,自然能保留所有小数位。

方案二:尝试修改Polars读取的引擎参数(不推荐,稳定性差)

如果你想坚持用pl.read_excel,可以尝试通过engine_kwargs传递参数给openpyxl,但这个方法依赖引擎的具体实现,稳定性不如方案一:

def parse_user_data(contents: bytes):
    buffer = BytesIO(contents)
    
    df_raw = pl.read_excel(
        buffer,
        has_header=False,
        engine="openpyxl",
        # 传递给openpyxl的参数,尝试保留原始值的字符串表示
        engine_kwargs={"data_only": True},
        schema_overrides={"column_5": pl.Utf8},
    ).with_columns(pl.col(pl.Utf8).str.to_lowercase())
    
    print(df_raw.select(pl.col("column_5")).head(20))

不过这个方案大概率还是会遇到截断问题,因为openpyxl本身读取数值单元格时还是会先转成浮点数,所以更推荐方案一。

火山引擎 最新活动