Получение NaN при разделении выровненных столбцов фрейма данных

#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.