Here is your result.
import numpy as np
mask_matrix = (
(df.start.to_numpy().reshape(1,-1).T < df.end.to_numpy())
& (df.index.to_numpy() <= np.arange(0,len(df)).reshape(1, -1).T)
)
df_add = pd.DataFrame(
(np.matmul(
(
(mask_matrix)
), df.label.to_numpy()
)
) / (mask_matrix.sum(axis=-1)),
columns = ["mean"]
)
df = pd.concat([df, df_add], axis=1)
When we create the matrix we use O(n^2) of additional space. Hopefully it is not a problem. Otherwise need to use a loop which I don't personally like when using vectorized computations.
A few additional comments:
df.start.to_numpy().reshape(1,-1).T < df.end.to_numpy() basically compares where start is below end for each row. This is the result:
array([[ True, True, True, True, True, True, True, True, True],
[ True, True, True, True, True, True, True, True, True],
[ True, True, True, True, True, True, True, True, True],
[False, True, True, True, True, True, True, True, True],
[False, True, True, True, True, True, True, True, True],
[False, True, True, True, True, True, True, True, True],
[False, False, False, True, True, True, True, True, False],
[False, False, False, False, True, True, True, True, False],
[False, False, False, False, True, True, True, True, False]])
(df.index.to_numpy() <= np.arange(0,len_).reshape(1, -1).T) restricts previous result to only rows that are precedent to current one. This mask looks like this:
array([[ True, False, False, False, False, False, False, False, False],
[ True, True, False, False, False, False, False, False, False],
[ True, True, True, False, False, False, False, False, False],
[ True, True, True, True, False, False, False, False, False],
[ True, True, True, True, True, False, False, False, False],
[ True, True, True, True, True, True, False, False, False],
[ True, True, True, True, True, True, True, False, False],
[ True, True, True, True, True, True, True, True, False],
[ True, True, True, True, True, True, True, True, True]])
Final mask_matrix (elementwise multiplication of previous two matrices) looks like this
array([[ True, False, False, False, False, False, False, False, False],
[ True, True, False, False, False, False, False, False, False],
[ True, True, True, False, False, False, False, False, False],
[False, True, True, True, False, False, False, False, False],
[False, True, True, True, True, False, False, False, False],
[False, True, True, True, True, True, False, False, False],
[False, False, False, True, True, True, True, False, False],
[False, False, False, False, True, True, True, True, False],
[False, False, False, False, True, True, True, True, False]])
Now multiplying this mask_matrix by vector df.label gives almost what we need. Just need to elementwise divide by the sum of True in mask_matrix