14

我正在寻找一个 python 库,它支持在各种 SI 前缀之间转换数字,例如,kilo 到 pico,nano 到 giga 等等。你会推荐什么?

4

6 回答 6

17

我将一个简单的函数(由 Jukka “Yucca” Korpela 编写的原始 C 版本)移植到 Python 以根据 SI 标准格式化数字。我经常使用它,例如,在绘图上设置刻度标签等。

您可以使用以下方式安装它:

pip install si-prefix

源代码在 GitHub 上可用

示例用法:

from si_prefix import si_format

print si_format(.5)
# 500.0m  (default precision is 1)

print si_format(.01331, precision=2)
# 13.31m

print si_format(1331, precision=2)
# 1.33k

print si_format(1331, precision=0)
# 1k
于 2015-08-19T10:33:45.800 回答
6

Dictionaries

If you don't want to use any 3rd-party library like the ones listed below, you can actually implement your own parsing function.

Use a dictionary to match up the prefixes to their values. I've done it for you already:

_prefix = {'y': 1e-24,  # yocto
           'z': 1e-21,  # zepto
           'a': 1e-18,  # atto
           'f': 1e-15,  # femto
           'p': 1e-12,  # pico
           'n': 1e-9,   # nano
           'u': 1e-6,   # micro
           'm': 1e-3,   # mili
           'c': 1e-2,   # centi
           'd': 1e-1,   # deci
           'k': 1e3,    # kilo
           'M': 1e6,    # mega
           'G': 1e9,    # giga
           'T': 1e12,   # tera
           'P': 1e15,   # peta
           'E': 1e18,   # exa
           'Z': 1e21,   # zetta
           'Y': 1e24,   # yotta
    }

Then you can use regex (as described by my answer here) to search or parse the input and use the dictionary for getting the appropriate value.


Unum

Unum is well finished and thoroughly documented library.

Pros:

  • allows you to define arbitrary units (magnitude only supports user-defined units as long as they are a combination of the base units).

Cons:

  • doesn't handle prefixes well
  • clutters your namespace with all its unit definitions (you end up with variables named M, S etc. in your namespace)

Magnitude

You can also use Magnitude, another library. It supports all the kinds of SI unit prefixes you're talking about, plus it'll handle the parsing as well. From the site:

A physical quantity is a number with a unit, like 10 km/h. Units are specified as strings. They can be any of the SI units, plus a bunch of non-SI, bits, dollars, and any combination of them. They can include the standard SI prefixes.
...
All standard prefixes are understood, from yocto to yotta and from kibi to exbi.

于 2012-06-10T17:45:52.567 回答
6

QuantiPhy是一个新的软件包,它可以在具有 SI 比例因子的数字之间进行转换。单位包(例如 Unum 和 Magnitude)通常是更好的选择,它们更重并专注于单位而不是比例因子。

QuantiPhy 提供了 Quantity,它是一个将数字与其测量单位相结合的对象(单位是可选的)。创建数量时,您可以使用 SI 单位前缀。一旦你有了一个数量,你就可以在表达式中使用它,它充当一个浮点数。或者您可以将其转换为字符串,在这种情况下,它默认使用 SI 单位前缀。

>>> from quantiphy import Quantity

# convert strings to quantities
>>> duration = Quantity('0.12 ks')
>>> print(duration)
120 s

# convert to other units when rendering to a string
>>> print(duration.render(scale='min'))
2 min

# quantities act like floats in expressions
>>> rate = 1/duration
>>> print(rate)
0.008333333333333333

# convert floats to quantities
>>> rate = Quantity(rate, 'Hz')
>>> print(rate)
8.3333 mHz

# can be used in format strings
>>> print(f'Duration = {duration:<12.3} Rate = {rate}')
Duration = 120 s        Rate = 8.3333 mHz

默认情况下,QuantiPhy 在渲染到字符串时使用自然前缀,这可能是您想要的。但是您可以使用缩放强制它渲染到特定前缀:

>>> mass = Quantity('1000 g')
>>> print(mass)
1 kg

>>> print(mass.render(show_si=False))
1e3 g

