Как выполнить операцию с двумя столбцами в одном и том же фрейме данных в Python Pandas?

#python #pandas #dataframe #lambda #apply

Вопрос:

Я пытаюсь применить операцию 'x-y/y' , являющуюся x столбцом 'Faturamento' и y столбцом 'Custo' из вызываемого 'df' фрейма данных , и сохранить результаты в новом вызываемом столбце 'Roi' .

Моя попытка использовать функцию применить:

 df['Roi'] = df.apply(lambda x, y: x['Faturamento']-y['Custo']/y['Custo'], axis=1)
 

Возвращается:

Ошибка типа: () отсутствует 1 требуемый позиционный аргумент: «y»

Как я могу это сделать?

Комментарии:

1. Попробуйте изменить эту строку на: df['Roi'] = df.apply(lambda x: (x['Faturamento']-x['Custo'])/x['Custo'], axis=1)

2. Используйте встроенную функцию Pandas, когда это возможно. В этом случае вам не нужно полагаться на .apply() функцию и лямбда, которая используется в основном для ситуаций без встроенной функции. Просто используйте операции по столбцам с помощью Pandas, которые лучше всего подходят для этого варианта использования.

3. Я собираюсь дать вам несколько контрольных цифр, и вы поймете разницу.

4. Посмотрите на огромную разницу в 833 раза быстрее для встроенной функции Pandas по столбцам по сравнению .apply lambda с функцией для набора данных из 40000 строк. Даже для небольшого набора данных из 4 строк встроенный Pandas работает все еще быстрее.

5. Определенно, вам следует использовать встроенную функцию арифметических операций Pandas вместо использования .apply() lambda

Ответ №1:

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

 df['Roi'] = (df['Faturamento'] - df['Custo']) / df['Custo']
 

или

 df['Roi'] = df['Faturamento'] / df['Custo'] - 1
 

Таким образом, вы можете наслаждаться быстрой векторизованной обработкой Панд, которая была оптимизирована для быстрой работы. Если вы используете .apply() с включенной функцией лямбда axis=1 , это просто медленный цикл Python в базовой обработке, и он будет медленным.

Контрольный показатель производительности

Тест 1. Маленький df с 4 рядами

    Faturamento  Custo
0           50     20
1           10      5
2            5     15
3          100    400
 
 %%timeit
df['Roi'] = df.apply(lambda x: (x['Faturamento']-x['Custo'])/x['Custo'], axis=1)

721 µs ± 3.54 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
 
 %%timeit
df['Roi'] = df['Faturamento'] / df['Custo'] - 1

490 µs ± 4.83 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
 

Краткое описание: .apply лямбда занимает 721 µs , в то время как встроенные Панды занимают 490 µs : в 1,47 раза быстрее для небольшого набора данных .

Тест 2. Большой df с 40000 строками

 df2 = pd.concat([df] * 10000, ignore_index=True)
 
 %%timeit
df2['Roi'] = df2.apply(lambda x: (x['Faturamento']-x['Custo'])/x['Custo'], axis=1)

639 ms ± 3.62 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
 
 %%timeit
df2['Roi'] = df2['Faturamento'] / df2['Custo'] - 1

767 µs ± 12.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
 

Сводка: .apply лямбда занимает 639 ms (= 639,000 µs) , в то время как встроенные Панды занимают 767 µs : в 833 раза быстрее для большого набора данных .

Комментарии:

1. ясс!!! спасибо, это работает

2. @CarolVieira Я думаю, что вам следует использовать векторизованную и все же более простую версию, подобную этому решению, вместо того, чтобы по-прежнему использовать .apply функцию и лямбда.

Ответ №2:

Я думаю, ты имеешь в виду:

 df['Roi'] = df.apply(lambda x: (x['Faturamento']-x['Custo'])/x['Custo'], axis=1)
 

x относится к фрейму данных