2015-11-06 2 views
0

Я пытаюсь оптимизировать свой код Python 2.7.x. Я собираюсь выполнить одну операцию внутри цикла for, возможно, миллионы раз, поэтому я хочу, чтобы она была как можно быстрее.Оптимизация кода Python для преобразования списка строк в целые числа и поплавки

Моя операция принимает список из 10 строк и преобразует их в 2 целых числа, за которыми следуют 8 поплавков.

Вот MWE из моих попыток:

import timeit 

    words = ["1"] * 10 

    start_time = timeit.default_timer() 
    for ii in range(1000000): 
     values = map(float, words) 
     values[0] = int(values[0]) 
     values[1] = int(values[1]) 
    print "1", timeit.default_timer() - start_time 

    start_time = timeit.default_timer() 
    for ii in range(1000000): 
     values = map(int, words[:2]) + map(float, words[2:]) 
    print "2", timeit.default_timer() - start_time 

    start_time = timeit.default_timer() 
    local_map = map 
    for ii in range(1000000): 
     values = local_map(float, words) 
     values[0] = int(values[0]) 
     values[1] = int(values[1]) 
    print "3", timeit.default_timer() - start_time 

    1 2.86574220657 
    2 3.83825802803 
    3 2.86320781708 

Первый блок кода является самым быстрым я сумел. Функция map выглядит намного быстрее, чем использование списка. Но есть еще избыточность, потому что я сопоставляю все с плавающей точкой, а затем меняю первые два элемента на целые числа.

Есть ли что-то более быстрое, чем мой код?

Почему не делает функцию карты локальной, local_map = map, улучшает скорость в третьем блоке кода?

+0

на общем примечании, используя '% timeit', вероятно, лучше для измерения производительности ... – Julien

+0

Вы связаны с Python 2? – Felk

+0

@Felk yep Python 2.7.x – innisfree

ответ

0

Я не нашел ничего более быстрого, но ваш самый быстрый код на самом деле будет ошибочным в некоторых случаях. Проблема заключается в том, что Python float (который является C-двойным) имеет ограниченную точность, для значений, превышающих 2 ** 53 (IIRC; может быть отключено на один бит), он не может представлять все целочисленные значения. Напротив, Python int - произвольная точность; если у вас есть память, он может представлять эффективные бесконечные значения.

Вы хотели бы изменить:

values[0] = int(values[0]) 
values[1] = int(values[1]) 

к:

values[0] = int(words[0]) 
values[1] = int(words[1]) 

, чтобы избежать этого. Репарация сделает это более зависимым от длины обрабатываемой строки (поскольку преобразование в несколько раз превышает затраты на более длинные входы).

Альтернатива, что по крайней мере на моем Python (3.5) работает довольно быстро, - это предустановить набор преобразователей, чтобы вы могли напрямую вызвать правильную функцию. Например:

words = ["1"] * 10 
converters = (int,) * 2 + (float,) * 8 

values = [f(v) for f, v in zip(converters, words)] 

Вы хотите проверить с обеими версиями zip чтобы увидеть, если list производящая версия генератора на основе itertools.izip быстрее (для коротких входов, как это, я действительно не могу сказать). В Python 3.5 (где zip всегда является генератором, например, Py2's itertools.izip), это заняло около 10% дольше, чем ваше самое быстрое решение для тех же самых входов (я использовал min() из timeit.repeat, а не ручную версию, которую вы использовали); это может быть лучше, если входы больше (и, следовательно, анализ будет стоить дороже).

Смежные вопросы