조건부 판다 교체


123

DataFrame이 있고 값을 초과하는 특정 열의 값을 0으로 바꾸고 싶습니다. 나는 이것이 이것을 달성하는 방법이라고 생각했습니다.

df[df.my_channel > 20000].my_channel = 0

채널을 새 데이터 프레임에 복사하면 간단합니다.

df2 = df.my_channel 

df2[df2 > 20000] = 0

이것은 내가 원하는 것을 정확히 수행하지만 원래 DataFrame의 일부로 채널에서 작동하지 않는 것 같습니다.


여기서 당신이 찾고 있다고 생각하는 것을 찾았 습니다 .
feetwet

답변:


181

.ix인덱서는 0.20.0 이전의 pandas 버전에서 제대로 작동하지만 pandas 0.20.0부터는 .ix인덱서가 더 이상 사용되지 않으므로 사용 하지 않아야합니다. 대신 .loc또는 iloc인덱서를 사용할 수 있습니다 . 이 문제는 다음과 같이 해결할 수 있습니다.

mask = df.my_channel > 20000
column_name = 'my_channel'
df.loc[mask, column_name] = 0

또는 한 줄로

df.loc[df.my_channel > 20000, 'my_channel'] = 0

mask있는 행을 선택하는 데 도움이 df.my_channel > 20000입니다 True동안, df.loc[mask, column_name] = 0선택된 행에 설정 값 0 어디에 mask이름이 열에 보유 column_name.

업데이트 : 이 경우, 당신은 사용해야 loc당신이 사용하는 경우 때문에 iloc, 당신이 얻을 것이다 NotImplementedError당신에게 그 이야기 의 정수 유형에 iLocation 기반 부울 인덱싱하여 사용할 수 없습니다 .


81

시험

df.loc[df.my_channel > 20000, 'my_channel'] = 0

참고 : v0.20.0부터는 / 대신 ix 사용되지 않습니다 .lociloc


8
감사합니다. 나도 내 자신의 솔루션을 찾았습니다. df.my_channel [df.my_channel> 20000] = 0
BMichell

2
@BMichell 나는 귀하의 솔루션이 0.13에서 경고를주기 시작할 것이라고 생각합니다. 아직 시도 할 기회가 없었습니다
lowtech

yield error : /opt/anaconda3/envs/python35/lib/python3.5/site-packages/ipykernel_launcher.py:1 : SettingWithCopyWarning : A value is trying to be set on a copy of a DataFrame from a DataFrame 문서 : pandas.pydata.org/pandas-docs/stable/... "" "는 IPython 커널을 시작하기위한 진입 점입니다.
룻거 Hofste

@RutgerHofste 언급 해 주셔서 감사합니다. 또 다른 주장은 Python3을 사용하지 않습니다
lowtech

34

np.where 기능은 다음과 같이 작동합니다.

df['X'] = np.where(df['Y']>=50, 'yes', 'no')

귀하의 경우에는 다음을 원할 것입니다.

import numpy as np
df['my_channel'] = np.where(df.my_channel > 20000, 0, df.my_channel)

19

원래 데이터 프레임이 업데이트되지 않는 이유는 체인 인덱싱으로 인해 데이터 프레임보기가 아닌 복사본이 수정 될 수 있기 때문 입니다. 문서는 이 조언을 제공 :

pandas 객체에서 값을 설정할 때 체인 인덱싱이라는 것을 피하기 위해주의를 기울여야합니다.

몇 가지 대안이 있습니다.

loc + 부울 인덱싱

loc 값을 설정하는 데 사용할 수 있으며 부울 마스크를 지원합니다.

df.loc[df['my_channel'] > 20000, 'my_channel'] = 0

mask + 부울 인덱싱

시리즈에 할당 할 수 있습니다.

df['my_channel'] = df['my_channel'].mask(df['my_channel'] > 20000, 0)

또는 시리즈를 제자리에서 업데이트 할 수 있습니다.

df['my_channel'].mask(df['my_channel'] > 20000, 0, inplace=True)

np.where + 부울 인덱싱

조건이 충족 되지 않을 때 원래 시리즈를 할당하여 NumPy를 사용할 수 있습니다 . 그러나 처음 두 솔루션은 지정된 값만 명시 적으로 변경하므로 더 깨끗합니다.

df['my_channel'] = np.where(df['my_channel'] > 20000, 0, df['my_channel'])

0

다음 과 같은 lambda기능을 사용 합니다 .SeriesDataFrame

f = lambda x: 0 if x>100 else 1
df['my_column'] = df['my_column'].map(f)

이것이 효율적인 방법이라고 주장하지는 않지만 잘 작동합니다.


3
이것은 비효율적이며 행 단위 연산에서 Python 수준 루프를 포함하므로 권장되지 않습니다.
jpp

감사합니다 . loc여기에서 df.loc[: , 'my_column'] = df['my_column'].map(f). 아래에 추가 한 것만 큼 빠른지 모르겠습니다.
Ozkan Serttas 2018

2
아니요, 여전히 열 방식이 아닌 행 방식으로 작동하므로 여전히 느립니다.
jpp 2018

0

이 시도:

df.my_channel = df.my_channel.where(df.my_channel <= 20000, other= 0)

또는

df.my_channel = df.my_channel.mask(df.my_channel > 20000, other= 0)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.