Python загадка о для цикла и сокращения - PullRequest
0 голосов
/ 13 февраля 2019

Я пытаюсь вычислить байтовую энтропию для исполняемого файла.Сначала я использовал цикл for для его вычисления после получения гистограммы в виде массива.Затем я попытался использовать functools.reduce, чтобы немного закрепиться.Интересно, что я получаю разные результаты из одного и того же массива и одной и той же функции, и я хочу понять, почему.

Я сократил его до простого цикла и двухстрочного кода, но я не мог понять, почему один изони не правы.Я сравнил все элементы списка "prob" и "prob" из цикла for, все значения одинаковы.

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)

AND

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

Один из них дает 0,813826598594107 другойодин 0,8605594205272858."Hist" - это numpy.ndarray.

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Проблема заключается в начальном значении, как @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().

0 голосов
/ 13 февраля 2019

Ваше начальное значение отличается.В циклической версии вы сначала применяете calc_entropy(0, prob[0]), но с помощью limit ваше первое приложение будет calc_entropy(prob[0], prob[1]).Вы можете изменить это, вызвав reduce с начальным значением: reduce(calc_entropy, prob, 0).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...