我试过搜索这个并且找不到满意的答案。
我想获取一个列表/数组,并将它们全部舍入为n个有效数字。我写了一个函数来做这个,但我想知道是否有一个标准的方法呢?我已经搜索但找不到它。例如:
In: [ 0.0, -1.2366e22, 1.2544444e-15, 0.001222 ], n=2
Out: [ 0.00, -1.24e22, 1.25e-15, 1.22e-3 ]
由于
答案 0 :(得分:9)
测试所有已经提出的解决方案,我发现它们要么
这是我尝试解决所有这些问题的解决方案。 (编辑2020-03-18:按照A. West的建议添加了np.asarray
。)
def signif(x, p):
x = np.asarray(x)
x_positive = np.where(np.isfinite(x) & (x != 0), np.abs(x), 10**(p-1))
mags = 10 ** (p - 1 - np.floor(np.log10(x_positive)))
return np.round(x * mags) / mags
测试:
def scottgigante(x, p):
x_positive = np.where(np.isfinite(x) & (x != 0), np.abs(x), 10**(p-1))
mags = 10 ** (p - 1 - np.floor(np.log10(x_positive)))
return np.round(x * mags) / mags
def awest(x,p):
return float(f'%.{p-1}e'%x)
def denizb(x,p):
return float(('%.' + str(p-1) + 'e') % x)
def autumn(x, p):
return np.format_float_positional(x, precision=p, unique=False, fractional=False, trim='k')
def greg(x, p):
return round(x, -int(np.floor(np.sign(x) * np.log10(abs(x)))) + p-1)
def user11336338(x, p):
xr = (np.floor(np.log10(np.abs(x)))).astype(int)
xr=10.**xr*np.around(x/10.**xr,p-1)
return xr
def dmon(x, p):
if np.all(np.isfinite(x)):
eset = np.seterr(all='ignore')
mags = 10.0**np.floor(np.log10(np.abs(x))) # omag's
x = np.around(x/mags,p-1)*mags # round(val/omag)*omag
np.seterr(**eset)
x = np.where(np.isnan(x), 0.0, x) # 0.0 -> nan -> 0.0
return x
def seanlake(x, p):
__logBase10of2 = 3.010299956639811952137388947244930267681898814621085413104274611e-1
xsgn = np.sign(x)
absx = xsgn * x
mantissa, binaryExponent = np.frexp( absx )
decimalExponent = __logBase10of2 * binaryExponent
omag = np.floor(decimalExponent)
mantissa *= 10.0**(decimalExponent - omag)
if mantissa < 1.0:
mantissa *= 10.0
omag -= 1.0
return xsgn * np.around( mantissa, decimals=p - 1 ) * 10.0**omag
solns = [scottgigante, awest, denizb, autumn, greg, user11336338, dmon, seanlake]
xs = [
1.114, # positive, round down
1.115, # positive, round up
-1.114, # negative
1.114e-30, # extremely small
1.114e30, # extremely large
0, # zero
float('inf'), # infinite
[1.114, 1.115e-30], # array input
]
p = 3
print('input:', xs)
for soln in solns:
print(f'{soln.__name__}', end=': ')
for x in xs:
try:
print(soln(x, p), end=', ')
except Exception as e:
print(type(e).__name__, end=', ')
print()
结果:
input: [1.114, 1.115, -1.114, 1.114e-30, 1.114e+30, 0, inf, [1.114, 1.115e-30]]
scottgigante: 1.11, 1.12, -1.11, 1.11e-30, 1.11e+30, 0.0, inf, [1.11e+00 1.12e-30],
awest: 1.11, 1.11, -1.11, 1.11e-30, 1.11e+30, 0.0, inf, TypeError,
denizb: 1.11, 1.11, -1.11, 1.11e-30, 1.11e+30, 0.0, inf, TypeError,
autumn: 1.11, 1.11, -1.11, 0.00000000000000000000000000000111, 1110000000000000000000000000000., 0.00, inf, TypeError,
greg: 1.11, 1.11, -1.114, 1.11e-30, 1.11e+30, ValueError, OverflowError, TypeError,
user11336338: 1.11, 1.12, -1.11, 1.1100000000000002e-30, 1.1100000000000001e+30, nan, nan, [1.11e+00 1.12e-30],
dmon: 1.11, 1.12, -1.11, 1.1100000000000002e-30, 1.1100000000000001e+30, 0.0, inf, [1.11e+00 1.12e-30],
seanlake: 1.11, 1.12, -1.11, 1.1100000000000002e-30, 1.1100000000000001e+30, 0.0, inf, ValueError,
时间:
def test_soln(soln):
try:
soln(np.linspace(1, 100, 1000), 3)
except Exception:
[soln(x, 3) for x in np.linspace(1, 100, 1000)]
for soln in solns:
print(soln.__name__)
%timeit test_soln(soln)
结果:
scottgigante
135 µs ± 15.3 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
awest
2.23 ms ± 430 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
denizb
2.18 ms ± 352 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
autumn
2.92 ms ± 206 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
greg
14.1 ms ± 1.21 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
user11336338
157 µs ± 50.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
dmon
142 µs ± 8.52 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
seanlake
20.7 ms ± 994 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
答案 1 :(得分:5)
numpy.set_printoptions您要找的是什么?
import numpy as np
np.set_printoptions(precision=2)
print np.array([ 0.0, -1.2366e22, 1.2544444e-15, 0.001222 ])
给出:
[ 0.00e+00 -1.24e+22 1.25e-15 1.22e-03]
修改强>
如果您尝试转换数据,numpy.around似乎可以解决此问题的各个方面。但是,在指数为负数的情况下,它不会执行您想要的操作。
答案 2 :(得分:2)
从示例数字中我认为你的意思是重要的数字而不是小数位(-1.2366e22
到0位小数仍然是-1.2366e22
)。
这段代码对我有用,我一直以为应该有一个内置功能:
def Round_To_n(x, n):
return round(x, -int(np.floor(np.sign(x) * np.log10(abs(x)))) + n)
>>> Round_To_n(1.2544444e-15,2)
1.25e-15
>>> Round_To_n(2.128282321e3, 6)
2130.0
答案 3 :(得分:2)
好的,如此合理安全地说这在标准功能中是不允许的。为了关闭它,这是我尝试一个强大的解决方案。这是相当丑陋/非pythonic和prob说明为什么我问这个问题更好,所以请随意纠正或击败:)
def round2SignifFigs(vals,n):
"""
(list, int) -> numpy array
(numpy array, int) -> numpy array
In: a list/array of values
Out: array of values rounded to n significant figures
Does not accept: inf, nan, complex
>>> m = [0.0, -1.2366e22, 1.2544444e-15, 0.001222]
>>> round2SignifFigs(m,2)
array([ 0.00e+00, -1.24e+22, 1.25e-15, 1.22e-03])
"""
import numpy as np
if np.all(np.isfinite(vals)) and np.all(np.isreal((vals))):
eset = np.seterr(all='ignore')
mags = 10.0**np.floor(np.log10(np.abs(vals))) # omag's
vals = np.around(vals/mags,n)*mags # round(val/omag)*omag
np.seterr(**eset)
vals[np.where(np.isnan(vals))] = 0.0 # 0.0 -> nan -> 0.0
else:
raise IOError('Input must be real and finite')
return vals
最近我得到整洁不考虑0.0,nan,inf或复杂:
>>> omag = lambda x: 10**np.floor(np.log10(np.abs(x)))
>>> signifFig = lambda x, n: (np.around(x/omag(x),n)*omag(x))
,并提供:
>>> m = [0.0, -1.2366e22, 1.2544444e-15, 0.001222]
>>> signifFig(m,2)
array([ nan, -1.24e+22, 1.25e-15, 1.22e-03])
答案 4 :(得分:2)
人们对&#34;重要数字&#34;的理解非常薄弱,这也是为什么很少有编程语言有内置的原因之一。
0.00是两个有效数字,因为小数点左边的零点不重要,但右边两个是。
1.234568e-01 - &gt; 0.123500 右手数字有7个有效数字,因为如果显示,则分数中的尾随零是显着的。因此映射是不正确的,因为正确的版本0.1234568到4 sig fig是0.1235。将其写为0.1234500意味着最后两个零是真实的并且是准确的,在这种情况下它们不是。
在某些情况下,甚至可以在给定数值的情况下计算sig figs的数量,而必须知道值的历史或来源。例如,如果溶液的pH值为7.00,它只有两个sig figs,它们是&#34; .00&#34;。由于pH是对数函数,因此7并不显着,而7只是基础数中10的幂。例如,1.0e-7,-log10(1.00e-7)= 7.00。原始数字有2个sig fig(1.0),-log10有2个sig fig&#39; s,=(#34; .00&#34;)而7不是sig fig。
在实践中,有时候图形的数量是模糊的。如果一个人写了1234000,则规则说000是无关紧要的。但如果他们真的很重要怎么办?如果作者想要正确地进行,并且无论如何,他们会写1.234000e6(1.234000x10 ^ 6)。该版本有7 sig fig。
12300 3 sig fig (but may be ambiguous to some)
1.23e4 3 sig fig (unambiguous)
1.2300e4 5 sig fig
12300.0 6 sig fig
12300.100 8 sig fig
答案 5 :(得分:1)
此处给出的大多数解决方案要么(a)没有给出正确的有效数字,要么(b)不必要地复杂。
如果您的目标是 display 格式,则numpy.format_float_positional直接支持所需的行为。以下片段返回浮点数x
,其格式为4个有效数字,但不包含科学计数法。
import numpy as np
x=12345.6
np.format_float_positional(x, precision=4, unique=False, fractional=False, trim='k')
> 12340.
答案 6 :(得分:1)
这是秋天答案的一个版本,该版本已矢量化,因此可以应用于浮点数组,而不仅仅是单个 float 。
x = np.array([12345.6, 12.5673])
def sf4(x):
x = float(np.format_float_positional(x, precision=4, unique=False, fractional=False,trim='k'))
return x
vec_sf4 = np.vectorize(sf4)
vec_sf4(x)
>>>np.array([12350., 12.57])
答案 7 :(得分:0)
有一个简单的解决方案,它使用pythons字符串格式化系统中内置的逻辑:
def round_sig(f, p):
return float(('%.' + str(p) + 'e') % f)
使用以下示例进行测试:
for f in [0.01, 0.1, 1, 10, 100, 1000, 1000]:
f *= 1.23456789
print('%e --> %f' % (f, round_sig(f,3)))
产生:
1.234568e-02 --> 0.012350
1.234568e-01 --> 0.123500
1.234568e+00 --> 1.235000
1.234568e+01 --> 12.350000
1.234568e+02 --> 123.500000
1.234568e+03 --> 1235.000000
1.234568e+03 --> 1235.000000
祝你好运!
(如果你喜欢使用lambdas:
round_sig = lambda f,p: float(('%.' + str(p) + 'e') % f)
)
答案 8 :(得分:0)
我喜欢Greg上面非常简短的有效程序。但是,它具有两个缺点。一是它不适用于x<0
,无论如何都不适合我。 (应该删除np.sign(x)
。)另外,如果x
是一个数组,则它不起作用。我已经用下面的例程修复了这两个问题。请注意,我已经更改了n
的定义。
def Round_n_sig_dig(x, n):
import numpy as np
xr = (np.floor(np.log10(np.abs(x)))).astype(int)
xr=10.**xr*np.around(x/10.**xr,n-1)
return xr
答案 9 :(得分:0)
sround = lambda x,p: float(f'%.{p-1}e'%x)
>>> print( sround(123.45, 2) )
120.0
答案 10 :(得分:0)
在搜寻互联网并没有找到答案之后,我感到非常沮丧,因此我编写了自己的代码。希望这就是您要寻找的
import numpy as np
from numpy import ma
exp = np.floor(ma.log10(abs(X)).filled(0))
ans = np.round(X*10**-exp, sigfigs-1) * 10**exp
只需插入np数组X和所需数量的有效数字。干杯!
答案 11 :(得分:0)
对于以指数符号表示的(display-)格式,numpy.format_float_scientific(x, precision = n)
(其中 x 是要格式化的数字)似乎效果很好。该方法返回一个string
。 (这类似于@Autumn的答案)
这里是一个例子:
>>> x = 7.92398e+05
>>> print(numpy.format_float_scientific(x, precision = 3))
7.924e+05
在这里,参数 precision = n 固定尾数中的小数位数(通过四舍五入)。可以将其重新转换为float
类型...这显然将只保留字符串中存在的数字。尽管它将转换为位置浮点格式,但需要做更多的工作-因此,我认为对于大量数字而言,重新转换可能是个坏主意。
此外,这不适用于可迭代对象...请在docs上查找更多信息。
答案 12 :(得分:0)
另一种效果很好的解决方案。从@ScottGigante进行测试,以1.75ms的时间倒数第二。
import math
def sig_dig(x, n_sig_dig = 5):
num_of_digits = len(str(x).replace(".", ""))
if n_sig_dig >= num_of_digits:
return x
n = math.floor(math.log10(abs(x)) + 1 - n_sig_dig)
result = round(x * 10**(-n)) * 10**n
return result
如果还应将其应用于列表/数组,则可以将其向量化为
sig_dig_vec = np.vectorize(sig_dig)
信用:受this post启发的答案