How to set values in diagonal and repeat over all rows?

Question:

I have a timeserie dataframe filled with 0 and a various number of columns and I would like to fill values in diagonal with 100 starting by the first row and the first column. I could use the solution proposed in the question bellow but it stops after value of the last column has been filled.
Set values on the diagonal of pandas.DataFrame

How could I make it repeat over all rows?

This is how my dataframe looks like:

                               A      B
2020-05-02 23:00:00+00:00    0.0    0.0
2020-05-03 00:00:00+00:00    0.0    0.0
2020-05-03 01:00:00+00:00    0.0    0.0
2020-05-03 02:00:00+00:00    0.0    0.0
2020-05-03 03:00:00+00:00    0.0    0.0

But as you can see using Numpy fill_diagonal doesn’t complete the job.

import numpy as np
np.fill_diagonal(df.values, 0)

                               A      B
2020-05-02 23:00:00+00:00  100.0    0.0
2020-05-03 00:00:00+00:00    0.0  100.0
2020-05-03 01:00:00+00:00    0.0    0.0
2020-05-03 02:00:00+00:00    0.0    0.0
2020-05-03 03:00:00+00:00    0.0    0.0

When there are 2 columns I would like is something like this:

                               A      B
2020-05-02 23:00:00+00:00  100.0    0.0
2020-05-03 00:00:00+00:00    0.0  100.0
2020-05-03 01:00:00+00:00  100.0    0.0
2020-05-03 02:00:00+00:00    0.0  100.0
2020-05-03 03:00:00+00:00  100.0    0.0
Asked By: Florent

||

Answers:

Here’s a numpy based approach, reshaping based on the amount of columns and slice assigning back with a given value:

def fill_wrapped_diag(a, fill_val):
    r,c = a.shape
    r_left = c-r%c
    a_ext = np.pad(a, ((0,r_left),(0,0)))
    a_r = a_ext.reshape((r+r_left)//c, -1)
    a_r[:,::c+1] = fill_val
    return a_r.reshape(a_ext.shape)[:-r_left]

df[:] = fill_wrapped_diag(df.values, 100)
print(df)
                               A      B
2020-05-02-23:00:00+00:00  100.0    0.0
2020-05-03-00:00:00+00:00    0.0  100.0
2020-05-03-01:00:00+00:00  100.0    0.0
2020-05-03-02:00:00+00:00    0.0  100.0
2020-05-03-03:00:00+00:00  100.0    0.0

Some other examples:

a = np.zeros((8,4))
fill_wrapped_diag(a, fill_val=100)

array([[100.,   0.,   0.,   0.],
       [  0., 100.,   0.,   0.],
       [  0.,   0., 100.,   0.],
       [  0.,   0.,   0., 100.],
       [100.,   0.,   0.,   0.],
       [  0., 100.,   0.,   0.],
       [  0.,   0., 100.,   0.],
       [  0.,   0.,   0., 100.]])

a = np.random.randint(0,10,(7,3))
fill_wrapped_diag(a, fill_val=75)

array([[75,  8,  8],
       [ 4, 75,  7],
       [ 3,  5, 75],
       [75,  5,  5],
       [ 5, 75,  2],
       [ 3,  6, 75],
       [75,  1,  8]])
Answered By: yatu

Here is a way using np.identity and np.tile

s = df.shape

df.where(np.tile(np.identity(s[-1]),(s[0],1))[:s[0]] != 1,100)
Answered By: rhug123
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.