Nano Hash - криптовалюты, майнинг, программирование

Эффективный способ найти минимальное и максимальное значение изменяющегося набора в python

Мне нужно найти минимальное/максимальное значение в изменяющемся большом наборе, в С++ это может быть

#include<set>
using namespace std;
int minVal(set<int> & mySet){
    return *mySet.begin();
}
int maxVal(set<int> & mySet){
    return *mySet.rbegin();
}
int main(){
    set <int> mySet;
    for(..;..;..){
       // add or delete element in mySet
       ...
       // print the min and max value in the set
       printf("%d %d\n", minVal(mySet), maxVal(mySet)); 
    }
}

В C++ каждая операция запроса выполняется за O(1), но в python я пытался использовать встроенные методы min и max, но они слишком медленные. Каждая минимальная/максимальная операция занимает время O(n) (n - длина моего набора). Есть ли какой-нибудь элегантный и эффективный способ сделать это? Или любой тип данных поддерживает эту операцию?

mySet=set()
for i in range(..):
  # add or delete element in mySet
  ...
  # print the min and max value in the set
  print(min(mySet),max(mySet))
10.01.2014

  • Постарайтесь отсортировать список. С исходным списком используйте алгоритм быстрой сортировки, чтобы отсортировать его. Затем каждый раз, когда вы добавляете или удаляете, убедитесь, что он находится в правильном месте в списке. Тогда ваши минимальные и максимальные значения могут быть просто проиндексированы с любого конца. 10.01.2014
  • Как насчет использования heapq. 10.01.2014
  • Набор Python неупорядочен, поэтому вам придется каждый раз сканировать весь набор. Возможно, вы хотели вместо этого использовать кучу min-max? 10.01.2014
  • @falsetru: heapq дает вам минимальную кучу или максимальную кучу, но не минимальную кучу. 10.01.2014
  • @MartijnPieters, да, это так. OP может потребоваться два объекта heapq. один с исходными значениями, один с отрицательными значениями. 10.01.2014
  • @falsetru: существует такая вещь, как куча min-max, которую легко достаточно реализовать на Python. 10.01.2014
  • @MartijnPieters, спасибо за ссылки. 10.01.2014
  • это обязательно должен быть набор? похоже, что реализация любого вида двоичного дерева удлинит поиск O (1) (больше похоже на O (log n) для двоичного дерева). при этом оптимизации Python будут другими... если begin() в С++ всегда является наименьшим элементом, то они сортируются по присваиванию, что по крайней мере является операцией O (log n). в питоне это просто хешируется и (обычно) O (1). 10.01.2014
  • Кстати, реализация древовидных структур данных в Python на практике совсем не быстрая, даже если так говорит анализ сложности. Имейте в виду, что все нативные структуры данных, предоставляемые стандартными библиотеками, реализованы на C. 10.01.2014
  • @falsetru Позволит ли heapq удалить элемент не сверху? (Я не могу найти какой-либо метод для этого в документации.) 10.01.2014

Ответы:


1

Эффективной реализацией с точки зрения сложности является обертка python set (который использует хэш-таблицу) и сохранение пары атрибутов maxElement и minElement в объекте и их соответствующее обновление при добавлении или удалении элементов. Это сохраняет каждый запрос существования, минимум и максимум O (1). Однако операция удаления будет O(n) в худшем случае с простейшей реализацией (поскольку вам нужно найти следующий за минимальным элемент, если вам случится удалить минимальный элемент, и то же самое происходит с максимальным).

При этом реализация C++ использует сбалансированное дерево поиска, которое имеет O(log n) проверок существования, операций удаления и вставки. Вы можете найти реализацию этого типа структуры данных в пакете bintrees.

Я бы не стал использовать только heapq, как это предлагается в комментариях, поскольку куча - это O (n) для проверки существования элементов (я думаю, основная точка установленной структуры данных, которая, как я полагаю, вам нужна).

