2

I have a df like this where Col1 and Col2 are not related at all:

Col1   Col2
Apple  France
Bana   
Grape   Mexico
        Argentina
Sat     India
        Russia
        US

I want to shift individual columns based on missing values

Resultant df:

Col1   Col2
Apple  France
Bana   Mexico
Grape   Argentina
Sat     India
        Russia
        US   

I have seen answers using Subset where we can drop all rows but I just wanted to delete that cell and move the rest of the values up!!

Rahul Agarwal
  • 4,034
  • 7
  • 27
  • 51

1 Answers1

3

Use a bit changed justify function:

c = ['Col1','Col2']
#if missing values are empty strings
df[c] = justify(df[c].to_numpy(), invalid_val='', side='up', axis=0)

#if missing values are NaNs
#df[c] = justify(df[c].to_numpy(), invalid_val=np.nan, side='up', axis=0)
print (df)
    Col1       Col2
0  Apple     France
1   Bana     Mexico
2  Grape  Argentina
3    Sat      India
4            Russia
5                US
6                  

#https://stackoverflow.com/a/44559180/2901002
def justify(a, invalid_val=0, axis=1, side='left'):    
    """
    Justifies a 2D array

    Parameters
    ----------
    A : ndarray
        Input array to be justified
    axis : int
        Axis along which justification is to be made
    side : str
        Direction of justification. It could be 'left', 'right', 'up', 'down'
        It should be 'left' or 'right' for axis=1 and 'up' or 'down' for axis=0.

    """

    if invalid_val is np.nan:
        mask = pd.notna(a)
    else:
        mask = a!=invalid_val
    justified_mask = np.sort(mask,axis=axis)
    if (side=='up') | (side=='left'):
        justified_mask = np.flip(justified_mask,axis=axis)
    out = np.full(a.shape, invalid_val, dtype=object) 
    if axis==1:
        out[justified_mask] = a[mask]
    else:
        out.T[justified_mask.T] = a.T[mask.T]
    return out
jezrael
  • 822,522
  • 95
  • 1,334
  • 1,252