Reputation:
I am trying to shift
values in a pandas df
. Specifically, rows
that follow a specific value
. For the df
below I want to shift
the row
to the left when the above value is == 'X'
.
d = ({
'A' : ['Foo','','Foo',''],
'B' : ['X','Bar','X','Bar'],
'C' : ['','Y','','Y'],
})
df = pd.DataFrame(data=d)
Out:
A B C
0 Foo X
1 Bar Y
2 Foo X
3 Bar Y
I have tried this:
b = ['X']
x = df.B=='X'
df.loc[x, b] = df.loc[x, b].apply(lambda x: x.shift(-1), axis=1)
Intended Output:
A B C
0 Foo X
1 Bar Y
2 Foo X
3 Bar Y
Whilst these strings
are identical my dataset varies. Foo
will be the same but the string
that follows X
will vary. So I can't just select Bar
and shift
row
left. I need something that finds the row
below X
and shifts left
Upvotes: 1
Views: 1861
Reputation: 164623
If you just want to get rid of empty values, you can use a list comprehension and then feed to the pd.DataFrame
constructor:
res = pd.DataFrame([list(filter(None, row)) for row in df.values.tolist()],
columns=df.columns[:2])
print(res)
A B
0 Foo X
1 Bar Y
2 Foo X
3 Bar Y
Upvotes: 1
Reputation: 323226
You can do
df.replace('',np.nan).apply(lambda x: sorted(x, key=pd.isnull), 1).fillna('')
Out[538]:
A B C
0 Foo X
1 Bar Y
2 Foo X
3 Bar Y
Upvotes: 1
Reputation: 59274
IIUC
s = (df == 'X').any(1)
idx_to_change = s[s].index+1
df.loc[idx_to_change,:] = df.loc[idx_to_change].shift(-1,axis=1)
df.fillna('')
A B C
0 Foo X
1 Bar Y
2 Foo X
3 Bar Y
Upvotes: 2