Если вы собираетесь вызывать функцию расстояния много раз во время одного выполнения вашей программы, вы можете немного увеличить скорость, используя предварительно вычисленную таблицу битовых счетчиков. Вот (еще одна) версия функции расстояния Хэмминга:
# _nbits[k] is the number of 1s in the binary representation of k for 0 <= k < 256.
_nbits = np.array(
[0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3,
4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4,
4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2,
3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,
4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4,
5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3,
3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2,
3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5,
6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5,
5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6,
7, 7, 8], dtype=np.uint8)
def hamming_distance1(a, b):
c = np.bitwise_xor(a, b)
n = _nbits[c].sum()
return n
Далее a
и b
— это списки Python длиной 32, указанные в комментарии к вопросу. divakar_hamming_distance()
и divakar_hamming_distance_v2()
взяты из ответа @Divakar.
Вот время работы @Divakar:
In [116]: %timeit divakar_hamming_distance(a, b)
The slowest run took 5.57 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 11.3 µs per loop
In [117]: %timeit divakar_hamming_distance_v2(a, b)
The slowest run took 5.35 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 10.3 µs per loop
hamming_distance1(a, b)
немного быстрее:
In [118]: %timeit hamming_distance1(a, b)
The slowest run took 6.04 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 7.42 µs per loop
На моем компьютере инициализация _nbits
занимает около 11 мкс, поэтому нет никаких преимуществ в использовании hamming_distance1
, если вы вызываете функцию только один раз. Если вы вызовете его три или более раз, вы получите чистый выигрыш в производительности.
Если входные данные уже представляют собой массивы numpy, все функции выполняются значительно быстрее:
In [119]: aa = np.array(a)
In [120]: bb = np.array(b)
In [121]: %timeit divakar_hamming_distance_v2(aa, bb)
The slowest run took 8.22 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 5.72 µs per loop
In [122]: %timeit hamming_distance1(aa, bb)
The slowest run took 12.67 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 2.77 µs per loop
Конечно, если вы всегда делаете это непосредственно перед вычислением расстояния Хэмминга, время, необходимое для преобразования, должно быть включено в общее время. Однако, если вы напишете код, который генерирует a
и b
, чтобы воспользоваться преимуществом numpy ранее, вы можете уже иметь их в виде массивов numpy к тому времени, когда вы вычислите расстояние Хэмминга.
(Я также немного поэкспериментировал с двумерным массивом предварительно вычисленных расстояний Хэмминга между 8-битными значениями — массивом формы (256, 256) — но стоимость инициализации выше, а прирост производительности невелик.)
person
Warren Weckesser
schedule
29.11.2016
0 + 1
вместо этого, потому что 254 — это все единицы, кроме одного бита, тогда как 255 — это все единицы? - person Divakar   schedule 29.11.2016a
иb
? - person Warren Weckesser   schedule 30.11.2016