Есть ли способ заполнить условия выбора np из фрейма данных?

Рассмотрим таблицу поиска, подобную этой:

   lower_bound upper_bound category
0       3          6         A
1       10         40        B
2       80         200       C
3       350        600       D
4       900        1500      E

Затем есть DataFrame элементов, которые нам нужно классифицировать на основе вышеуказанных условий:

    id    value
0  id_1     20
1  id_2    500
2  id_3   1000

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

    id   value  category
0  id_1    20       B
1  id_2    500      D
2  id_3    1000     E

Я пробовал следующее, что работает:

conditions = []
choices = []
for condition in lookup_df.to_dict('records'):
    conditions.append(
        (df['value'].between(condition['lower_bound'], condition['upper_bound']))
    )
    choices.append(condition['category'])

А потом:

df['category'] = np.select(conditions, choices, default=np.nan)

Есть ли способ сгенерировать условия без преобразования в dict и зацикливания поиска DataFrame?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
44
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете использовать пустую трансляцию. Идея состоит в том, чтобы создать логическую маску, которая возвращает True для диапазона, в который попадает каждое «значение» в lookup_df. Затем выберите совпадающие значения, используя логическое индексирование.

vals = df['value'].to_numpy()
msk = (lookup_df[['lower_bound']].to_numpy() < vals) & (vals < lookup_df[['upper_bound']].to_numpy())
df['category'] = lookup_df[['category']].to_numpy().repeat(len(df), axis=1)[msk]

Выход:

     id  value category
0  id_1     20        B
1  id_2    500        D
2  id_3   1000        E

Если вам нужны значения NaN для значений, выходящих за пределы любого диапазона, здесь лучше всего подойдет dot product (это точно так же, как @Корралиен решение):

vals = df[['value']].to_numpy()
msk = (lookup_df['lower_bound'].to_numpy() < vals) & (vals < lookup_df['upper_bound'].to_numpy())
df = df.assign(category=msk.dot(lookup_df['category'])).replace('', float('nan'))

Мне очень нравится этот подход. Однако один вопрос: что произойдет, если элемент не может быть классифицирован (т. е. не находится между какими-либо границами)? Я думаю, что это было бы опущено вместо того, чтобы присвоить категорию nan или что-то в этом роде.

ttsak 10.05.2022 10:11

@ Этелом Это верно. В этом случае лучше всего подойдет np.dot.

user7864386 10.05.2022 10:55

Вы можете использовать pd.merge_asof:

output = pd.merge_asof(df, lookup_df[["lower_bound","category"]], left_on = "value", right_on = "lower_bound").drop("lower_bound", axis=1)

>>> output
     id  value category
0  id_1     20        B
1  id_2    500        D
2  id_3   1000        E
Ответ принят как подходящий

Вы можете использовать np.dot:

vals = np.vstack(df['value'].values)
lb = condition['lower_bound'].values <= vals
ub = vals <= condition['upper_bound'].values
df['category'] = np.dot(lb & ub, condition['category'])

Выход:

я быценностькатегория
id_120Б
id_2500Д
id_31000Е
dot очень красиво; рад снова тебя видеть :-)
user7864386 09.05.2022 22:14

Другие вопросы по теме