I have two functions which shift a row of a pandas dataframe to the top or bottom, respectively. After applying them more then once to a dataframe, they seem to work incorrectly.
These are the 2 functions to move the row to top / bottom:
def shift_row_to_bottom(df, index_to_shift): """Shift row, given by index_to_shift, to bottom of df.""" idx = df.index.tolist() idx.pop(index_to_shift) df = df.reindex(idx + [index_to_shift]) return df def shift_row_to_top(df, index_to_shift): """Shift row, given by index_to_shift, to top of df.""" idx = df.index.tolist() idx.pop(index_to_shift) df = df.reindex([index_to_shift] + idx) return df
Note: I don’t want to reset_index
for the returned df.
Example:
df = pd.DataFrame({'Country' : ['USA', 'GE', 'Russia', 'BR', 'France'], 'ID' : ['11', '22', '33','44', '55'], 'City' : ['New-York', 'Berlin', 'Moscow', 'London', 'Paris'], 'short_name' : ['NY', 'Ber', 'Mosc','Lon', 'Pa'] }) df = Country ID City short_name 0 USA 11 New-York NY 1 GE 22 Berlin Ber 2 Russia 33 Moscow Mosc 3 BR 44 London Lon 4 France 55 Paris Pa
This is my dataframe:
Now, apply function for the first time. Move row with index 0
to bottom:
df_shifted = shift_row_to_bottom(df,0) df_shifted = Country ID City short_name 1 GE 22 Berlin Ber 2 Russia 33 Moscow Mosc 3 BR 44 London Lon 4 France 55 Paris Pa 0 USA 11 New-York NY
The result is exactly what I want.
Now, apply function again. This time move row with index 2
to the bottom:
df_shifted = shift_row_to_bottom(df_shifted,2) df_shifted = Country ID City short_name 1 GE 22 Berlin Ber 2 Russia 33 Moscow Mosc 4 France 55 Paris Pa 0 USA 11 New-York NY 2 Russia 33 Moscow Mosc
Well, this is not what I was expecting. There must be a problem when I want to apply the function a second time. The promblem is analog to the function shift_row_to_top
.
My question is:
- What’s going on here?
- Is there a better way to shift a specific row to top / bottom of the dataframe? Maybe a pandas-function?
- If not, how would you do it?
Advertisement
Answer
Your problem is these two lines:
idx = df.index.tolist() idx.pop(index_to_shift)
idx
is a list and idx.pop(index_to_shift)
removes the item at index index_to_shift
of idx
, which is not necessarily valued index_to_shift
as in the second case.
Try this function:
def shift_row_to_bottom(df, index_to_shift): idx = [i for i in df.index if i!=index_to_shift] return df.loc[idx+[index_to_shift]] # call the function twice for i in range(2): df = shift_row_to_bottom(df, 2)
Output:
Country ID City short_name 0 USA 11 New-York NY 1 GE 22 Berlin Ber 3 BR 44 London Lon 4 France 55 Paris Pa 2 Russia 33 Moscow Mosc