Рубрики
Без рубрики

Визуализация алгоритма забега в Python

В этой статье будет рассмотрено, как вы можете использовать библиотеки визуализации и программное обеспечение для определения времени выполнения … Теги с питоном, наукой данных, алгоритмами, информатикой.

В этой статье будет рассмотрено, как вы можете использовать библиотеки визуализации и программное обеспечение для определения сложностей среды для разных алгоритмов. Мы рассмотрим основное использование matplotlib Для визуализации двухмерных участков и Numpy Для вычисления линий наилучшего соответствия, а затем рассказать о том, как эти библиотеки можно использовать для определения их сложности времени выполнения либо через «угадание», либо путем сравнения графиков их времени выполнения с известными функциями (т.е. y =x , y = 2^n )

Если вы заинтересованы в загрузке кода, представленного в этой статье, пожалуйста, посетите Этот репозиторий на моем GitHub (Chroline/VisuizationRuntimes).

Сложность времени выполнения, более конкретно сложность времени выполнения Анализ , это измерение того, как «быстрый» может работать алгоритм как объем операций, которые он требует, увеличивается. Прежде чем мы погрузимся в визуализацию времени пробега разных алгоритмов, давайте посмотрим на пару основных примеров, чтобы объяснить концепцию.

Возьмите следующее Добавить функция Он принимает два параметра, A и b и выполняет дополнение на A и b Анкет

def add(a, b):
    return a + b

При предоставлении любых двух параметров (1 и 2, 2 и 3, 29347 и 93648) количество операций не изменяется. Поэтому мы говорим, что алгоритм работает в постоянной или O (1) , время.

Однако теперь рассмотрим следующее перестановки функция Он принимает один основной параметр, строка и печатает все перестановки этой строки.

def permutations(string, step = 0):
    if step == len(string):
        print "".join(string)
     for i in range(step, len(string)):
        string_copy = [c for c in string]
        string_copy[step], string_copy[i] =string_copy[i], string_copy[step]
        permutations(string_copy, step + 1)

Как вы могли себе представить, эта функция займет гораздо больше времени, чем предыдущая Добавить функция; На самом деле, эта функция будет работать в так называемом Фактор Время, представленное как На!) . Это потому, что как количество символов в строка увеличивается, объем операций, необходимых для поиска всех перестановки, увеличивается факторно.

Сравнивая время выполнения двух функций визуально, вы заметите резкий контраст на графиках, которые они производят. Для Добавить Функция, вы бы соблюдали плоскую линию, так как вход функции не влияет на объем операций, требуемых функцией. Однако для перестановки Функция, вы бы соблюдали линию, которая резко всплывает вверх (наклон линии приблизится к бесконечности), потому что объем операций увеличивается факторно с увеличением размера входа.

Теперь, когда мы рассмотрели основы анализа сложности времени выполнения, мы можем начать процесс написания кода, чтобы визуализировать время выполнения различных алгоритмов.

Перед запуском каких -либо визуализаций мы должны сначала импортировать необходимые библиотеки и инициализировать их.

  • matplotlib библиотека, которая будет создавать и отображать графики
  • Numpy библиотека, которая состоит из многочисленных математических функций
  • Timeit это библиотека, которую мы будем использовать во времени, как долго каждый звонок в алгоритм принимает
  • Математика Основная библиотека математики Python
  • случайный Основная библиотека рандомизации Python
import matplotlib.pyplot as plt
import numpy as np
import timeit
import math
import random

plt.rcParams['figure.figsize'] = [10, 6] # set size of plot

Ниже приведены некоторые сегменты кода, которые демонстрируют, как использовать matplotlib и Numpy Анкет

Сумма функция

Питон сумма Функция вычисляет сумму всех элементов предоставленного Итерабильный Анкет Эта функция реализует алгоритм с O (n) Сложность времени выполнения.

Чтобы проверить это, мы будем использовать Linspace Метод из Numpy Библиотека для создания итерабильных с 50 равномерно распределенными значениями в диапазоне от 10 до 10 000. График, хотя и не совершенно прямой сюжет, иллюстрирует это.

ns = np.linspace(10, 10_000, 50, dtype=int)
ts = [timeit.timeit('sum(range({}))'.format(n), number=100)
      for n in ns]

plt.plot(ns, ts, 'or')

Мы можем добавить линию наилучшего соответствия (с помощью функции 4-й степени), чтобы дополнительно иллюстрировать это. График никогда не будет совершенно прямой, но он должен приблизиться.

