Как сделать MinIFS в Python Dataframe

У меня есть фрейм данных с 7 столбцами. Я хочу создать 8-й столбец с выводом уравнения. Уравнение: из столбцов 2-7 для тех чисел, которые выше столбца 1, выведите минимальное значение в столбец 8.

В Excel я бы использовал эту формулу в Col8: =MINIFS($Col2:$Col7,$Col2:$Col7,">"&$Col1)

    Date_Time         Col1   Col2     Col3    Col4   Col5    Col6    Col7
20  3/14/2022 0:35  0.68053 0.68048 0.68094 0.6811  0.68111 0.68126 0.68179
21  3/14/2022 0:36  0.6805  0.6805  0.68091 0.68109 0.68111 0.68125 0.68178
22  3/14/2022 0:37  0.68052 0.68051 0.68089 0.68107 0.6811  0.68124 0.68177
23  3/14/2022 0:38  0.68057 0.6805  0.68086 0.68106 0.6811  0.68123 0.68176
24  3/14/2022 0:39  0.68055 0.6805  0.68083 0.68104 0.68109 0.68122 0.68175

Выход приведенного выше образца данных будет следующим:

Col8
0.68094
0.68091
0.68089
0.68086
0.68083

Я прочитал много сообщений и попробовал с np.where:

ColList = [Col2,Col3,Col4,Col5,Col6,Col7]
df['Col8'] = np.where(df[ColList ].min(axis=1) > df['Col1'],df[ColList ].min(axis=1),np.nan)

Но он находит минимальное число в списке, а затем проверяет, больше ли это минимальное число, чем Col1. Что я ищу, так это сделать это в обратном порядке: чтобы он смотрел только на числа, которые больше, чем Col1, и возвращал минимум из этих чисел (или возвращал np.nan, если нет чисел больше, чем Col1).

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

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
23
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

s = df[["Col1"]].values
tmp = df.loc[:, "Col2":] - s
tmp[tmp<=0] = np.inf
df["Col8"] = tmp.min(axis=1) + s.ravel()

Выход:

print(df["Col8"])

20    0.68094
21    0.68091
22    0.68089
23    0.68086
24    0.68083
Name: Col8, dtype: float64

Логика:

  1. Сначала мы вычисляем расстояние между Col1 и другими.
  2. Затем любые отрицательные расстояния (то есть те, которые меньше Col1) заменяются на numpy.inf, чтобы исключить минимальное сравнение.

Спектакль:

df = df.sample(n=100000, replace=True).reset_index(drop=True)

%%timeit

s = df[["Col1"]].values
tmp = df.loc[:, "Col2":] - s
tmp[tmp<=0] = np.inf
df["Col8"] = tmp.min(axis=1) + s.ravel()

# 13.1 ms ± 379 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Один из вариантов — сравнить в numpy, а затем использовать pd.where и min(axis=1), чтобы получить желаемый результат:

left = df.filter(regex=r"[2-7]")
right = df.Col1.to_numpy()[:, None]
booleans = left.to_numpy() > right
left.where(booleans).min(axis = 1)

    0.68094
    0.68091
    0.68089
    0.68086
    0.68083

Я не смог хорошо скопировать ваши данные (проблемы со столбцом даты), поэтому вывод серии.

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