如何高效统计拟合值与真实值数组元素的共同有效小数位数?
高效评估多项式拟合的有效小数位数
我需要用np.polyfit拟合复杂函数,通过统计近似值与真实值的有效小数位数评估拟合质量。原方法通过将浮点数转为字符串求最长公共前缀,效率极低,现提供基于数值计算的高效实现方案。
原低效实现代码
import numpy as np from collections import Counter x = np.linspace(1, 2, 4096) exp = np.exp(x) poly = np.polyfit(x, exp, 6) approx = np.polyval(poly, x) def LCP(s1, s2): c = 0 for a, b in zip(s1, s2): if a != b: break c += 1 return c def leading_digits(f1, f2): l = LCP(str(f1), str(f2)) - 1 return max(l, 0) correct_places = Counter() for a, b in zip(approx, exp): correct_places[leading_digits(a, b)] += 1
原输出:
Counter({7: 2014, 8: 1699, 6: 207, 9: 135, 5: 27, 10: 12, 11: 2})
高效实现方案
核心思路
避开字符串转换和Python循环,基于有效数字的数学定义用numpy向量化运算直接推导:
- 符号不同的数值有效位数为0
- 相对误差越小,有效一致位数越多,可通过对数运算直接计算:
有效位数 = floor(-log10(相对误差)) - 完全匹配的数值设为浮点数最大有效位数(如15)
高效代码实现
import numpy as np from collections import Counter x = np.linspace(1, 2, 4096) exp_true = np.exp(x) poly = np.polyfit(x, exp_true, 6) exp_approx = np.polyval(poly, x) def count_significant_agreement(true_vals, approx_vals): # 符号不匹配的位置有效位数为0 signs_match = np.sign(true_vals) == np.sign(approx_vals) # 计算绝对误差与相对误差 abs_err = np.abs(true_vals - approx_vals) rel_err = abs_err / np.abs(true_vals) # 初始化结果数组 sig_digits = np.zeros_like(true_vals, dtype=int) # 处理完全匹配的情况(误差为0) perfect_mask = rel_err == 0 sig_digits[perfect_mask] = 15 # 处理符号匹配但非完全匹配的情况 valid_mask = signs_match & ~perfect_mask sig_digits[valid_mask] = np.floor(-np.log10(rel_err[valid_mask])).astype(int) # 确保结果非负(误差大于真实值时设为0) sig_digits = np.maximum(sig_digits, 0) return sig_digits # 计算有效位数并统计 sig_digits = count_significant_agreement(exp_true, exp_approx) correct_places = Counter(sig_digits) print(correct_places)
方案优势
- 速度提升显著:numpy向量化运算替代Python循环,数据量越大优势越明显(4096个元素下,效率提升数十倍)
- 结果更可靠:避免字符串格式(如科学计数法)带来的歧义,完全基于数学定义计算
- 扩展性强:可直接处理大规模数组,无需修改核心逻辑
内容的提问来源于stack exchange,提问作者Ξένη Γήινος
相关产品推荐
相关产品推荐

