np.log() 默认是自然对数(底数为e),非常用对数;需用np.log10()或np.log2()分别处理以10或2为底的场景,且输入必须为正数,否则返回nan或-inf。

np.log() 默认是自然对数,不是以10为底
很多人一看到 np.log() 就默认它等于计算器上的 “log”(即 log₁₀),结果算出来数值对不上。其实 NumPy 严格遵循数学惯例:np.log() 就是 ln(x),底数是 e;np.log10() 才是常用对数,np.log2() 是二进制对数。
常见错误现象:
– 输入 np.log(100) 得到约 4.605,而不是 2
– 想做图像横轴取对数刻度,误用 np.log() 导致坐标标错
- 如果明确要常用对数(比如 pH、分贝、地震震级),直接用
np.log10() - 如果做信息论或位运算相关计算(如熵、ID3 决策树),优先用
np.log2(),语义清晰且避免浮点误差放大 -
np.log()在梯度计算、概率模型(如 softmax、log-likelihood)中更自然,因为导数简洁:d/dx ln(x) = 1/x
对负数或零调用 np.log() 会返回 nan 或 inf
np.log() 及其变体只对正实数有定义。传入 ≤ 0 的值不会报错,而是静默返回 nan(负数)或 -inf(零),后续计算极易被污染。
使用场景举例:
– 数据归一化后做对数变换(如 TF-IDF 向量)
– 绘图前对 y 值取对数,但原始数据含 0
- 先过滤或替换非正数:
x_safe = np.where(x > 0, x, np.nan),再调用np.log(x_safe) - 加极小偏移虽快但危险:
np.log(x + 1e-12)可能掩盖真实零值问题,尤其在科学计算中不推荐 - 用
np.errstate(invalid='raise')主动捕获nan,适合调试阶段
换底公式没必要手写,np.log(x) / np.log(base) 足够可靠
有人担心 np.log10() 和 np.log(1000) / np.log(10) 结果不同,其实 NumPy 已优化过所有内置对数函数,精度和性能都优于手动换底。只有 base 非常规(比如 log₃ 或 log₁₀₀₀)才需除法。
参数差异注意点:
– np.log(x) / np.log(3) 和 np.emath.logn(3, x) 行为不同:后者支持复数输入,前者遇到负数直接出 nan
– 所有基于除法的换底都继承被除数的精度误差,base 越接近 1,相对误差越明显
- base 是整数且常见(2/10/e),无条件用
np.log2()、np.log10()、np.log() - base 是变量(如用户输入的底数),用
np.log(x) / np.log(base)即可,不必引入np.emath - 避免写
np.log(x) * np.log(np.e) / np.log(base)—— 多余,np.log(np.e)就是 1.0
log 输出 dtype 取决于输入,但复数输入需显式启用
默认情况下,np.log() 对 float32/float64 输入返回同类型;但如果输入含负数,普通调用仍返回 real dtype + nan,而非自动转复数。
性能影响:
– np.complex64 输入比 float64 慢约 1.5×,内存占用翻倍
– 大多数机器学习 pipeline 不期望复数,意外触发会导致下游断言失败
- 需要复数结果(如信号处理中的相位谱),先转类型:
np.log(x.astype(complex)) - 不确定输入符号,又想安全得到复数结果,用
np.emath.log(x)(注意不是np.math) -
np.emath.log()对正实数行为与np.log()一致,无需额外判断分支
实际用的时候,最常被忽略的是:log 前没检查数据是否全为正,以及把 np.log() 当成 log₁₀ 用却没改业务逻辑。这两个点一旦出错,结果偏差不是小数点后几位的问题,而是数量级错乱。

















