how to shift non nan value in multiple columns row wise by group?

Question:

so i have data frame as below

A1 A2 A3 A4 A5 A6
1 nan 3 7 nan 8
nan 5 nan 11 9 nan
54 6 84 12 3 nan
10 nan nan 16 nan 45
12 93 13 31 5 91
73 nan 45 nan nan 9

i want to shift the whole data frame n rows such that it skips nan rows but still preserve it.
desire output:
for n =2

A1 A2 A3 A4 A5 A6
nan nan nan nan nan nan
nan nan nan nan nan nan
nan nan nan 7 nan nan
1 nan nan 11 nan nan
54 5 3 12 9 8
10 nan 84 nan nan 45

i tried the following:

df['dummy'] = df.apply(lambda x: 1 if pd.notnull(x[column]) else 0, axis=1)
df['dummy2'] = df.groupby(['dummy'])[column].shift(n)
df[column] = df.apply(lambda x: x['dummy2'] if x['dummy']==1 else x[column], axis=1)

which is good if there is only a few columns i need to shift.

i also tried the applymap function

dummy_df = df.applymap(lambda x: 1 if pd.notnull(x) else 0)

which returns a dummy data frame to separate groups that i want to shift, just have no idea what to do next with it.
the problem is that there are thousands of columns i need to shift row wise.

Is there any ways i can do this using minimum loops? And are there any ways to do it with groupby function using dummy_df?

Asked By: beginer101

||

Answers:

try this:

tmp = df.apply(
    lambda s: s.sort_values(
        key=lambda v: pd.notnull(v)
        ).values
    )
res = tmp.shift(2)
res
Answered By: ziying35

Use lambda function with Series.dropna and Series.shift:

df = df.apply(lambda x: x.dropna().shift(2))

print (df)
     A1   A2    A3    A4   A5    A6
0   NaN  NaN   NaN   NaN  NaN   NaN
1   NaN  NaN   NaN   NaN  NaN   NaN
2   NaN  NaN   NaN   7.0  NaN   NaN
3   1.0  NaN   NaN  11.0  NaN   NaN
4  54.0  5.0   3.0  12.0  9.0   8.0
5  10.0  NaN  84.0   NaN  NaN  45.0
Answered By: jezrael
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.