10.01.2014
  • Пакет bintrees устарел. Вместо этого используйте sortedcontainers. Ищите мой ответ для более подробной информации. 02.03.2020
  • heapq подходит для быстрого нахождения минимума, но не максимума набора. 23.12.2020

  • 2

    Вы можете использовать две очереди приоритетов для поддержания минимального и максимального значений в наборе соответственно. К сожалению, heapq библиотеки stdlib не поддерживает удаление записей из очередь в O(log n) раза из коробки. Предлагаемый обходной путь — просто пометить записи как удаленные и отбрасывать их, когда вы выталкиваете их из очереди (хотя во многих сценариях это может быть нормально). Ниже приведен класс Python, реализующий этот подход:

    from heapq import heappop, heappush
    
    class MinMaxSet:
        def __init__(self):
            self.min_queue = []
            self.max_queue = []
            self.entries = {}  # mapping of values to entries in the queue
    
        def __len__(self):
            return len(self.entries)
    
        def add(self, val):
            if val not in self.entries:
                entry_min = [val, False]
                entry_max = [-val, False]
    
                heappush(self.min_queue, entry_min)
                heappush(self.max_queue, entry_max)
    
                self.entries[val] = entry_min, entry_max
    
        def delete(self, val):
            if val in self.entries:
                entry_min, entry_max = self.entries.pop(val)
                entry_min[-1] = entry_max[-1] = True  # deleted
    
        def get_min(self):
            while self.min_queue[0][-1]:
                heappop(self.min_queue)
            return self.min_queue[0][0]
    
        def get_max(self):
            while self.max_queue[0][-1]:
                heappop(self.max_queue)
            return -self.max_queue[0][0]
    

    Демо:

    >>> s = MinMaxSet()
    >>> for x in [1, 5, 10, 14, 11, 14, 15, 2]:
    ...     s.add(x)
    ... 
    >>> len(s)
    7
    >>> print(s.get_min(), s.get_max())
    1 15
    >>> s.delete(1)
    >>> s.delete(15)
    >>> print(s.get_min(), s.get_max())
    2 14
    
    08.08.2019

    3

    С 2020 года bintrees пакетов устарели и должны быть заменены на sortedcontainers.

    Пример использования:

    import sortedcontainers
    
    s = sortedcontainers.SortedList()
    s.add(10)
    s.add(3)
    s.add(25)
    s.add(8)
    min = s[0]      # read min value
    min = s.pop(0)  # read and remove min value
    max = s[-1]     # read max value
    max = s.pop()   # read and remove max value
    

    Помимо SortedList у вас также есть SortedDict и SortedSet. Вот документация по API.

    01.03.2020

    4

    numpy min max в два раза быстрее собственного метода

    import time as t
    import numpy as np
    
    def initialize():
        storage.reset()
    
    def tick():
    
        array = data.btc_usd.period(250, 'close')
    
        t1 = t.time()
    
        a = min(array)
        b = max(array)
    
        t2 = t.time()
    
        c = np.min(array)
        d = np.max(array)
    
        t3 = t.time()
    
        storage.t1 = storage.get('t1', 0)
        storage.t2 = storage.get('t2', 0)
        storage.t1 += t2-t1
        storage.t2 += t3-t2
    
    
    def stop():
    
        log('python: %.5f' % storage.t1)
        log('numpy: %.5f' % storage.t2)
        log('ticks: %s' % info.tick)
    

    урожаи:

    [2015-11-06 10:00:00] python: 0.45959
    [2015-11-06 10:00:00] numpy: 0.26148
    [2015-11-06 10:00:00] ticks: 7426
    

    но я думаю, что вы ищете что-то вроде этого:

    import time as t
    import numpy as np
    
    def initialize():
        storage.reset()
    
    def tick():
    
        storage.closes = storage.get('closes', [])
        if info.tick == 0:
            storage.closes = [float(x) for x in data.btc_usd.period(250, 'close')]
        else:
            z = storage.closes.pop(0) #pop left
            price = float(data.btc_usd.close)
            storage.closes.append(price) #append right
        array = np.array(storage.closes)[-250:]
    
        # now we know 'z' just left the list and 'price' just entered
        # otherwise the array is the same as the previous example
    
        t1 = t.time()
        # PYTHON METHOD
        a = min(array)
        b = max(array)
    
        t2 = t.time()
        # NUMPY METHOD
        c = np.min(array)
        d = np.max(array)
    
        t3 = t.time()
        # STORAGE METHOD
        storage.e = storage.get('e', 0)
        storage.f = storage.get('f', 0)
        if info.tick == 0:
            storage.e = np.min(array)
            storage.f = np.max(array)
        else:
            if z == storage.e:
                storage.e = np.min(array)
            if z == storage.f:
                storage.f = np.max(array)
            if price < storage.e:
                storage.e = price
            if price > storage.f:
                storage.f = price
    
        t4 = t.time()
    
        storage.t1 = storage.get('t1', 0)
        storage.t2 = storage.get('t2', 0)
        storage.t3 = storage.get('t3', 0)    
        storage.t1 += t2-t1
        storage.t2 += t3-t2
        storage.t3 += t4-t3
    
    
    def stop():
    
        log('python: %.5f'  % storage.t1)
        log('numpy: %.5f'   % storage.t2)
        log('storage: %.5f' % storage.t3)
        log('ticks: %s'     % info.tick)
    

    урожаи:

    [2015-11-06 10:00:00] python: 0.45694
    [2015-11-06 10:00:00] numpy: 0.23580
    [2015-11-06 10:00:00] storage: 0.16870
    [2015-11-06 10:00:00] ticks: 7426
    

    что приводит нас примерно к 1/3 нативного метода с 7500 итерациями против списка из 250

    06.11.2015
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..