degree = 4
coeffs = np.polyfit(ns, ts, degree)
p = np.poly1d(coeffs)
plt.plot(ns, ts,'or')
plt.plot(ns, [p(n)for nin ns],'-b')

Список индексации

Получение элемента из списка (индексация списка) работает с O (1) Сложность времени выполнения, что означает, что количество элементов в списке не влияет на то, как долго требуется алгоритм. Как это представлено в графике?

lst = list(range(1_000_000))
ns = np.linspace(0, len(lst), 1000, endpoint=False, dtype=int)
ts = [timeit.timeit('_ = lst[{}]'.format(n),
                    globals=globals(),
                    number=10000)
for nin ns]

plt.plot(ns, ts,'or')

degree = 4
coeffs = np.polyfit(ns, ts, degree)
p = np.poly1d(coeffs)
plt.plot(ns, [p(n)for nin ns],'-b')

Теперь мы рассмотрим графики, созданные следующими алгоритмами:

  • Линейный поиск
  • Бинарный поиск
  • вставка сортировки

Линейный поиск

Линейный поиск имеет сложность времени выполнения O (n) , который будет представлен приблизительно прямой линией.

Красные сюжеты Продемонстрировать поиск элемента в перетасованном, Синие сюжеты Продемонстрировать поиск элемента, которого нет в списке.

Линия, наиболее подходящая для красных участков, обычно будет меньше, чем у синих графиков, потому что поиск элемента, которого нет в списке требует итерации по всему списку.

## searches for an item in a list
def contains(lst, x):
    for y in lst:
        if x == y: return True
    return False

ns = np.linspace(10, 10_000, 100, dtype=int)

# red plots
ts = [timeit.timeit('contains(lst, 0)', 
                    setup='lst=list(range({})); random.shuffle(lst)'.format(n),
                    globals=globals(),
                    number=100)
      for n in ns]
plt.plot(ns, ts, 'or')

# line of best fit for red plots
degree = 4
coeffs = np.polyfit(ns, ts, degree)
p = np.poly1d(coeffs)
plt.plot(ns, [p(n) for n in ns], '-r')

# blue plots
ts = [timeit.timeit('contains(lst, -1)', 
                    setup='lst=list(range({}))'.format(n),
                    globals=globals(),
                    number=100)
      for n in ns]
plt.plot(ns, ts, 'ob')

# line of best fit for blue plots
degree = 4
coeffs = np.polyfit(ns, ts, degree)
p = np.poly1d(coeffs)
plt.plot(ns, [p(n) for n in ns], '-b')

Бинарный поиск

Бинарный поиск работает с O (log n) Сложность времени выполнения.

# searches for an item in a list using linear search
def contains(lst, x):
    lo = 0
    hi = len(lst)-1
    while lo <= hi:
        mid = (lo + hi) // 2
        if x < lst[mid]:
            hi = mid - 1
        elif x > lst[mid]:
            lo = mid + 1
        else:
            return True
    else:
        return False

ns = np.linspace(10, 10_000, 100, dtype=int)
ts = [timeit.timeit('contains(lst, 0)', 
                    setup='lst=list(range({}))'.format(n),
                    globals=globals(),
                    number=1000)
      for n in ns]

plt.plot(ns, ts, 'or')

degree = 4
coeffs = np.polyfit(ns, ts, degree)
p = np.poly1d(coeffs)
plt.plot(ns, [p(n) for n in ns], '-b')

Выше это то, как должен выглядеть график в почти идеальном моделировании. Как видите, есть некоторые выбросы, и в идеальном симуляции линия наилучшего соответствия будет идентична логарифмической функции.

Вставка сортировки

Какая сложность времени выполнения имеет сортирование вставки? Мы можем использовать графики его времени выполнения и сравнить эти графики с графиками известных времен пробежки, чтобы определить, какое самое близкое совпадение.

def insertion_sort(lst):
    for i in range(1, len(lst)):
        for j in range(i, 0, -1):
            if lst[j-1] > lst[j]:
                lst[j-1], lst[j] = lst[j], lst[j-1]
            else:
                break

# 15 values
ns = np.linspace(100, 2000, 15, dtype=int)
ts = [timeit.timeit('insertion_sort(lst)',
                    setup='lst=list(range({})); random.shuffle(lst)'.format(n),
                    globals=globals(),
                    number=1)
         for n in ns]
plt.plot(ns, ts, 'or');

