【问题标题】:Python mystery about for loop and reduce关于for循环和reduce的Python之谜
【发布时间】:2019-07-07 09:21:42
【问题描述】:

我正在尝试计算可执行文件的字节熵。在将直方图作为数组后,我首先使用 for-loop 进行计算。然后我尝试使用 functools.reduce 来固定一点。有趣的是,我从同一个数组和同一个函数中得到了不同的结果,我想知道为什么。

我将它简化为一个简单的循环和两行代码块,但我不明白为什么其中一个是错误的。我比较了for循环中列表“prob”和“prob”的所有元素,所有值都相同。

calc_entropy = lambda e,p: e - p*math.log(p,256) if (p != .0) else e

prob = hist / bytes_len
e = functools.reduce(calc_entropy, prob)

e = .0
for freq in hist:
    prob = freq / bytes_len
    e = calc_entropy(e,prob)

其中一个给出 0.813826598594107,另一个给出 0.8605594205272858。 “hist”是一个 numpy.ndarray。

【问题讨论】:

  • 如果你给 histbytes_len 我会很好。您可以将 np.random 与 np.random.seed(123) 一起使用。
  • 您的numpy.ndarray hist 中的dtype 是什么?是float还是整数类型?
  • 我的猜测:/ 的浮点精度是这里的问题。 docs.python.org/2/tutorial/floatingpoint.html
  • @AlexYu 它是 numpy.float64
  • @FelixMartinez 但是,循环中的所有“概率”值都等于数组中的相应值。

标签: python numpy lambda functional-programming


【解决方案1】:

您的初始值不同。 在循环版本中,您首先应用calc_entropy(0, prob[0]),但使用reduce,您的第一个应用是calc_entropy(prob[0], prob[1])。您可以通过使用初始值调用reduce 来更改它:reduce(calc_entropy, prob, 0)

【讨论】:

  • 有道理。等待批准
  • 是的。你是对的 - 我用只有 3 个元素的数组做了实验
  • 这似乎是一个可能的原因。我也发布了我的实验作为答案。
【解决方案2】:

问题在于初始值,正如@YSelf 在他的回答中指出的那样。

这是一个演示:

import functools
import math
import numpy as np

calc_entropy = lambda e, p: e - p*math.log(p, 256) if (p != .0) else e

def f1a(hist, bytes_len):
    prob = hist / bytes_len
    e = functools.reduce(calc_entropy, prob)              # no initial value
    return e


def f1b(hist, bytes_len):
    prob = hist / bytes_len
    e = functools.reduce(calc_entropy, prob, 0.0)         # with initial value
    return e


def f2(hist, bytes_len):
    e = 0.0
    for freq in hist:
        prob = freq / bytes_len
        e = calc_entropy(e, prob)
    return e

一些测试(我只展示了一个测试,但是我做了几个不同数字的测试,都得出了相同的结论):

>>> b = 5
>>> h = np.random.rand(10)
>>> h
[0.68968912 0.37621079 0.76577699 0.06287911 0.49159805 0.63960027
 0.50323918 0.56442714 0.28445216 0.03391277]

>>> f1a(h, b)
0.4449530941371813
>>> f1b(h, b)
0.3562920060014537
>>> f2(h, b)
0.3562920060014537

注意f1b()f2() 的结果如何相等,但与f1a() 不同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 2019-09-21
    • 2018-02-22
    • 2016-02-18
    • 1970-01-01
    • 2012-01-07
    相关资源
    最近更新 更多