justify data from right to left

Viewed 65

I have a dataset of rows containing varying lengths of integer values in a series. I want to separate the series so each integer has its own column but align these values along the right-most column. I want the dataframe to resenble upper triangle of a matrix.

Currently I have a dataset like:

    variable    value
0   0   [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
1   1   [1, 2, 3, 4, 5, 6, 7, 8, 9]
2   2   [1, 2, 3, 4, 5, 6, 7, 8]
3   3   [1, 2, 3, 4, 5, 6, 7]
4   4   [1, 2, 3, 4, 5, 6]
5   5   [1, 2, 3, 4, 5]
6   6   [1, 2, 3, 4]
7   7   [1, 2, 3]
8   8   [1, 2]
9   9   [1]

I apply this function

df = pd.DataFrame([pd.Series(x) for x in df2.value])
df.columns = ['{}'.format(x+1) for x in df.columns]

and I get this:

    1   2   3   4   5   6   7   8   9   10
0   1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 0.0
1   1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 NaN
2   1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 NaN NaN
3   1.0 2.0 3.0 4.0 5.0 6.0 7.0 NaN NaN NaN
4   1.0 2.0 3.0 4.0 5.0 6.0 NaN NaN NaN NaN
5   1.0 2.0 3.0 4.0 5.0 NaN NaN NaN NaN NaN
6   1.0 2.0 3.0 4.0 NaN NaN NaN NaN NaN NaN
7   1.0 2.0 3.0 NaN NaN NaN NaN NaN NaN NaN
8   1.0 2.0 NaN NaN NaN NaN NaN NaN NaN NaN
9   1.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN

But what i want is this:

    1   2   3   4   5   6   7   8   9   10
0   1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 0.0
1   NaN 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 
2   NaN NaN 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 
3   NaN NaN NaN 1.0 2.0 3.0 4.0 5.0 6.0 7.0 
4   NaN NaN NaN NaN 1.0 2.0 3.0 4.0 5.0 6.0 
5   NaN NaN NaN NaN NaN 1.0 2.0 3.0 4.0 5.0 
6   NaN NaN NaN NaN NaN NaN 1.0 2.0 3.0 4.0
7   NaN NaN NaN NaN NaN NaN NaN 1.0 2.0 3.0 
8   NaN NaN NaN NaN NaN NaN NaN NaN 1.0 2.0 
9   NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.0 
2 Answers

One possible approach is to use Series.str.len to calculate the max length of the list in the column value i.e lmax then using list comprehension pad each of the list based on lmax:

lmax = df['value'].str.len().max()
df1 = pd.DataFrame([[np.nan] * (lmax - len(s)) + s
                    for s in df['value']], columns=range(1, lmax + 1))

Result:

print(df1)
     1    2    3    4    5    6    7    8    9  10
0  1.0  2.0  3.0  4.0  5.0  6.0  7.0  8.0  9.0   0
1  NaN  1.0  2.0  3.0  4.0  5.0  6.0  7.0  8.0   9
2  NaN  NaN  1.0  2.0  3.0  4.0  5.0  6.0  7.0   8
3  NaN  NaN  NaN  1.0  2.0  3.0  4.0  5.0  6.0   7
4  NaN  NaN  NaN  NaN  1.0  2.0  3.0  4.0  5.0   6
5  NaN  NaN  NaN  NaN  NaN  1.0  2.0  3.0  4.0   5
6  NaN  NaN  NaN  NaN  NaN  NaN  1.0  2.0  3.0   4
7  NaN  NaN  NaN  NaN  NaN  NaN  NaN  1.0  2.0   3
8  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  1.0   2
9  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN   1

You could also use np.pad, but need to cast the dtype of each array into float first in order to fill with nan:

s = pd.DataFrame([np.pad(np.array(a).astype(float), (10 - len(a), 0), mode="constant",
                         constant_values=np.NaN) for a in df["value"]])
print (s)

     0    1    2    3    4    5    6    7    8     9
0  1.0  2.0  3.0  4.0  5.0  6.0  7.0  8.0  9.0  10.0
1  NaN  1.0  2.0  3.0  4.0  5.0  6.0  7.0  8.0   9.0
2  NaN  NaN  1.0  2.0  3.0  4.0  5.0  6.0  7.0   8.0
3  NaN  NaN  NaN  1.0  2.0  3.0  4.0  5.0  6.0   7.0
4  NaN  NaN  NaN  NaN  1.0  2.0  3.0  4.0  5.0   6.0
5  NaN  NaN  NaN  NaN  NaN  1.0  2.0  3.0  4.0   5.0
6  NaN  NaN  NaN  NaN  NaN  NaN  1.0  2.0  3.0   4.0
7  NaN  NaN  NaN  NaN  NaN  NaN  NaN  1.0  2.0   3.0
8  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  1.0   2.0
9  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN   1.0
Related