В науке данных часто нужно объединить непрерывные данные, чтобы обобщать шумные наблюдения. Гистограммы – главный пример биннинга данных, что позволяет вам быстро идентифицировать шаблоны в данных.
Особенности того, как одна группа эти банки могут варьироваться. Для случаев, когда вы просто используете центральные значения, чтобы быть потокарными/напольными, я придумал элегантное и перспективное решение с использованием модели данных контейнеров Python.
Контейнеры – это объекты, которые хранят вещи и используют квадратные скобки []
Обозначение для доступа:
- Элементы списка
my_list
можно получить доступ и модифицировать через индексЯ
сmy_list [я]
утверждение. - Значения словаря
my_dict
Доступ к доступу и доступен и mofied через ключк
сmy_dict [k]
утверждение. Я создал пользовательский тип контейнераBins
в абстрактные банкины данных. Элементы банки данныхmy_bins
Доступ к доступу и модифицировано через любой Настоящее числоn
сmy_bins [n]
Отказ Еслиn
не является фактическим ключомmy_bins
Затем он будет округлен до ближайшего фактического ключа.
Bins
инициализируется с нужными интервалами. Каждый интервал по существу является ключом, соединенным с количеством, где количество начинается в 0.
>>> bins = Bins([-6, -3, 0, 3, 6]) >>> bins {-6: 0, -3: 0, 0: 0, 3: 0, 6: 0} >>> bins[3] += 1 # n = 3 >>> bins {-6: 0, -3: 0, 0: 0, 3: 1, 6: 0} >>> bins[7] += 1 # n = 6 >>> bins[11] += 1 # n = 6 >>> bins[6.5] += 1 # n = 6 >>> bins {-6: 0, -3: 0, 0: 0, 3: 1, 6: 3} >>> bins[-1000000] += 1 # n = -6 >>> bins {-6: 1, -3: 0, 0: 0, 3: 1, 6: 3} >>> bins[0.5] += 1 # n = 0 >>> bins {-6: 1, -3: 0, 0: 1, 3: 1, 6: 3}
Как вы можете видеть, это чувствует себя ужасно, как словарь-инфакт, Bins
наследует абстрактный базовый класс Mutablappapping
Чтобы отразить интерфейс, который можно ожидать от Дикт
Отказ Минимальный подкласс потребует переопределения следующих методов.
class Bins(MutableMapping): def __init__(self, *args, **kwargs): ... def __getitem__(self, key): ... def __setitem__(self, key, value): ... def __delitem__(self, key): ... def __iter__(self): ... def __len__(self): ...
Сначала мы хотим инициализировать Bins
с нужными интервалами. Мы можем сохранить это как во внутреннем диктоме, который будет держать содержимое Bins
Отказ
def __init__(self, intervals): empty_bins = {interval: 0 for interval in intervals} self._dict = empty_bins
__GetItem __ ()
и __setitem __ ()
Методы определяют поведение использования квадратных кронштейнов []
Обозначение. Мы хотим пересекать ключ
И закруглить его до ближайшего интервала, перед применением допустимого ключа (интервал) на наш внутренний словарь.
def __getitem__(self, key): interval = self._roundkey(key) return self._dict[interval] def __setitem__(self, key, value): interval = self._roundkey(key) self._dict[interval] = value def _roundkey(self, key): intervals = list(self._dict.keys()) minkey = intervals[0] midkeys = intervals[1:-1] maxkey = intervals[-1] if key <= minkey: return minkey elif key >= maxkey: return maxkey elif key in midkeys: return key else: i = bisect_left(intervals, key) leftkey = intervals[i - 1] rightkey = intervals[i] if abs(leftkey - key) < abs(rightkey - key): return leftkey else: return rightkey
Как видите, метод _roundkey ()
раунды ключ
к ближайшему интервалу. Мы проверяем ли ключ
Первый промежуток времени, прежде чем использовать Python’s bisect_left
Чтобы найти интервалы потока и полов относительно ключ
и вернуть ближайший.
И что нам нужно сделать, чтобы добывать нефтяные операторы, такие как + =
работающий? Ничего! Все, что они делают, это получение значения из прошедшего ключа через __GetItem __ ()
, применяя операцию для значения, и присвоение нового значения ключению через __setitem __ ()
Отказ
Так что, если у вас тоже есть __delitem __ ()
, __iter __ ()
и __лен __ ()
напрямую интерфейс с Self._dict.
у тебя будет работать Bins
вашего собственного!
Производственная готовность
Но я не совсем доволен этим. В первую очередь, если мы пройдем интервалы, которые не являются заказа, то мы полностью привернули, как _roundkey ()
Работает в нахождении ближайшего интервала. Мы может Просто сортируйте интервалы сами по инициализации.
def __init__(self, intervals): empty_bins = {interval: 0 for interval in sorted(intervals)} self._dict = empty_bins
Перед Python 3.7 это не будет идеально, поскольку словари не гарантируют заказа ввода. Однако они делают, однако мы все еще можем оказаться неупорядоченным Self._dict.
Если кто-то использовал Обновление ()
метод. Я не могу предшествовать ситуации, которую кто-то захочет сделать это, но Обновление ()
Используется в сериализации данных и в любого выставленности Mutablappapping
Так что это хорошая идея, чтобы обновить наш внутренний порядок словаря.
К счастью, у нас есть Сортируется
от SortedContainers
Пакет Который будет Гунтинте на ключах словаря всегда будут отсортированы.
def __init__(self, intervals): empty_bins = {interval: 0 for interval in intervals} self._sdict = SortedDict(empty_bins)
Мы также можем кэшировать _roundkey ()
результат часто пропущенных ключей. Я нашел в некоторых ситуациях, которые я использовал Bins
В алгоритме это могло значительно улучшить производительность, как округление плавать
-тип ключ к интервалу немного дорого, но точно такой же ключ пропускается регулярно.
Питона @lru_cache ()
Декоратор делает это просто для реализации. Вы можете просто попнуть его на функцию с помощью hashable аргументов, и это будет использовать LRU кэш хранить результаты частое функции вызовы
Поскольку акт ключей округления заинтересован только в Интервалы Bins
Я создал метод UTIL (экземпляр-агностик), который принимает только интервалы и переданный ключ, чтобы найти ближайший интервал и удобно завернуть _roundkey ()
Отказ
class Bins(MutableMapping): ... @property def intervals(self): return tuple(self._sdict.keys()) def _roundkey(self, key): return find_closest_interval(self.intervals, key) ... @lru_cache() def find_closest_interval(intervals, key): minkey = intervals[0] midkeys = intervals[1:-1] maxkey = intervals[-1] if key <= minkey: return minkey elif key >= maxkey: return maxkey elif key in midkeys: return key else: i = bisect_left(intervals, key) leftkey = intervals[i - 1] rightkey = intervals[i] if abs(leftkey - key) < abs(rightkey - key): return leftkey else: return rightkey
Плавник
Я надеюсь, что вы научились сегодня или две вещи, и, возможно, даже иметь новый инструмент в вашем рабочем состоянии данных.
Я выставил Bins
Реализация, которую я использовал в моей библиотеке тестирования случайности Coinflip , доступно в Coinflip.Collions. Bins
пространство имен. Я верю, что это готово к производству, но, возможно, есть причуды, которые я еще предстоит столкнуться и тестировать! Исходный код доступен на Github ( Испытания тоже).
Действительно прохладный проект будет реализовывать интервальные диапазоны, чтобы биннинг не должен положиться на «центральные значения». Это может быть достигнуто очень хорошо с Ломтики (например obj [a: b: c]
синтаксис) – это не беспрецедентно, как Пандас Использует ломтики для выражения операций довольно красиво.
Для любых любителей Raymond Hettinger вы узнаете, что каждый трюк и инструмент, который я использую здесь, был сильно под влиянием него. Спасибо также redditore levenphonons для того, чтобы дать мне большие отзывы!
Оригинал: “https://dev.to/honno/simplify-data-binning-with-a-custom-dict-28i5”