如何在 Pint 中定义和使用百分比

9
我目前正在使用Pint来处理单位和单位转换。这对于在Pint中已经定义的单位似乎很有效,例如:
>>> import pint
>>> ureg = pint.UnitRegistry()
>>> Q = ureg.Quantity
>>> a = Q(5, 'm/s')
>>> a
<Quantity(5, 'meter / second')>
>>> a.to('ft/s')
<Quantity(16.404199475065617, 'foot / second')>

我尝试定义我的自定义单位,代表百分比。就单位转换而言,百分比只是一个无量纲分数的一百倍,这也是我定义它的方式。
>>> ureg.define('percent = dimensionless * 100 = pct')
>>> a = Q(5, 'pct')
>>> a
<Quantity(5, 'percent')>

然而,我似乎无法在分数('dimensionless')和百分数('pct')之间进行转换。
>>> a.to('dimensionless')
Traceback (most recent call last):
  File "<pyshell#31>", line 1, in <module>
    a.to('dimensionless')
  File "C:\Python35\python-3.5.1.amd64\lib\site-packages\pint\quantity.py", line 263, in to
    magnitude = self._convert_magnitude_not_inplace(other, *contexts, **ctx_kwargs)
  File "C:\Python35\python-3.5.1.amd64\lib\site-packages\pint\quantity.py", line 231, in _convert_magnitude_not_inplace
    return self._REGISTRY.convert(self._magnitude, self._units, other)
  File "C:\Python35\python-3.5.1.amd64\lib\site-packages\pint\unit.py", line 1026, in convert
    return self._convert(value, src, dst, inplace)
  File "C:\Python35\python-3.5.1.amd64\lib\site-packages\pint\unit.py", line 1042, in _convert
    src_dim = self._get_dimensionality(src)
  File "C:\Python35\python-3.5.1.amd64\lib\site-packages\pint\unit.py", line 813, in _get_dimensionality
    self._get_dimensionality_recurse(input_units, 1.0, accumulator)
  File "C:\Python35\python-3.5.1.amd64\lib\site-packages\pint\unit.py", line 837, in _get_dimensionality_recurse
    self._get_dimensionality_recurse(reg.reference, exp2, accumulator)
  File "C:\Python35\python-3.5.1.amd64\lib\site-packages\pint\unit.py", line 835, in _get_dimensionality_recurse
    reg = self._units[self.get_name(key)]
KeyError: ''

我想要做的是能够在“0.73”和“73%”之间进行转换。我该如何定义并使用这样的单位?

4个回答

8

看来GitHub问题hgrecco/pint#185涵盖了你所描述的情况。

使用该问题中讨论的解决方法对我有用,我使用Pint-0.7.2

from pint.unit import ScaleConverter
from pint.unit import UnitDefinition
import pint

ureg = pint.UnitRegistry()
Q = ureg.Quantity

ureg.define(UnitDefinition('percent', 'pct', (), ScaleConverter(1 / 100.0)))
a = Q(5, 'pct')

print a
print a.to('dimensionless')

输出:

5 percent
0.05 dimensionless

2
我使用了 from pint.converters import ScaleConverter - nowox
4
从 pint 0.8 开始,它们似乎已经移除了 pint.unit.ScaleConverter,但 pint.converters.ScaleConverter 仍然可用,因此解决方案的其余部分仍然有效。 - Cory Kramer
在 pint 0.9 中,可以通过首先定义一个单位 ureg.define('fraction = []'),然后使用这个单位来定义缩放版本,而不是直接使用 dimensionless。有关详细信息,请参见我的答案 - GeoMatt22

7

我曾经遇到了同样的问题,后来想出了一个简单的解决方案,看起来效果不错。

import pint

ureg = pint.UnitRegistry()
ureg.define('fraction = [] = frac')
ureg.define('percent = 1e-2 frac = pct')
ureg.define('ppm = 1e-6 fraction')

print(ureg('100 pct').to('dimensionless'))
print(ureg('0.5 dimensionless').to('pct'))
print(ureg('pct').to('ppm'))
print(ureg('1e4 ppm').to('pct'))

输出:

1.0 dimensionless
50.0 percent
10000.0 ppm
0.9999999999999999 percent

(Note: 最后一行存在轻微的舍入误差。)
我从默认的单位字典中获取了语法,其中基本单位的定义如下:
# reference
gram = [mass] = g  # dimensional
radian = [] = rad  # dimensionless

两种解决方案之间存在一点差异:你的解决方案在调用 to_base_units() 时解析为“分数”,而另一种解决方案解析为“无量纲”。 - Morwenn

2
在0.22版本中,百分比功能已经内置支持:
以下操作会按预期执行:
import pint
ureg = pint.UnitRegistry()
pint.__version__  # 0.22
ureg.Quantity(1,'%')  # 1 percent
ureg.Quantity(1,'').to('percent')  # 100.0 percent
ureg.Quantity(100,'percent').to('')  # 1.0 dimensionless

然而,.to('%') 仍然存在 问题


0

在 pint ≥0.16 中,尝试

ureg.define('percent = 1 / 100 = %')

或者

ureg.define('percent = 0.01 = %')

如果你想使用不仅仅是ureg('1 percent'),还有ureg('1 %'),那么就需要添加一个预处理器

ureg = pint.UnitRegistry(preprocessors=[
     lambda s: s.replace('%', ' percent '),
])

感谢GitHub上这条评论的贡献者提供了预处理器代码示例。


当我执行这个操作时,x = ureg('1 %').to('') 的结果符合预期(x<Quantity(0.01, 'dimensionless')>),我也可以使用 x.to('percent'),但是 x.to('%') 会出现错误 pint.errors.DefinitionSyntaxError: missing unary operator "%" - 有什么想法和解决方法吗? - Michal Kaut
@MichalKaut,我已经看到了你在GitHub上的评论(https://github.com/hgrecco/pint/issues/185#issuecomment-1264660139),但是很遗憾,我对Pint的内部工作过程不太熟悉,无法帮助解决这个问题。如果你找到解决方案,我很乐意听取你的回复! - Nicolai Weitkemper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接