Reputation: 85
I have a df where two column values have True
, False
or NaN
df
a b c
0 a True NaN
1 b False True
2 c NaN False
3 d NaN NaN
4 e False NaN
5 f True False
I'm trying to convert the values in columns b
and c
.
If True
comes in one column, another will be False
If NaN
present change that False
.
Similarly for False
. If NaN
is present in both columns. Change both values to False
Resultant df:
a b c
0 a True False
1 b False True
2 c True False
3 d False False
4 e False True
5 f True False
Upvotes: 3
Views: 1410
Reputation: 11
There are three inbuilt python methods to change column values based on condition. You can refer to the below link for same: https://pythonexamples.org/pandas-dataframe-replace-values-in-column-based-on-condition/
My problem statement was for the column ACTIONCODE in data frame (df2) if column value is A/AMEND/correction then change it to MODIFY
df2.loc[((df2.ACTIONCODE == 'A') | (df2.ACTIONCODE == 'AMEND') | (df2.ACTIONCODE == 'correction')), 'ACTIONCODE'] = 'MODIFY'
NOTE: The or and and python statements require truth-values. For pandas these are considered ambiguous so you should use “bitwise” | (or) or & (and) operations
Upvotes: 1
Reputation: 367
Create filters for conditions
na_false = (df['b'].isna()) & (df['c'] == False)
na_true = (df['b'].isna()) & (df['c'] == True)
true_na = (df['b'] == True) & (df['c'].isna())
false_na = (df['b'] == False) & (df['c'].isna())
na_na = (df['b'].isna()) & (df['c'].isna())
Set column values using filters
df.loc[na_false,'b'] = True
df.loc[na_true,'b'] = False
df.loc[true_na, 'c'] = False
df.loc[false_na, 'c'] = True
df.loc[na_na, ['b', 'c']] = False
Upvotes: 0
Reputation: 28729
This uses numpy where
to check each column for the conditions and replace with the opposite value :
cond1 = df.b.notna() & df.c.isna()
cond2 = df.b.isna() & df.c.notna()
df.assign(
c=lambda x: np.where(cond1, df.b.sub(1).ne(0), df.c),
b=lambda x: np.where(cond2, df.c.sub(1).ne(0), df.b),
).mask(lambda x: x.isna(), False)
a b c
0 a True False
1 b False True
2 c True False
3 d False False
4 e False True
5 f True False
Alternatively, you could use .loc
and assign the values :
cond3 = df.b.isna() & df.c.isna()
df.loc[cond1, "c"] = df.loc[cond1, "b"].sub(1).ne(0)
df.loc[cond2, "b"] = df.loc[cond2, "c"].sub(1).ne(0)
df.loc[cond3, ["b", "c"]] = False
Upvotes: 0
Reputation: 308
create a user-defined function swap:
import numpy as np
def swap(x):
if(x['b']==False and x['c']==np.NaN):
return True
if(x['b']==True and x['c']==np.NaN):
return False
else:
return c
def swap2(x):
if(x['c']==False and x['b']==np.NaN):
return True
if(x['c']==True and x['b']==np.NaN):
return False
else:
return b
Then use apply function:
df['c']=df.apply(swap, axis=1)
df['b']=df.apply(swap2, axis=1)
then fill NAs with false
df.fillna(False)
Upvotes: 0
Reputation: 150825
Let's try two-step filling:
s = df[['b','c']]
# both are `NaN`, fill with `False`
df.loc[s.isna().all(1), ['b','c']] = False
# inverse the sum
sums = (1 - s.sum(1)).astype(bool)
# fill the remaining `NaN` with the inverse sum
df[['b','c']] = s.apply(lambda x: x.fillna(sums))
Output:
a b c
0 a True False
1 b False True
2 c True False
3 d False False
4 e False True
5 f True False
Upvotes: 5