Smasell
Smasell

Reputation: 1228

Python Dataframe. Move rows values left according index of rows

I have the table like this:

import pandas as pd
data = [[20, 15, 10, 5], [20, 15, 10, 5], [20, 15, 10, 5], [20, 15, 10, 5]]
df = pd.DataFrame(data, columns = ['one', 'two', 'three', 'four'])
df
one two three four
20 15 10 5
20 15 10 5
20 15 10 5
20 15 10 5

I want to move every rows values left according their rows index. Row values with index 0 stays the same, Row values with index 1 moves left in one point, Row values with index 2 moves left in two points, etc... Desired table should looks like this:

one two three four
20 15 10 5
15 10 5 0
10 5 0 0
5 0 0 0

Thanks for helping me!

Upvotes: 2

Views: 832

Answers (3)

Henry Ecker
Henry Ecker

Reputation: 35626

An upper right triangle to upper left triangle approach:

Create a mask to grab the upper triangle of the DataFrame using np.triu + np.ones + DataFrame.shape

mask = np.triu(np.ones(df.shape, dtype=bool))
[[ True  True  True  True]
 [False  True  True  True]
 [False False  True  True]
 [False False False  True]]

Grab corresponding values from the values of the DataFrame:

a = df.values[mask]
[20 15 10  5 15 10  5 10  5  5]

Create a np.zeros skeleton of the same dtype as a and fliplr the mask and assign back:

tri = np.zeros(df.shape, dtype=a.dtype)
tri[np.fliplr(mask)] = a
[[20 15 10  5]
 [15 10  5  0]
 [10  5  0  0]
 [ 5  0  0  0]]

Turn back into a DataFrame:

new_df = pd.DataFrame(tri, columns=df.columns)

new_df:

   one  two  three  four
0   20   15     10     5
1   15   10      5     0
2   10    5      0     0
3    5    0      0     0

Complete Working Example:

import numpy as np
import pandas as pd

data = [[20, 15, 10, 5], [20, 15, 10, 5], [20, 15, 10, 5],
        [20, 15, 10, 5]]
df = pd.DataFrame(data, columns=['one', 'two', 'three', 'four'])

mask = np.triu(np.ones(df.shape, dtype=bool))
a = df.values[mask]
tri = np.zeros(df.shape, dtype=a.dtype)
tri[np.fliplr(mask)] = a
new_df = pd.DataFrame(tri, columns=df.columns)
print(new_df)

Upvotes: 1

Ank
Ank

Reputation: 1704

Another way by using a simple loop to shift the values in every row, and then use fillna to replace NA values with 0:

for i in range(len(df)):
    df.iloc[i,:] = df.iloc[i,:].shift(-i)

df.fillna(0, inplace=True)

Output:

>>> df
   one   two  three  four
0   20  15.0   10.0   5.0
1   15  10.0    5.0   0.0
2   10   5.0    0.0   0.0
3    5   0.0    0.0   0.0

Upvotes: 3

azro
azro

Reputation: 54148

You could use a method that shift left regarding the index value and fills with 0

import pandas as pd


def rotate_row(row):
    return pd.Series(row.to_list()[row.name:] + [0] * row.name, index=row.index)


data = [[20, 15, 10, 5], [20, 15, 10, 5], [20, 15, 10, 5], [20, 15, 10, 5]]
df = pd.DataFrame(data, columns=['one', 'two', 'three', 'four'])
df = df.apply(rotate_row, axis=1)
print(df)
   one  two  three  four
0   20   15     10     5
1   15   10      5     0
2   10    5      0     0
3    5    0      0     0

Upvotes: 1

Related Questions