关于python小数点精度控制的问题

本文探讨了Python中浮点数的精度问题,包括单精度和双精度的区别,以及如何使用round()函数和decimal模块来控制小数点后的位数。提供了实现不同精度需求的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于python小数点精度控制的问题

基础

浮点数是用机器上浮点数的本机双精度(64 bit)表示的。提供大约17位的精度和范围从-308到308的指数。和C语言里面的double类型相同。Python不支持32bit的单精度浮点数。如果程序需要精确控制区间和数字精度,可以考虑使用numpy扩展库。

Python 3.X对于浮点数默认的是提供17位数字的精度。

关于单精度和双精度的通俗解释:

单精度型和双精度型,其类型说明符为float 单精度说明符,double 双精度说明符。在Turbo C中单精度型占4个字节(32位)内存空间,其数值范围为3.4E-38~3.4E+38,只能提供七位有效数字。双精度型占8 个字节(64位)内存空间,其数值范围为1.7E-308~1.7E+308,可提供16位有效数字。

要求较小的精度

将精度高的浮点数转换成精度低的浮点数

1,round()内置方法

在这里插入图片描述
round()如果只有一个数作为参数,不指定位数的时候,返回的是一个整数,而且是最靠近的整数(这点上类似四舍五入)。但是当出现.5的时候,两边的距离都一样,round()取靠近的偶数,这就是为什么round(2.5) = 2。当指定取舍的小数点位数的时候,一般情况也是使用四舍五入的规则,但是碰到.5的这样情况,如果要取舍的位数前的小树是奇数,则直接舍弃,如果偶数这向上取舍。看下面的示例:
在这里插入图片描述

2,使用格式化

效果和round()是一样的。
在这里插入图片描述

要求超过17位的精度分析

python默认的是17位小数的精度,但是这里有一个问题,就是当我们的计算需要使用更高的精度(超过17位小数)的时候该怎么做呢?

1,使用格式化(不推荐)

在这里插入图片描述
可以显示,但是不准确,后面的数字往往没有意义。
2,高精度使用decimal模块,配合getcontext
在这里插入图片描述
默认的context的精度是28位,可以设置为50位甚至更高,都可以。这样在分析复杂的浮点数的时候,可以有更高的自己可以控制的精度。其实可以留意下context里面的这rounding=ROUND_HALF_EVEN 参数。ROUND_HALF_EVEN, 当half的时候,靠近even.

关于小数和取整

既然说到小数,就必然要说到整数。一般取整会用到这些函数:

1,round()

这个不说了,前面已经讲过了。一定要注意它不是简单的四舍五入,而是ROUND_HALF_EVEN的策略

2,math模块的ceil(x)

取大于或者等于x的最小整数。

3,math模块的floor(x)

取小于或者等于x的最大整数。
在这里插入图片描述
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

居中的图片: Alt

居中并且带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。1

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.2.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件或者.html文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. 注脚的解释 ↩︎

