按比例将 Numpy 浮点数数组转换为整数(平衡化学方程式)
Convert Numpy array of floats to ints proportionately (balancing chemical equation)
我有一个平衡化学方程式的代码。唯一的问题是我想将最终解决方案(即 1D np 浮点数组)转换为整数。显然,我不能直接将它四舍五入到最接近的整数,那样会弄乱平衡。一种方法是将它与将浮点数转换为整数的数字相乘(类型无关紧要)。请参阅下面的示例。
>>> coeffs=equation_balancer(reactants=["H2","O2"], products=["H2O"])
>>> coeffs
{"H2": 1.0, "O2": 0.5, 'H2O1': 1.0}
>>> import numpy as np
>>> np.asarray([i for i in coeffs.values()])
array([1. , 0.5, 1.])
如果最终数组乘以2
,则可以删除分数(浮点数)。
PS 为了显示上面的示例,我改回 np,因为 equation_balancer 使用 scipy.linalg.solve 来平衡等式。
>>> np.asrray([i for i in coeffs.values()])*2
array([2., 1., 2.])
如何得到这个与数组相乘得到整数值数组的数字?数组的实际类型无关紧要。
一种方法是将数组与最高分母相乘,即 10 的倍数。然后找到最大公因数:
>>> c=np.asrray([i for i in coeffs.values()])*10
>>> factor = np.gcd.reduce(c.astype(int))
>>> factor
5
>>> c/factor
array([2., 1., 2.])
在上述情况下,找到由最高小数位数定义的 10*n 至关重要。我现在不知道如何编码。还有其他更合适的方法吗?任何帮助。
我对我的解决方案并不完全满意,但它似乎工作正常,让我知道你的想法,我实际上是将浮点数转换为字符串并计算小数点后的字符数,它会工作只要值始终为 float
import numpy as np
coeffs = {"H2": .1, "O2": 0.05, 'H2O1': .1}
n = max([len(str(i).split('.')[1]) for i in coeffs.values()])
c=np.array([i for i in coeffs.values()])*10**n
factor = np.gcd.reduce(c.astype(np.uint64))
print((c/factor).astype(np.uint64))
来源及其他解决方案:
Easy way of finding decimal places
测试: 运行 一些可能的困难案例转换回来的例子
primes = [3,5,7,11,13,17,19,23,29,79] ## some prime numbers
primes_over_1 = [1/i for i in primes]
for i in range(1, len(primes_over_1) - 1):
coeffs = {"H2": primes_over_1[i-1], "O2": primes_over_1[i], 'H2O1': primes_over_1[i+1]}
print('coefs: ', [a for a in coeffs.values()])
n = max([len(str(a).split('.')[1]) for a in coeffs.values()])
c=np.array([a for a in coeffs.values()])*10**n
factor = np.gcd.reduce(c.astype(np.uint64))
coeffs_asInt = (c/factor).astype(np.uint64)
print('as int:', coeffs_asInt)
coeffs_back = coeffs_asInt.astype(np.float64)*(factor/10**n)
coeffs_back_str = ["{0:.16g}".format(a) for a in coeffs_back]
print('back: ', coeffs_back_str)
print('########################################################\n')
输出:
coefs: [0.3333333333333333, 0.2, 0.14285714285714285]
as int: [8333333333333333 5000000000000000 3571428571428571]
back: ['0.3333333333333334', '0.2', '0.1428571428571428']
########################################################
coefs: [0.2, 0.14285714285714285, 0.09090909090909091]
as int: [5000000000000000 3571428571428571 2272727272727273]
back: ['0.2', '0.1428571428571428', '0.09090909090909093']
########################################################
coefs: [0.14285714285714285, 0.09090909090909091, 0.07692307692307693]
as int: [14285714285714284 9090909090909092 7692307692307693]
back: ['0.1428571428571428', '0.09090909090909093', '0.07692307692307694']
########################################################
coefs: [0.09090909090909091, 0.07692307692307693, 0.058823529411764705]
as int: [2840909090909091 2403846153846154 1838235294117647]
back: ['0.09090909090909091', '0.07692307692307693', '0.05882352941176471']
########################################################
coefs: [0.07692307692307693, 0.058823529411764705, 0.05263157894736842]
as int: [2403846153846154 1838235294117647 1644736842105263]
back: ['0.07692307692307693', '0.05882352941176471', '0.05263157894736842']
########################################################
coefs: [0.058823529411764705, 0.05263157894736842, 0.043478260869565216]
as int: [1838235294117647 1644736842105263 1358695652173913]
back: ['0.05882352941176471', '0.05263157894736842', '0.04347826086956522']
########################################################
coefs: [0.05263157894736842, 0.043478260869565216, 0.034482758620689655]
as int: [6578947368421052 5434782608695652 4310344827586207]
back: ['0.05263157894736842', '0.04347826086956522', '0.03448275862068966']
########################################################
coefs: [0.043478260869565216, 0.034482758620689655, 0.012658227848101266]
as int: [21739130434782608 17241379310344828 6329113924050633]
back: ['0.04347826086956522', '0.03448275862068966', '0.01265822784810127']
########################################################
这似乎有效:
(感谢 this SO answer 如何将浮点数转换为“最小”整数分子和整数分母的元组——而不是一些非常大的分子和分母)
import numpy as np
from fractions import Fraction
# A configurable param.
# Keep this small to avoid frekish large results.
# Increase it only in rare cases where the coeffs
# span a "huge" scale.
MAX_DENOM = 100
fractions = [Fraction(val).limit_denominator(MAX_DENOM)
for val in coeffs.values()]
ratios = np.array([(f.numerator, f.denominator) for f in fractions])
# As an alternative to the above two statements, uncomment and use
# below statement for Python 3.8+
# ratios = np.array([Fraction(val).limit_denominator(MAX_DENOM).as_integer_ratio()
# for val in coeffs.values()])
factor = np.lcm.reduce(ratios[:,1])
result = [round(v * factor) for v in coeffs.values()]
# print
result
coeffs = {"H2": 1.0, "O2": 0.5, 'H2O1': 1.0}
的输出:
[2, 1, 2]
coeffs = {"H2": 0.5, "N2":0.5, "O2": 1.5, "H1N1O3":1.0}
的输出:
[1, 1, 3, 2]
coeffs = {"H2": 1.0, "O3": (1/3), "H2O1":1.0}
的输出:
[3, 1, 3]
coeffs = {"H4": 0.5, "O7": (1/7), "H2O1":1.0}
的输出:
[7, 2, 14]
coeffs = {"H2": .1, "O2": 0.05, 'H2O1': .1}
的输出:
[2, 1, 2]
我有一个平衡化学方程式的代码。唯一的问题是我想将最终解决方案(即 1D np 浮点数组)转换为整数。显然,我不能直接将它四舍五入到最接近的整数,那样会弄乱平衡。一种方法是将它与将浮点数转换为整数的数字相乘(类型无关紧要)。请参阅下面的示例。
>>> coeffs=equation_balancer(reactants=["H2","O2"], products=["H2O"])
>>> coeffs
{"H2": 1.0, "O2": 0.5, 'H2O1': 1.0}
>>> import numpy as np
>>> np.asarray([i for i in coeffs.values()])
array([1. , 0.5, 1.])
如果最终数组乘以2
,则可以删除分数(浮点数)。
PS 为了显示上面的示例,我改回 np,因为 equation_balancer 使用 scipy.linalg.solve 来平衡等式。
>>> np.asrray([i for i in coeffs.values()])*2
array([2., 1., 2.])
如何得到这个与数组相乘得到整数值数组的数字?数组的实际类型无关紧要。
一种方法是将数组与最高分母相乘,即 10 的倍数。然后找到最大公因数:
>>> c=np.asrray([i for i in coeffs.values()])*10
>>> factor = np.gcd.reduce(c.astype(int))
>>> factor
5
>>> c/factor
array([2., 1., 2.])
在上述情况下,找到由最高小数位数定义的 10*n 至关重要。我现在不知道如何编码。还有其他更合适的方法吗?任何帮助。
我对我的解决方案并不完全满意,但它似乎工作正常,让我知道你的想法,我实际上是将浮点数转换为字符串并计算小数点后的字符数,它会工作只要值始终为 float
import numpy as np
coeffs = {"H2": .1, "O2": 0.05, 'H2O1': .1}
n = max([len(str(i).split('.')[1]) for i in coeffs.values()])
c=np.array([i for i in coeffs.values()])*10**n
factor = np.gcd.reduce(c.astype(np.uint64))
print((c/factor).astype(np.uint64))
来源及其他解决方案: Easy way of finding decimal places
测试: 运行 一些可能的困难案例转换回来的例子
primes = [3,5,7,11,13,17,19,23,29,79] ## some prime numbers
primes_over_1 = [1/i for i in primes]
for i in range(1, len(primes_over_1) - 1):
coeffs = {"H2": primes_over_1[i-1], "O2": primes_over_1[i], 'H2O1': primes_over_1[i+1]}
print('coefs: ', [a for a in coeffs.values()])
n = max([len(str(a).split('.')[1]) for a in coeffs.values()])
c=np.array([a for a in coeffs.values()])*10**n
factor = np.gcd.reduce(c.astype(np.uint64))
coeffs_asInt = (c/factor).astype(np.uint64)
print('as int:', coeffs_asInt)
coeffs_back = coeffs_asInt.astype(np.float64)*(factor/10**n)
coeffs_back_str = ["{0:.16g}".format(a) for a in coeffs_back]
print('back: ', coeffs_back_str)
print('########################################################\n')
输出:
coefs: [0.3333333333333333, 0.2, 0.14285714285714285]
as int: [8333333333333333 5000000000000000 3571428571428571]
back: ['0.3333333333333334', '0.2', '0.1428571428571428']
########################################################
coefs: [0.2, 0.14285714285714285, 0.09090909090909091]
as int: [5000000000000000 3571428571428571 2272727272727273]
back: ['0.2', '0.1428571428571428', '0.09090909090909093']
########################################################
coefs: [0.14285714285714285, 0.09090909090909091, 0.07692307692307693]
as int: [14285714285714284 9090909090909092 7692307692307693]
back: ['0.1428571428571428', '0.09090909090909093', '0.07692307692307694']
########################################################
coefs: [0.09090909090909091, 0.07692307692307693, 0.058823529411764705]
as int: [2840909090909091 2403846153846154 1838235294117647]
back: ['0.09090909090909091', '0.07692307692307693', '0.05882352941176471']
########################################################
coefs: [0.07692307692307693, 0.058823529411764705, 0.05263157894736842]
as int: [2403846153846154 1838235294117647 1644736842105263]
back: ['0.07692307692307693', '0.05882352941176471', '0.05263157894736842']
########################################################
coefs: [0.058823529411764705, 0.05263157894736842, 0.043478260869565216]
as int: [1838235294117647 1644736842105263 1358695652173913]
back: ['0.05882352941176471', '0.05263157894736842', '0.04347826086956522']
########################################################
coefs: [0.05263157894736842, 0.043478260869565216, 0.034482758620689655]
as int: [6578947368421052 5434782608695652 4310344827586207]
back: ['0.05263157894736842', '0.04347826086956522', '0.03448275862068966']
########################################################
coefs: [0.043478260869565216, 0.034482758620689655, 0.012658227848101266]
as int: [21739130434782608 17241379310344828 6329113924050633]
back: ['0.04347826086956522', '0.03448275862068966', '0.01265822784810127']
########################################################
这似乎有效:
(感谢 this SO answer 如何将浮点数转换为“最小”整数分子和整数分母的元组——而不是一些非常大的分子和分母)
import numpy as np
from fractions import Fraction
# A configurable param.
# Keep this small to avoid frekish large results.
# Increase it only in rare cases where the coeffs
# span a "huge" scale.
MAX_DENOM = 100
fractions = [Fraction(val).limit_denominator(MAX_DENOM)
for val in coeffs.values()]
ratios = np.array([(f.numerator, f.denominator) for f in fractions])
# As an alternative to the above two statements, uncomment and use
# below statement for Python 3.8+
# ratios = np.array([Fraction(val).limit_denominator(MAX_DENOM).as_integer_ratio()
# for val in coeffs.values()])
factor = np.lcm.reduce(ratios[:,1])
result = [round(v * factor) for v in coeffs.values()]
# print
result
coeffs = {"H2": 1.0, "O2": 0.5, 'H2O1': 1.0}
的输出:
[2, 1, 2]
coeffs = {"H2": 0.5, "N2":0.5, "O2": 1.5, "H1N1O3":1.0}
的输出:
[1, 1, 3, 2]
coeffs = {"H2": 1.0, "O3": (1/3), "H2O1":1.0}
的输出:
[3, 1, 3]
coeffs = {"H4": 0.5, "O7": (1/7), "H2O1":1.0}
的输出:
[7, 2, 14]
coeffs = {"H2": .1, "O2": 0.05, 'H2O1': .1}
的输出:
[2, 1, 2]