Столбец добавляется в фрейм данных с минимальным значением для каждого элемента только из столбцов, соответствующих словарю. Как добавить условие при вычислении минимального значения - если значения в выбранных столбцах больше значений в столбце «Col7»?
import pandas as pd
my_dict = {'Item1':['Col1','Col3','Col6'],
'Item2':['Col2','Col4','Col6','Col8']
}
df=pd.DataFrame({
'Col0':['Item1','Item2'],
'Col1':[20,25],
'Col2':[89,15],
'Col3':[36,30],
'Col4':[40,108],
'Col5':[55,2],
'Col6':[35,38],
'Col7':[30,20]
})
df['min']=df.apply(lambda r:r[[col for col in my_dict.get(r['Col0'], []) if col in r]].min(),axis=1)
Результат должен быть:
df=pd.DataFrame({
'Col0':['Item1','Item2'],
'Col1':[20,25],
'Col2':[89,15],
'Col3':[36,30],
'Col4':[40,108],
'Col5':[55,2],
'Col6':[35,38],
'Col7':[30,20],
'min':[35,38]
})
Нет, не все, а только из столбцов, соответствующих словарю для каждого элемента. Для элемента 1 — «Col1», «Col3», «Col6», для элемента 2 «Col2», «Col4», «Col6», «Col8» («Col8» не существует в df, и это нормально)






Следуя подходу, который вы применяете , ему требуется логическое индексирование (с gt):
df["min"]= (
df.apply(lambda r: r.reindex(my_dict[r["Col0"]])
.loc[lambda s: s.gt(r["Col7"])].min(), axis=1)
)
Выход :
Col0 Col1 Col2 Col3 Col4 Col5 Col6 Col7 min
0 Item1 20 89 36 40 55 35 30 35
1 Item2 25 15 30 108 2 38 20 38
[2 rows x 9 columns]
Рецепт будет довольно простым:
Col0 из my_dict.Col7.min этих отфильтрованных значений.Вышеупомянутое, выраженное в коде, может выглядеть так:
import pandas as pd
my_dict = {
'Item1': ['Col1', 'Col3', 'Col6'],
'Item2': ['Col2', 'Col4', 'Col6', 'Col8']
}
df = pd.DataFrame({
'Col0': ['Item1', 'Item2'],
'Col1': [20, 25],
'Col2': [89, 15],
'Col3': [36, 30],
'Col4': [40, 108],
'Col5': [55, 2],
'Col6': [35, 38],
'Col7': [30, 20]
})
# Adding the 'min' column by applying
# a function across each row
df['min'] = df.apply(lambda row: min([row[col] for col in my_dict.get(row['Col0'], []) if col in row and row[col] > row['Col7']]), axis=1)
print(df)
Не работает, если нет значений, удовлетворяющих условию, например. если условие >(row["Col7"]*1.2), возникнет ошибка: ValueError: min() arg — пустая последовательность
Как и в ответе Марцина, вы можете добавить and r[col] > r['Col7'] к своему состоянию после if col in r. Итак, эта строка будет выглядеть так:
df['min']=df.apply(lambda r:r[[col for col in my_dict.get(r['Col0'], []) if col in r and r[col] > r['Col7']]].min(),axis=1)
Большое спасибо! Есть ли способ получить имя минимального столбца? Я попытался добавить .astype(float).idxmin(),axis=1), но он говорит ValueError: попытайтесь получить argmin пустой последовательности
Вы заменили .min()? По коду, который ты сказал? Потому что это работает для меня. Столбец 'min' затем содержит имена столбцов с минимальным значением (то есть выше значения 'Col7'). Мой код: df['min']=df.apply(lambda r:r[[col for col in my_dict.get(r['Col0'], []) if col in r and r[col] > r['Col7']]].astype(float).idxmin(),axis=1)
Вы можете получить минимальное значение и имя столбца, адаптировав ответ, данный на ваш предыдущий вопрос, передав значение по умолчанию в min для случая, когда условие приводит к отсутствию соответствующих столбцов:
df[['min', 'name']] = df.apply(
lambda r:min(((r[col], col) for col in my_dict.get(r['Col0'], []) if col in r and r[col] > r['Col7']), default=(np.nan, '')),
axis=1, result_type='expand'
)
Вывод (для вашего образца данных):
Col0 Col1 Col2 Col3 Col4 Col5 Col6 Col7 min name
0 Item1 20 89 36 40 55 35 30 35 Col6
1 Item2 25 15 30 108 2 38 20 38 Col6
Если мы изменим условие на r[col] > r['Col7']*1.2, результат будет таким:
Col0 Col1 Col2 Col3 Col4 Col5 Col6 Col7 min name
0 Item1 20 89 36 40 55 35 30 NaN
1 Item2 25 15 30 108 2 38 20 38.0 Col6
Обратите внимание: я использовал NaN и '' в качестве значений по умолчанию, вместо них вы можете использовать все, что захотите.
@Евгения, не волнуйся, я рада, что смогла помочь
Я предполагаю, что в столбце
'min'вам нужно, чтобы минимальное значение из всех столбцов было больше, чем значение в'Col7'для этой строки, но не должно ли значение для второй строки быть 30 вместо 38? Поскольку'Col7'содержит значение 20 во второй строке.