>>> print(mass.render(show_si=False, scale=(1e-12, 'pg')))
1e9 pg

在这种情况下,您必须关闭 SI 单位前缀以避免获得多个前缀:'1 npg'。

一个更自然的例子可能是您要转换单位:

>>> l = Quantity('2um')                                                      
>>> print(l.render(scale='Å'))                                               
20 kÅ                                                                        

>>> print(f'{l:sÅ}')                                                         
20 kÅ

最后一个示例显示您可以将所需的单位放在类型之后的格式字符串中,并且将自动为您完成转换。

于 2017-07-15T21:23:56.650 回答
4

我不知道这是否是最好的答案,但它适用于我的情况。随意验证我的解决方案。我是第一次使用 Python,欢迎提出建设性的批评......以及积极的反馈:D
这是我的代码:

class Units:
def __init__(self):
    global si;
    si = {
          -18 : {'multiplier' : 10 ** 18, 'prefix' : 'a'},
          -17 : {'multiplier' : 10 ** 18, 'prefix' : 'a'},
          -16 : {'multiplier' : 10 ** 18, 'prefix' : 'a'},
          -15 : {'multiplier' : 10 ** 15, 'prefix' : 'f'},
          -14 : {'multiplier' : 10 ** 15, 'prefix' : 'f'},
          -13 : {'multiplier' : 10 ** 15, 'prefix' : 'f'},
          -12 : {'multiplier' : 10 ** 12, 'prefix' : 'p'},
          -11 : {'multiplier' : 10 ** 12, 'prefix' : 'p'},
          -10 : {'multiplier' : 10 ** 12, 'prefix' : 'p'},
          -9 : {'multiplier' : 10 ** 9, 'prefix' : 'n'},
          -8 : {'multiplier' : 10 ** 9, 'prefix' : 'n'},
          -7 : {'multiplier' : 10 ** 9, 'prefix' : 'n'},
          -6 : {'multiplier' : 10 ** 6, 'prefix' : 'u'},
          -5 : {'multiplier' : 10 ** 6, 'prefix' : 'u'},
          -4 : {'multiplier' : 10 ** 6, 'prefix' : 'u'},
          -3 : {'multiplier' : 10 ** 3, 'prefix' : 'm'},
          -2 : {'multiplier' : 10 ** 2, 'prefix' : 'c'},
          -1 : {'multiplier' : 10 ** 1, 'prefix' : 'd'},
           0 : {'multiplier' : 1, 'prefix' : ''},
           1 : {'multiplier' : 10 ** 1, 'prefix' : 'da'},
           2 : {'multiplier' : 10 ** 3, 'prefix' : 'k'},
           3 : {'multiplier' : 10 ** 3, 'prefix' : 'k'},
           4 : {'multiplier' : 10 ** 3, 'prefix' : 'k'},
           5 : {'multiplier' : 10 ** 3, 'prefix' : 'k'},
           6 : {'multiplier' : 10 ** 6, 'prefix' : 'M'},
           7 : {'multiplier' : 10 ** 6, 'prefix' : 'M'},
           8 : {'multiplier' : 10 ** 6, 'prefix' : 'M'},
           9 : {'multiplier' : 10 ** 9, 'prefix' : 'G'},
          10 : {'multiplier' : 10 ** 9, 'prefix' : 'G'},
          11 : {'multiplier' : 10 ** 9, 'prefix' : 'G'},
          12 : {'multiplier' : 10 ** 12, 'prefix' : 'T'},
          13 : {'multiplier' : 10 ** 12, 'prefix' : 'T'},
          14 : {'multiplier' : 10 ** 12, 'prefix' : 'T'},
          15 : {'multiplier' : 10 ** 15, 'prefix' : 'P'},
          16 : {'multiplier' : 10 ** 15, 'prefix' : 'P'},
          17 : {'multiplier' : 10 ** 15, 'prefix' : 'P'},
          18 : {'multiplier' : 10 ** 18, 'prefix' : 'E'},
          }

