Decimal模块在Streamlit中数据显示异常问题求助
解决Streamlit中Decimal类型DataFrame列显示异常问题
问题背景
为解决浮点数精度问题(例如Python中0.1 + 0.2 == 0.3结果为False),我用Decimal模块处理DataFrame中的欧元货币列,确保精确运算(Decimal('0.1')+Decimal('0.2') == Decimal('0.3')结果为True)。
在Jupyter Notebook中运行以下代码,输出完全正常:
d = {'name': ["A", "B", "C"], 'amount': [0.1, 0.2, 0.3]} df = pd.DataFrame(data=d) print("Original") print(df) print("Original_Test") print(df['amount'][0]+df['amount'][1]==df['amount'][2]) for col in df: if "amount" in col or "eur" in col: df[col] = list(df[col]) df[col] = [Decimal(str(round(i,2))) for i in df[col]] print("Decimal Layout") print(df) print("Decimal Layout_Test") print(df['amount'][0]+df['amount'][1]==df['amount'][2])
但适配到Streamlit后,尽管运算结果显示为True,amount列却错误显示为[1, 2, 3]而非预期的[0.1, 0.2, 0.3],Streamlit代码如下:
d = {'name': ["A", "B", "C"], 'amount': [0.1, 0.2, 0.3]} df = pd.DataFrame(data=d) st.write(df) for col in df: if "amount" in col or "eur" in col: df[col] = list(df[col]) df[col] = [Decimal(str(round(i,2))) for i in df[col]] st.write(df) st.write(df['amount'][0]+df['amount'][1]==df['amount'][2])
问题原因
Streamlit的st.write()渲染DataFrame时,对Python标准库的Decimal类型处理逻辑与Jupyter不同。Jupyter会直接输出Decimal的字符串表示,而Streamlit在尝试解析Decimal类型时出现异常,导致只显示了数值的整数部分(如Decimal('0.1')被错误解析为1)。
解决方案
以下三种方法可解决该显示问题,同时保留Decimal的精确运算能力:
方法一:显示前将Decimal列转为格式化字符串
复制DataFrame用于显示,把Decimal列转换为带两位小数的字符串,既保证运算精度,又能正确显示格式:
import streamlit as st import pandas as pd from decimal import Decimal d = {'name': ["A", "B", "C"], 'amount': [0.1, 0.2, 0.3]} df = pd.DataFrame(data=d) st.write("原始DataFrame") st.write(df) # 用Decimal处理列,保证运算精度 for col in df: if "amount" in col or "eur" in col: df[col] = [Decimal(str(round(i,2))) for i in df[col]] # 复制DataFrame并格式化显示列 df_display = df.copy() df_display['amount'] = df_display['amount'].apply(lambda x: f"{x:.2f}") st.write("处理后的DataFrame") st.write(df_display) # 验证运算精度 st.write("运算精度验证结果:", df['amount'][0]+df['amount'][1]==df['amount'][2])
方法二:使用Pandas Styler格式化显示
利用Pandas的Styler工具直接格式化Decimal列的显示样式,无需转换数据类型:
import streamlit as st import pandas as pd from decimal import Decimal d = {'name': ["A", "B", "C"], 'amount': [0.1, 0.2, 0.3]} df = pd.DataFrame(data=d) st.write("原始DataFrame") st.write(df) # 用Decimal处理列 for col in df: if "amount" in col or "eur" in col: df[col] = [Decimal(str(round(i,2))) for i in df[col]] # 用Styler格式化显示 styler = df.style.format({'amount': lambda x: f"{x:.2f}"}) st.write("处理后的DataFrame") st.write(styler) st.write("运算精度验证结果:", df['amount'][0]+df['amount'][1]==df['amount'][2])
方法三:使用Pandas的Decimal数据类型
若你的Pandas版本支持(通常需1.3.0及以上),可指定列的dtype为'decimal',让Streamlit正确识别并渲染:
import streamlit as st import pandas as pd from decimal import Decimal d = {'name': ["A", "B", "C"], 'amount': [0.1, 0.2, 0.3]} df = pd.DataFrame(data=d) st.write("原始DataFrame") st.write(df) # 转换为Pandas支持的Decimal dtype for col in df: if "amount" in col or "eur" in col: df[col] = pd.Series([Decimal(str(round(i,2))) for i in df[col]], dtype='decimal') st.write("处理后的DataFrame") st.write(df) st.write("运算精度验证结果:", df['amount'][0]+df['amount'][1]==df['amount'][2])
内容的提问来源于stack exchange,提问作者Andrea Farrugia
相关产品推荐
相关产品推荐

