Найти корзину, куда лучше всего подходят данные - PullRequest
2 голосов
/ 07 февраля 2020

Я пытаюсь написать функцию get_best_bin, которая помещает значение в наиболее подходящую ячейку:

У меня есть ячейка, представляющая собой список (начало, конец) значений.

def get_best_bin(value, bins):
    return index of bins that the value fits best into. 

Например,

bins = [
 (0.0, 0.5),
 (0.5, 1.5),
 (1.5, 3.0),
 (4.5, 5.5)
]

value = [0.4,1.0]

И поэтому

get_best_bin(value, bins)

вернет:

1

, поскольку большая часть строки в [0.4,1.0] принадлежит мусорное ведро (0.5, 1.5). * Примечание: Даже если есть небольшое пересечение с корзиной (0.0, 0.5), большая часть пересечения находится в (0.5, 1.5)*

Пока это то, что я пробовал, но я могу получить только возможное бины, где существует пересечение:

possible_bins = set()
for ind,width in enumerate(bins):
    if width[0] <= value[0] <= width[1]:
        possible_bins.add(width)
    if width[0] <= value[1] <= width[1]:
        possible_bins.add(width)
print(possible_bins)

#{(0.0, 0.5), (0.5, 1.5)}

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

Ответы [ 4 ]

4 голосов
/ 07 февраля 2020

Вы можете сделать что-то вроде:

def get_best_bin(value, bins):
    intesections = [min(value[1], b[1]) - max(value[0], b[0]) for b in bins]
    return intesections.index(max(intesections))

Объяснение:

Если есть пересечение, пересечение начинается с max(value[0], b[0]) и заканчивается min(value[1], b[1]). таким образом, длина пересечения составляет end - start, что означает min(value[1], b[1]) - max(value[0], b[0]).

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

1 голос
/ 07 февраля 2020

Я бы решил эту проблему немного по-другому.

У вас есть много корзин (допустим, они не отсортированы).

bins = [
  (0.0, 0.5),
  (0.5, 1.5),
  (1.5, 3.0),
  (4.5, 5.5)
  ]

Вы получите новое значение, которое должно правильно классифицируется как специфицированный c bin.

 value = (0.4, 1.0)

Обратите внимание, что я бы использовал кортеж, а не список для значения. Это больше соответствует вашему представлению бинов и гарантирует, что значение является неизменным.

Ваше решение вернет все бины, в которых это значение (хотя бы частично) содержится. Это хорошее начало!

Чтобы выбрать лучший бин, мы можем оценить ситуацию по многим различным аспектам.

Как вы написали в комментарии:

[лучший бин равен], если большинство диапазон значений пересекается с корзиной. Однако мы не знаем, что делать, если многие из наших корзин состоят из равных частей стоимости. Предполагая, что вы хотите первую ячейку из них:

def get_first_best_bin(value, bins):
    best_bin = None
    best_quality = 0
    # Iterate on all bins, Changed name width to bin to be consistent in naming
    for ind, bin in enumerate(bins):
        # we need to do evaluation only if value is contained at least partly in current bin
        # basically I made one-liner of your 2 ifs
        if bin[0] <= value[0] <= bin[1] or bin[0] <= value[1] <= bin[1]:
            # If value starts before bin we want edge of bin
            # otherwise value starts somewhere in bin so we calculate from value's start
            start = max(bin[0], value[0])

            # If value ends in bin we want to count up to its end
            # otherwise we take edge of bin
            fin = min(bin[1], value[1])
            # lets check if fit-quality is better now than previous best and choose current bin as best one so far
            if best_quality < fin - start:
                best_bin = bin
    return best_bin

Если вы предпочитаете последний лучший вариант, вы должны использовать это выражение if best_quality <= fin - start.

Аналогично вы можете выбрать best bin как bin, которая в основном заполнена значением. Просто измените выражение на if best_quality < (fin - start)/(bin[1] - bin[0]).

Помните, что если ваше значение не содержится ни в одном из этих столбцов, результатом будет None.

1 голос
/ 07 февраля 2020

Я получил это для работы с этим, я не могу быть лучшим способом, и это не написано как функция:

bins = [
 (0.0, 0.5),
 (0.5, 1.5),
 (1.5, 3.0),
 (4.5, 5.5)
]

value = [0.4,1.0]
intersections = []
for x in bins:
    lower = None
    higher = None
    if value[0]<x[1] and value[1]>x[0]:
        lower = x[0] if value[0]<x[0] else value[0]
        higher = x[1] if value[1]>x[1] else value[1]
    else:
        continue
    intersections.append(higher-lower)
bestBin = bins[intersections.index(max(intersections))]
1 голос
/ 07 февраля 2020

Следующий метод должен выполнить эту работу. Он основан на средних значениях. Однако, если вы хотите иметь более сложные правила выбора, чем просто расстояние L1, его нужно изменить.

import numpy as np

def get_best_bin(value, bins):
    ''' Computes the centers of the bins and checks to which the average value is the closest '''
    return np.argmin(np.absolute(np.mean(bins, 1) - np.mean(value)))

bins = [
 (0.0, 0.5),
 (0.5, 1.5),
 (1.5, 3.0),
 (4.5, 5.5)
]
value = [0.4,1.0]

get_best_bin(value, bins) # returns 1 for the given data
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...