Как сравнить значения полей в DataFrame?
Пытаюсь выделить аномальные отклонения некоторых плана от факта.
Задача - оставить на рассмотрение только те строки, в которых план расходится с фактом на величину, превышающую 20% от факта.
import pandas as pd
df = pd.read_excel(r'C:\Users\Usr\Desktop\file.xlsx',
index_col = None)
df = df[df['fact'].notnull() | df['plan'].notnull()]
df.drop_duplicates(inplace=True)
df = df.reset_index(drop=True).set_index('Code')
df['fact'].fillna(0, inplace=True)
df['plan'].fillna(0, inplace=True)
df1 = df.copy()
for i in df.index:
lower = df.loc[i, 'fact']*0.8
higher = df.loc[i, 'fact']*1.2
current = df.loc[i, 'plan']
if current > lower & current < higher
df1.drop(i)
df1.to_excel(r'C:\Users\Usr\Desktop\file2.xlsx')
Получаю следующую ошибку:
Traceback (most recent call last):
File "C:/Users/Usr/Desktop/proj/asd.py", line 17, in <module>
if current > lower & current < higher:
TypeError: ufunc 'bitwise_and' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
Пробовал и так:
...
for i in df.index:
first = False
second = False
if current < higher:
first = True
if current > lower:
second = True
if first and second:
df1.drop(i)
...
Ошибка:
Traceback (most recent call last):
File "C:/Users/Usr/Desktop/proj/asd.py", line 22, in <module>
if current < higher:
File "C:\Users\Usr\Desktop\proj\venv\lib\site-packages\pandas\core\generic.py", line 1478, in __nonzero__
raise ValueError(
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Не могу решить эту проблему
Ответы (2 шт):
Автор решения: strawdog
→ Ссылка
По-моему, вы очень сложно пытаетесь решить эту проблему. я бы посоветовал сделать по-другому:
Исходные:
import pandas as pd
import numpy as np
df = pd.DataFrame({'plan':[1, 2, 3, 4, 5], 'fact':[1.2, 2.4, 2.8, 4.1, 4.9]})
df1 = df.copy()
df1:
plan fact
0 1 1.2
1 2 2.4
2 3 2.8
3 4 4.1
4 5 4.9
Далее - обычное сравнение солбцами:
res = df[df1.pct_change(axis='columns')['fact'].ge(0.2) | np.isclose(df1.pct_change(axis='columns')['fact'], 0.2)]
Собственно, res получится:
plan fact
0 1 1.2
1 2 2.4
Автор решения: CrazyElf
→ Ссылка
for i in df.index:
lower = df.loc[i, 'fact']*0.8
higher = df.loc[i, 'fact']*1.2
current = df.loc[i, 'plan']
if current > lower & current < higher
df1.drop(i)
- Обычно всегда можно обойтись без перебора
DataFrame, совершая действия сразу со всей колонкой. Это и понятнее и эффективнее. - Вы в своём коде всё-равно в итоге работаете не с отдельными числами, а с
Pandas series, поэтому у вас и выходит ошибка. Вы можете в принципе взять первое число из серии (оно же и единственное), но, повторюсь, лучше обойтись вообще без перебора по индексу.
Правильный код может выглядеть так:
lower = df['fact']*0.8
higher = df['fact']*1.2
current = df['plan']
df1 = df.loc[(current <= lower) | (current >= higher)]
Обратите внимание на скобки в последней строке. Именно они чинят ошибку "The truth value of a Series is ambiguous."