degree = 4
coeffs = np.polyfit(ns, ts, degree)
p = np.poly1d(coeffs)
plt.plot(ns, [p(n) for n in ns], '-r')

Теперь мы можем сравнить этот график с графиками различных времен пробежки, чтобы в конечном итоге определить, что наиболее схоже и каким есть сортировка сложности выполнения.

Красные сюжеты Представляю O (log n) , Синие сюжеты Представляю O (n^2) , Зеленые сюжеты Представляю O (2^n) Анкет

# y = log x
# vertically stretched 1000x
ns = range(1, 100)
ts = [math.log(n, 2) * 1000 for n in ns]
plt.plot(ns, ts, 'or');

# y = x^2
ns = range(1, 100)
ts = [(n*n) for n in ns]
plt.plot(ns, ts, 'ob');


# y = 2^x
# vertically stretched 20x
# horizontally compressed 1x
ns = range(1, 10)
ts = [math.pow(2, n)*20 for n in ns]
plt.plot(ns, ts, 'og');

Основываясь на этих графиках, можно с уверенностью предположить, что вставка сортируется в O (n^2) время.

Можем ли мы использовать визуализацию времени загадочных функций, чтобы угадать их сложности времени выполнения?

Тайная функция № 1

def f(l: list, val): # l is a python list with n items
  d = {}
  for i in range(len(l)):
    d[l[i]] = i
  return d[val]

ns = range(5, 2000)
ts = [timeit.timeit('f(lst, {})'.format(n-1),
                    setup='lst=list(range({})); random.shuffle(lst)'.format(n),
                    globals=globals(),
                    number=1)
         for n in ns]
plt.plot(ns, ts, 'or');

degree = 4
coeffs = np.polyfit(ns, ts, degree)
p = np.poly1d(coeffs)
plt.plot(ns, [p(n) for n in ns], '-b')

Даже не сравнивая этот график с графиками возможного времени выполнения, мы уже можем с уверенностью предположить, что эта функция работает в На) время выполнения.

Тайная функция № 2

def g(l): # l is a python list of integers of length n
  pairs = [ (i,j) for i in range(len(l)) for j in range(len(l)) if i < j ]
  result = []
  for (i,j) in pairs:
    if l[i] == l[j]:
      result.append((i,j))
  return result

ns = range(5, 200)
ts = [timeit.timeit('g(lst)',
                    setup='lst=list(range({}))'.format(n),
                    globals=globals(),
                    number=1)
         for n in ns]
plt.plot(ns, ts, 'or')

degree = 4
coeffs = np.polyfit(ns, ts, degree)
p = np.poly1d(coeffs)
plt.plot(ns, [p(n) for n in ns], '-b')

Этот график выглядит очень похоже на тот, который для вставки, поэтому мы можем определить, что эта функция имеет сложность времени выполнения O (n^2) Анкет

Тайная функция № 3

def h(n):
   if n <= 1:
       return n
   else:
       return h(n-1) + h(n-2)

ns = range(5, 30)
ts = [timeit.timeit('h({})'.format(n),
                    globals=globals(),
                    number=1)
         for n in ns]
plt.plot(ns, ts, 'or')

Эта функция более неоднозначна, чем предыдущие два. Очевидно, что его время выполнения должно быть больше, чем На) По мере увеличения наклона как n увеличивается. Давайте рассмотрим графики Runtime O (n^2) в красный и O (2^n) в синий Анкет

# y = n^2
# vertically stretched 20x
ns = range(5, 30)
ts = [n*n*20000 for n in ns]
plt.plot(ns, ts, 'or')

# y = 2^n
# vertically compressed 50x
ns = range(5, 30)
ts = [math.pow(2, n)/50 for n in ns]
plt.plot(ns, ts, 'ob')

График времени выполнения таинственной функции № 3 больше напоминает синие графики, поэтому, следовательно, сложность времени выполнения таинственной функции № 3 – O (2^n) Анкет

Используя эти библиотеки визуализации, мы можем определить сложности времени выполнения функций и алгоритмов, сравнивая их с графиками/графиками известного времени выполнения (то есть, сравнивая графики внедрения сортировки сортировки с y = n^2 ). В дополнение к определению сложности выполнения, эта методология может быть использована для сравнения скоростей разных алгоритмов друг с другом. Имея всего несколько строк кода, вы можете быстро увидеть скорость, с которой выбранные вами алгоритмы будут работать с большими наборами данных!

Оригинал: “https://dev.to/chroline/visualizing-algorithm-runtimes-in-python-f92”