Reputation: 1228
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
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
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
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