#python #pandas
Вопрос:
У меня есть фрейм данных формы:
A B C
Cat-1 798.26 456.65 187.56
Cat-2 165165.53 45450.00 4897.57
Cat-3 488565.65 15198.56 15654.65
Cat-4 0.00 54256.35 49878.65
Cat-5 1156.61 789.05 89789.54
Cat-6 0.00 1644.78 6876.15
Я пытаюсь получить процент, разделив B на A. Для достижения этой цели я использовал следующее:
if_condition = df['A'] != 0
then = (1 - df['B'].div(df['A']))
else_= 0
df['New Col'] = np.where(if_condition, then, else_)
Я ожидал следующего результата:
A B C New Col
Cat-1 798.26 456.65 187.56 .5720
Cat-2 165165.53 45450.00 4897.57 .2751
Cat-3 488565.65 15198.56 15654.65 .0311
Cat-4 0.00 54256.35 49878.65 0
Cat-5 1156.61 789.05 89789.54 .6822
Cat-6 0.00 1644.78 6876.15 0
Однако я получил следующий результат:
A B C New Col
Cat-1 798.26 456.65 187.56 NaN
Cat-2 165165.53 45450.00 4897.57 0.2751
Cat-3 488565.65 15198.56 15654.65 0.0311
Cat-4 0.00 54256.35 49878.65 0
Cat-5 1156.61 789.05 89789.54 NaN
Cat-6 0.00 1644.78 6876.15 0
Я пробовал некоторые другие решения, которые включали выравнивание двух столбцов, однако это не изменило конечный результат. Что потенциально может генерировать эти значения NaN?
Комментарии:
1. Каковы ваши версии? Потому что ваш показанный код дает мне (в виде списка для более удобного просмотра в комментариях) ->>
df['New Col'].round(3).tolist()
->>[0.428, 0.725, 0.969, 0.0, 0.318, 0.0]
, что кажется разумным выводом.2. Кроме того, ваш ожидаемый результат просто выглядит как B/A, а не 1- (B/A). Это что, ошибка?
3. У меня есть три разных кадра данных. Из этих кадров данных два из них имеют приемлемые выходные данные. Однако средний фрейм данных дает результаты NaN. Я не могу точно описать, почему это происходит. Я распечатываю столбцы, которые пытаюсь разделить, и в этих столбцах ничего не выделяется. Что касается моего ожидаемого результата, я пересмотрел свой расчет, и он кажется мне правильным.
4. Ваш код отлично работает в моей системе. Нет никаких причин для
nan
того, чтобы быть вCat-1
иCat-5
.
Ответ №1:
import pandas as pd
import numpy as np
import io
df = pd.read_csv(io.StringIO(""" A B C
Cat-1 798.26 456.65 187.56
Cat-2 165165.53 45450.00 4897.57
Cat-3 488565.65 15198.56 15654.65
Cat-4 0.00 54256.35 49878.65
Cat-5 1156.61 789.05 89789.54
Cat-6 0.00 1644.78 6876.15"""), sep="ss ", engine="python")
df
# output
A B C
Cat-1 798.26 456.65 187.56
Cat-2 165165.53 45450.00 4897.57
Cat-3 488565.65 15198.56 15654.65
Cat-4 0.00 54256.35 49878.65
Cat-5 1156.61 789.05 89789.54
Cat-6 0.00 1644.78 6876.15
if_condition = df['A'] != 0
then = (1 - df['B'].div(df['A']))
else_= 0
df['New Col'] = np.where(if_condition, then, else_)
# output
A B C New Col
Cat-1 798.26 456.65 187.56 0.427943
Cat-2 165165.53 45450.00 4897.57 0.724822
Cat-3 488565.65 15198.56 15654.65 0.968891
Cat-4 0.00 54256.35 49878.65 0.000000
Cat-5 1156.61 789.05 89789.54 0.317791
Cat-6 0.00 1644.78 6876.15 0.000000
Кажется, это правильно.
Я использую версию pandas «1.2.5»
Также вы могли бы сделать это условие «если бы еще» немного проще:
df["New col"] = df.apply(lambda x: 1 - x["B"] / x["A"] if x["A"] != 0 else 0, axis=1)
Ответ №2:
Вам не нужно условие, замените -np.inf
на 0:
# df['New Col'] = (1 - df['B'] / df['A']).replace(-np.inf, 0)
df['New Col'] = ((1 - df['B'] / df['A']) * 100).round(2).replace(-np.inf, 0)
print(df)
# Output:
A B C New Col
Cat-1 798.26 456.65 187.56 42.79
Cat-2 165165.53 45450.00 4897.57 72.48
Cat-3 488565.65 15198.56 15654.65 96.89
Cat-4 0.00 54256.35 49878.65 0.00
Cat-5 1156.61 789.05 89789.54 31.78
Cat-6 0.00 1644.78 6876.15 0.00
Комментарии:
1. Ваше решение все еще дает
ZeroDivisionError: float division by zero
результат .
Ответ №3:
Я смог решить эту проблему, просто не ныряя на 0, а затем заменив NaN
значения на 0. Это дало ожидаемый результат:
df['New Col'] = (1 - df['B']/df['A'][df['A'] != 0]).fillna(0)
В принципе, я смог разделить все, кроме 0, а остальные значения NaN являются результатом не деления 0 и, таким образом, могут быть заменены на 0.