def convert(self, number):
    # Checking if its negative or positive
    if number < 0:
        negative = True;
    else:
        negative = False;

    # if its negative converting to positive (math.log()....)
    if negative:
        number = number - (number*2);

    # Taking the exponent
    exponent = int(math.log10(number));

    # Checking if it was negative converting it back to negative
    if negative:
        number = number - (number*2);

    # If the exponent is smaler than 0 dividing the exponent with -1
    if exponent < 0:
        exponent = exponent-1;
        return [number * si[exponent]['multiplier'], si[exponent]['prefix']]; 
    # If the exponent bigger than 0 just return it
    elif exponent > 0:
        return [number / si[exponent]['multiplier'], si[exponent]['prefix']]; 
    # If the exponent is 0 than return only the value
    elif exponent == 0:
        return [number, ''];


这就是它的工作原理:

c1 = +1.189404E-010
fres = -4.07237500000000E+007;
ls = +1.943596E-005;

units = sci.Units();
rValue, rPrefix = units.convert(c1);
print rValue;
print rPrefix;

print units.convert(fres);
print units.convert(ls);

回应是:

118.9404
p
[-40.72375, 'M']
[19.435959999999998, 'u']

我不知道是否有人会觉得这有帮助。我希望你会。我已经在这里发布了,所以想要帮助的人也可以给他们一个想法,也许他们可以优化它:)

于 2013-12-06T15:24:41.857 回答
3

我知道这是一个旧线程,但我只想抛出对我编写的处理各种前缀单位转换处理的 python 库的引用

以下是主要功能列表:

于 2016-01-07T16:32:56.760 回答
0

@naitsirhc,感谢您的包裹。我添加了一个小功能想法来使用你的包

import pandas as pd
import collections
Measure = collections.namedtuple('Measure', 'SLOT TEXT AVG HIGH LAST LOW SIGMA SWEEPS')
d=[Measure(SLOT='1', TEXT='CH1,AMPLITUDE', AVG='584.4782173493248E-3', HIGH='603.9744119119119E-3', LAST='594.125218968969E-3', LOW='561.1797735235235E-3', SIGMA='5.0385410346638E-3', SWEEPS='237996'), Measure(SLOT='2', TEXT='CH1,FREQUENCY', AVG='873.9706607717992E+6', HIGH='886.1564731675113E+6', LAST='873.9263571643770E+6', LOW='854.8833348698727E+6', SIGMA='4.382200567330E+6', SWEEPS='20705739'), Measure(SLOT='3', TEXT='CH4,PERIOD', AVG='1.1428492411436E-9', HIGH='1.1718844685593E-9', LAST='1.1432428766843E-9', LOW='1.1261916413092E-9', SIGMA='6.6735923746950E-12', SWEEPS='20680921'), Measure(SLOT='4', TEXT='CH4,FREQUENCY', AVG='875.0358282079155E+6', HIGH='887.9483414008331E+6', LAST='874.780693212961E+6', LOW='853.3264385945507E+6', SIGMA='5.0993358972092E+6', SWEEPS='20681008')]

from si_prefix import si_format

import si_prefix
si_prefix.SI_PREFIX_UNITS="yzafpnum kMGTPEZY"

def siSuffixNotation(element):
    try:
        ret=float(element)
        return str(si_format(ret)).replace(' ','')
    except ValueError:
        return element

df=pd.DataFrame(d)

df.T.applymap(siSuffixNotation) #<= nice pretty print output table
                    0              1           2              3
SLOT              1.0            2.0         3.0            4.0
TEXT    CH1,AMPLITUDE  CH1,FREQUENCY  CH4,PERIOD  CH4,FREQUENCY
AVG            584.5m         874.0M        1.1n         875.1M
HIGH           604.0m         885.6M        1.2n         887.9M
LAST           586.5m         874.2M        1.1n         874.9M
LOW            561.2m         854.9M        1.1n         854.1M
SIGMA            5.0m           4.4M        6.7p           5.1M
SWEEPS         191.5k          16.7M       16.6M          16.6M

多亏了你,我知道有一张我喜欢的漂亮的打印表。(我不喜欢数字和后缀之间的空格,我不喜欢 unicode 类型,我更喜欢 u for micro)++

于 2022-01-06T14:36:36.147 回答