关于for循环和reduce的Python之谜
我试图计算一个可执行文件的字节熵。在得到直方图作为数组后,我首先使用for循环来计算它。然后我试着使用functools.reduce来稍微紧固一点。有趣的是,我从同一个数组和同一个函数中得到了不同的结果,我想知道为什么 我把它简化为一个简单的循环和两行代码块,但我不明白为什么其中一个是错误的。我比较了for循环中列表“prob”和“prob”的所有元素,所有值都是相同的关于for循环和reduce的Python之谜,python,numpy,lambda,functional-programming,Python,Numpy,Lambda,Functional Programming,我试图计算一个可执行文件的字节熵。在得到直方图作为数组后,我首先使用for循环来计算它。然后我试着使用functools.reduce来稍微紧固一点。有趣的是,我从同一个数组和同一个函数中得到了不同的结果,我想知道为什么 我把它简化为一个简单的循环和两行代码块,但我不明白为什么其中一个是错误的。我比较了for循环中列表“prob”和“prob”的所有元素,所有值都是相同的 calc_entropy = lambda e,p: e - p*math.log(p,256) if (p != .0)
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)
及
其中一个给出0.813826598594107,另一个给出0.8605594205272858。“hist”是一个名词 您的初始值不同。
在循环版本中,您首先应用
calc_熵(0,prob[0])
,但使用reduce时,您的第一个应用是calc_熵(prob[0],prob[1])
。您可以通过调用带有初始值的reduce
来改变这一点:reduce(计算熵,prob,0)
正如@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
一些测试(我只展示了一个测试,但我做了几个不同数字的测试,所有测试的结论如下):
请注意
f1b()
和f2()
的结果是如何相等的,但不同于f1a()
如果您给出hist
和字节长度,我会很高兴。您可以将np.random与np.random.seed(123)一起使用。您的numpy.ndarray历史记录中的dtype
是什么?是浮点型还是整数型?我猜:/
中的浮点精度是问题所在@阿列克西:这是个裸体。float64@FelixMartinez但是,循环中的所有“prob”值都等于数组中的相应值。这是有意义的。等待批准是的。你是对的-我做了一个只有3个元素的数组的实验,这似乎是一个可能的原因。我把我的实验也贴出来作为答案。
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