Избегайте SettingWithCopyWarning в Pandas - PullRequest
0 голосов
/ 14 июля 2020

У меня есть следующий код, я не уверен, как его переписать, чтобы избежать SettingWithCopyWarning, или мне просто отключить предупреждение?

Код работает Я просто хочу назначить левый атрибут pd.cut в новый столбец, если число положительное, и правый атрибут, если отрицательный.

import numpy as np
import pandas as pd


bins = np.array([-1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0])
test_data = [{"ID": 1, "Value": -0.5}, {"ID": 2, "Value": 1.5}]

df = pd.DataFrame(test_data)

df["Bin"] = 0.0
df["Bin"][df["Value"] > 0.0] = [d['left'] for d in [{fn: getattr(f, fn) for fn in ['left']} for f in pd.cut(df["Value"], bins)]]
df["Bin"][df["Value"] < 0.0] = [d['right'] for d in [{fn: getattr(f, fn) for fn in ['right']} for f in pd.cut(df["Value"], bins)]]

print(df)

Выполнение кода дает

test.py:11: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  df["Bin"][df["Value"] > 0.0] = [d['left'] for d in [{fn: getattr(f, fn) for fn in ['left']} for f in pd.cut(df["Value"], bins)]]
e.py:12: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  df["Bin"][df["Value"] < 0.0] = [d['right'] for d in [{fn: getattr(f, fn) for fn in ['right']} for f in pd.cut(df["Value"], bins)]]
   ID  Value  Bin
0   1   -0.5 -0.5
1   2    1.5  1.0

Ответы [ 2 ]

1 голос
/ 14 июля 2020

Попробуйте следующее:

Изменить:

В случае всех +ve значений pd.cut(df.loc[df["Value"]<0,'Value'], bins, labels=bins[1:]) дает результат Series([], Name: Value, dtype: category - и, следовательно, ошибку назначение.

Но простой try except должен избегать этого:

from contextlib import suppress
with suppress(ValueError):
    df.loc[df["Value"] > 0.0,"Bin"] = pd.cut(df.loc[df["Value"]>0,'Value'], bins, labels=bins[:-1])
with suppress(ValueError):
    df.loc[df["Value"] < 0.0,"Bin"] = pd.cut(df.loc[df["Value"]<0,'Value'], bins, labels=bins[1:])

Кстати, здесь labels=bins[:-1] и labels=bins[1:] выполняет работу left и right в ваш исходный код.

0 голосов
/ 14 июля 2020

Вы должны заменить нарезку на loc:

df.loc[df["Value"] > 0.0, "Bin"] = [d['left'] for d in [{fn: getattr(f, fn) for fn in ['left']} for f in pd.cut(df["Value"], bins)]]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...