<think>我们面对的问题是:使用Python的pandas库解析Excel文件并将数据存储到数据库时,坐标值的小数点精度丢失。 原因分析:坐标通常是浮点数,而浮点数在计算机中存储和计算时可能存在精度问题。另外,在数据读取和写入过程中,可能由于数据类型转换或数据库字段类型设置导致精度丢失。 解决方案: 1. 确保在读取Excel文件时,pandas能够正确识别浮点数列,并保持足够的精度。 2. 在将数据写入数据库时,确保数据库表的字段类型能够存储高精度的浮点数(例如,使用DECIMAL或DOUBLE类型,具体取决于数据库)。 3. 在pandas和数据库交互的过程中,注意数据类型转换可能带来的精度损失。 具体步骤: 步骤1:使用pandas读取Excel文件时指定数据类型 在读取Excel文件时,可以通过`dtype`参数指定列的数据类型,或者使用`converters`参数来确保精度。但是,对于浮点数,pandas默认使用float64,其精度已经相当高(大约15-17位小数),通常能够满足坐标精度的要求。因此,问题可能不是出在读取阶段,而是写入阶段。 步骤2:检查pandas中DataFrame的数据类型 在读取数据后,打印DataFrame的数据类型,确保坐标列是float64类型。 步骤3:在写入数据库时处理精度 当我们使用to_sql方法写入数据库时,需要确保数据库表的字段类型能够存储高精度的浮点数。例如,在MySQL中,我们可以使用DOUBLE或DECIMAL类型,并指定精度。在SQLite中,REAL类型可以存储浮点数。 步骤4:使用SQLAlchemy进行数据类型映射 如果我们使用SQLAlchemy作为ORM工具,可以在定义表结构时指定列的数据类型和精度。例如,使用`DOUBLE(precision=15)`或`DECIMAL(precision=15, scale=10)`(根据需求调整精度小数位数)。 步骤5:在写入时使用chunksize参数(可选,大数据量时) 如果数据量很大,可以考虑分块写入,但这与精度问题无关。 步骤6:在写入数据库之前,确保DataFrame中的浮点数没有被意外转换为低精度类型。 示例代码: 假设我们有一个Excel文件,其中包含两列坐标:'longitude'和'latitude'。 1. 读取Excel文件: ```python import pandas as pd df = pd.read_excel('data.xlsx') # 查看数据类型 print(df.dtypes) # 如果发现坐标列不是float64,可以转换 # df['longitude'] = df['longitude'].astype(float) # df['latitude'] = df['latitude'].astype(float) ``` 2. 创建数据库表时指定精度(以MySQL为例,使用SQLAlchemy): ```python from sqlalchemy import create_engine, Column, Float, String from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Location(Base): __tablename__ = 'locations' id = Column(String, primary_key=True) longitude = Column(Float(precision=15)) # 或者使用DECIMAL类型 latitude = Column(Float(precision=15)) # 创建表 engine = create_engine('mysql+pymysql://user:password@localhost/db_name') Base.metadata.create_all(engine) ``` 3. 使用pandas的to_sql方法写入数据: ```python # 如果使用SQLAlchemy,可以这样写 from sqlalchemy import create_engine engine = create_engine('mysql+pymysql://user:password@localhost/db_name') # 写入数据,注意如果表已存在,可以使用if_exists参数 df.to_sql('locations', engine, if_exists='append', index=False) ``` 但是,如果我们在写入时没有使用SQLAlchemy的Table结构,而是直接使用to_sql,那么pandas会尝试根据数据类型推断数据库字段类型。对于浮点数,pandas会映射为FLOAT类型,而FLOAT类型在某些数据库中可能精度不够(例如MySQL的FLOAT只有4字节,而DOUBLE有8字节)。因此,我们需要在to_sql中指定数据类型。 4. 在to_sql中指定数据类型(使用dtype参数): ```python from sqlalchemy.types import FLOAT # 定义每列的数据类型 dtype = { 'longitude': FLOAT(precision=15), 'latitude': FLOAT(precision=15) } df.to_sql('locations', engine, if_exists='append', index=False, dtype=dtype) ``` 注意:如果数据库表已经存在,那么to_sql的dtype参数会被忽略。因此,我们需要确保在创建表时就指定好精度。 5. 使用DECIMAL类型(如果要求更高精度): 在数据库中,DECIMAL类型可以精确存储数字。在SQLAlchemy中,我们可以使用`DECIMAL`类型,并指定精度小数位数。 ```python from sqlalchemy import DECIMAL dtype = { 'longitude': DECIMAL(precision=20, scale=15), 'latitude': DECIMAL(precision=20, scale=15) } ``` 然后,在创建表或者使用to_sql时指定这个dtype。 总结:精度丢失问题通常可以通过在数据库中使用更高精度的数据类型(如DOUBLE或DECIMAL)并在pandas写入时明确指定列的数据类型来解决。 另外,如果问题仍然存在,可以在写入数据库前将DataFrame中的浮点数转换为字符串,保留足够的位数,然后再写入数据库,但这可能会增加存储和查询的复杂性。 因此,推荐的做法是: - 在数据库表中使用DECIMAL类型,并指定足够的精度(例如,经度纬度可能需要小数点后10位以上)。 - 在pandas的to_sql方法中,通过dtype参数指定列的数据类型为DECIMAL(或DOUBLE)并设置精度。 这样就能确保坐标值在存储到数据库时不会丢失精度。 相关问题: 1. 如何在使用pandas读取Excel文件时指定列的数据类型? 2. 在SQLAlchemy中如何定义DECIMAL类型的字段? 3. 除了数据库存储,还有哪些方法可以避免浮点数精度丢失? 4. 在Python中如何高精度地处理浮点数运算?</think>### Python pandas 读取Excel存入数据库时坐标精度丢失的解决方法 当使用 pandas 读取 Excel 文件并将坐标数据存入数据库时出现精度丢失问题,通常由以下原因导致: 1. **Excel浮点数存储限制**:Excel 默认精度为15位小数 2. **pandas数据类型转换**:读取时自动推断类型可能降低精度 3. **数据库字段类型限制**:如使用`FLOAT`类型会丢失精度 #### 解决方案(分步实施): --- ### 步骤1:读取Excel时指定高精度数据类型 在读取Excel时显式指定坐标列为高精度类型: ```python import pandas as pd # 指定坐标列为decimal.Decimal类型 df = pd.read_excel('data.xlsx', dtype={'longitude': 'float64', 'latitude': 'float64'}) # 或使用decimal提高精度 from decimal import Decimal converters = { 'longitude': lambda x: Decimal(str(x)), 'latitude': lambda x: Decimal(str(x)) } df = pd.read_excel('data.xlsx', converters=converters) ``` --- ### 步骤2:数据库表结构优化 创建数据库表时使用高精度字段类型: ```sql -- MySQL示例 CREATE TABLE locations ( id INT PRIMARY KEY AUTO_INCREMENT, longitude DECIMAL(18, 15), -- 18位总长度,15位小数 latitude DECIMAL(18, 15) ); -- PostgreSQL示例 CREATE TABLE locations ( id SERIAL PRIMARY KEY, longitude NUMERIC(18, 15), latitude NUMERIC(18, 15) ); ``` --- ### 步骤3:使用SQLAlchemy精确写入 通过SQLAlchemy控制数据类型映射: ```python from sqlalchemy import create_engine, DECIMAL from sqlalchemy.types import TypeDecorator # 自定义高精度类型 class HighPrecision(TypeDecorator): impl = DECIMAL(18, 15) # 创建数据库连接 engine = create_engine('mysql+pymysql://user:password@localhost/db_name') # 指定数据类型映射 dtype = { 'longitude': HighPrecision, 'latitude': HighPrecision } # 写入数据库 df.to_sql('locations', engine, if_exists='append', index=False, dtype=dtype) ``` --- ### 步骤4:验证精度(关键步骤) 写入前后进行数据验证: ```python # 读取后立即检查精度 print(df['longitude'].iloc[0]) # 查看原始值 # 从数据库回读验证 query = "SELECT longitude FROM locations LIMIT 1" db_value = pd.read_sql(query, engine).iloc[0,0] print(f"数据库存储值: {db_value}") ``` --- ### 补充说明 1. **避免使用`FLOAT`类型**:在数据库中始终使用`DECIMAL`/`NUMERIC`代替`FLOAT` 2. **Excel预处理**:在Excel中将坐标列设置为"数字"格式,小数位数设至最大 3. **中间格式转换**:可先导出为CSV保留精度,再导入数据库[^1] ```python # 临时保存为高精度CSV df.to_csv('temp_coords.csv', index=False, float_format='%.15f') ``` > **关键点**:精度丢失常发生在数据类型转换环节,需在pandas读取阶段、内存处理阶段和数据库写入阶段均保持高精度数据类型一致[^4]。 --- ### 相关问题 1. 如何在pandas中处理超过15位有效数字的坐标数据? 2. MySQL的DECIMAL和FLOAT类型在存储地理坐标时有何区别? 3. 使用SQLAlchemy时如何自定义字段类型映射? 4. 除了数据库存储,还有哪些方法可以保持地理坐标的原始精度? 5. 如何批量验证数据库中大量坐标数据的精度完整性? [^1]: 引用自CSV保存数据库方法 [^4]: 引用自pandas读取文件参数说明
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值